平行视图的透视图

时间:2014-07-06 16:36:26

标签: java graphics 3d

在书中给出的例子"计算机图形用于Java程序员,第二版"

存在视图向量转换

 private void shiftToOrigin()
   {  float xwC = 0.5F * (xMin + xMax),
            ywC = 0.5F * (yMin + yMax),
            zwC = 0.5F * (zMin + zMax);
      int n = w.size();
      for (int i=1; i<n; i++)
         if (w.elementAt(i) != null)
         {  ((Point3D)w.elementAt(i)).x -= xwC;
            ((Point3D)w.elementAt(i)).y -= ywC;
            ((Point3D)w.elementAt(i)).z -= zwC;
         }
      float dx = xMax - xMin, dy = yMax - yMin, dz = zMax - zMin;
      rhoMin = 0.6F * (float) Math.sqrt(dx * dx + dy * dy + dz * dz);
      rhoMax = 1000 * rhoMin;
      rho = 3 * rhoMin;

   }

   private void initPersp()
   {  
       float costh = (float)Math.cos(theta), 
            sinth = (float)Math.sin(theta),
            cosph = (float)Math.cos(phi), 
            sinph = (float)Math.sin(phi);
      v11 = -sinth;   v12 = -cosph * costh;   v13 = sinph * costh;
      v21 = costh;    v22 = -cosph * sinth;   v23 = sinph * sinth; 
                      v32 = sinph;            v33 = cosph; 
                                              v43 = -rho;  
   } 

   float eyeAndScreen(Dimension dim)
      // Called in paint method of Canvas class
   {  initPersp();
      int n = w.size();
      e = new Point3D[n];
      vScr = new Point2D[n];
      float xScrMin=1e30F, xScrMax=-1e30F, 
            yScrMin=1e30F, yScrMax=-1e30F;
      for (int i=1; i<n; i++)
      {  
          Point3D P = (Point3D)(w.elementAt(i));
         if (P == null)
         {  e[i] = null; vScr[i] = null;
         }  
         else
         {  float x = v11 * P.x + v21 * P.y;
            float y = v12 * P.x + v22 * P.y + v32 * P.z;
            float z = v13 * P.x + v23 * P.y + v33 * P.z + v43;
            Point3D Pe = e[i] = new Point3D(x, y, z);
            float xScr = -Pe.x/Pe.z, yScr = -Pe.y/Pe.z;
            vScr[i] = new Point2D(xScr, yScr);
            if (xScr < xScrMin) xScrMin = xScr;
            if (xScr > xScrMax) xScrMax = xScr;
            if (yScr < yScrMin) yScrMin = yScr;
            if (yScr > yScrMax) yScrMax = yScr;
         }
      } 
      float rangeX = xScrMax - xScrMin, rangeY = yScrMax - yScrMin;
      d = 0.95F * Math.min(dim.width/rangeX, dim.height/rangeY); //d burada
      imgCenter = new Point2D(d * (xScrMin + xScrMax)/2, 
                              d * (yScrMin + yScrMax)/2);
      for (int i=1; i<n; i++)
      { 
          if (vScr[i] != null){vScr[i].x *= d; vScr[i].y *= d;}
      }
      return d * Math.max(rangeX, rangeY); 
      // Maximum screen-coordinate range used in CvHLines for HP-GL
   }

这里float xScr = -Pe.x/Pe.z, yScr = -Pe.y/Pe.z;当我们将x和y除以z作为透视图时,如果我们不将它除以z,则视图将是平行的(正交) 这没关系,但如果我们想在同一本书中使用隐藏线算法进行这种平行视图坐标,则会错误地计算线条。我无法找到问题所在。什么可能导致这个问题?

这里的隐藏线算法:

 private void lineSegment(Graphics g, Point3D Pe, Point3D Qe,
      Point2D PScr, Point2D QScr, int iP, int iQ, int iStart)
   {  

      double u1 = QScr.x - PScr.x; //t
      double u2 = QScr.y - PScr.y; //t
      double minPQx = Math.min(PScr.x, QScr.x);//t
      double maxPQx = Math.max(PScr.x, QScr.x);//t
      double minPQy = Math.min(PScr.y, QScr.y);//t
      double maxPQy = Math.max(PScr.y, QScr.y);//t
      double zP = Pe.z; //t
      double zQ = Qe.z; //t
      double minPQz = Math.min(zP, zQ);//t 
      Point3D[] e = obj.getE();//e eye
      Point2D[] vScr = obj.getVScr(); //vscr screen

      for (int i=iStart; i<nTria; i++)//t
      { 
         Tria t = tr[i];
         int iA = t.iA, iB = t.iB, iC = t.iC;
         Point2D AScr = vScr[iA], BScr = vScr[iB], CScr = vScr[iC];

         // 1. Minimax test for x and y screen coordinates: //t
         if (maxPQx <= AScr.x && maxPQx <= BScr.x && maxPQx <= CScr.x 
          || minPQx >= AScr.x && minPQx >= BScr.x && minPQx >= CScr.x
          || maxPQy <= AScr.y && maxPQy <= BScr.y && maxPQy <= CScr.y
          || minPQy >= AScr.y && minPQy >= BScr.y && minPQy >= CScr.y)
             continue;

         // 2. Test if PQ is an edge of ABC: //t
         if ((iP == iA || iP == iB || iP == iC) &&
             (iQ == iA || iQ == iB || iQ == iC)) 
             continue;

         // 3. Test if PQ is clearly nearer than ABC://t
         Point3D Ae = e[iA], Be = e[iB], Ce = e[iC];
         double zA = Ae.z, zB = Be.z, zC = Ce.z;
         if (minPQz >= zA && minPQz >= zB && minPQz >= zC) 
             continue;

         // 4. Do P and Q (in 2D) lie in a half plane defined
         //    by line AB, on the side other than that of C?
         //    Similar for the edges BC and CA.
         double eps = 0.1; // Relative to numbers of pixels //t
         if (Tools2D.area2(AScr, BScr, PScr) < eps && 
             Tools2D.area2(AScr, BScr, QScr) < eps ||
             Tools2D.area2(BScr, CScr, PScr) < eps && 
             Tools2D.area2(BScr, CScr, QScr) < eps ||
             Tools2D.area2(CScr, AScr, PScr) < eps && 
             Tools2D.area2(CScr, AScr, QScr) < eps) 
             continue;

         // 5. Test (2D) if A, B and C lie on the same side
         //    of the infinite line through P and Q://t
         double PQA = Tools2D.area2(PScr, QScr, AScr);
         double PQB = Tools2D.area2(PScr, QScr, BScr);
         double PQC = Tools2D.area2(PScr, QScr, CScr);

         if (PQA < +eps && PQB < +eps && PQC < +eps ||
             PQA > -eps && PQB > -eps && PQC > -eps)
            continue;

         // 6. Test if neither P nor Q lies behind the 
         //    infinite plane through A, B and C://t
         int iPol = refPol[i];
         Polygon3D pol = (Polygon3D)polyList.elementAt(iPol);
         double a = pol.getA(), b = pol.getB(), c = pol.getC(),
            h = pol.getH(), eps1 = 1e-5 * Math.abs(h),
            hP = a * Pe.x + b * Pe.y + c * Pe.z,
            hQ = a * Qe.x + b * Qe.y + c * Qe.z;
         if (hP > h - eps1 && hQ > h - eps1)
            continue;

         // 7. Test if both P and Q behind triangle ABC://t
         boolean PInside = 
            Tools2D.insideTriangle(AScr, BScr, CScr, PScr);
         boolean QInside = 
            Tools2D.insideTriangle(AScr, BScr, CScr, QScr);
         if (PInside && QInside) 
             return;


         // 8. If P nearer than ABC and inside, PQ visible;//t
         //    the same for Q:
         double h1 = h + eps1;
         boolean PNear = hP > h1, QNear = hQ > h1;
         if (PNear && PInside || QNear && QInside) 
             continue;

         // 9. Compute the intersections I and J of PQ
         // with ABC in 2D.
         // If, in 3D, such an intersection lies in front of
         // ABC, this triangle does not obscure PQ.
         // Otherwise, the intersections lie behind ABC and
         // this triangle obscures part of PQ:
         double lambdaMin = 1.0, lambdaMax = 0.0;
         for (int ii=0; ii<3; ii++)
         {  double v1 = BScr.x - AScr.x, v2 = BScr.y - AScr.y,
                   w1 = AScr.x - PScr.x, w2 = AScr.y - PScr.y,
                   denom = u2 * v1 - u1 * v2;
            if (denom != 0)
            {  double mu = (u1 * w2 - u2 * w1)/denom;
               // mu = 0 gives A and mu = 1 gives B.
               if (mu > -0.0001 && mu < 1.0001)
               {  double lambda = (v1 * w2 - v2 * w1)/denom;
                  // lambda = PI/PQ 
                  // (I is point of intersection)
                  if (lambda > -0.0001 && lambda < 1.0001)
                  {  if (PInside != QInside && 
                     lambda > 0.0001 && lambda < 0.9999)
                     {  lambdaMin = lambdaMax = lambda;
                        break; 
                        // Only one point of intersection
                     }
                     if (lambda < lambdaMin) lambdaMin = lambda;
                     if (lambda > lambdaMax) lambdaMax = lambda;
                  }
               }
            }
            Point2D temp = AScr; AScr = BScr; 
            BScr = CScr; CScr = temp;
         }
         float d = obj.getD();
         if (!PInside && lambdaMin > 0.001)
         {  double IScrx = PScr.x + lambdaMin * u1,
                   IScry = PScr.y + lambdaMin * u2;
            // Back from screen to eye coordinates:
            double zI = 1/(lambdaMin/zQ + (1 - lambdaMin)/zP),
                   xI = -zI * IScrx / d, yI = -zI * IScry / d;
            if (a * xI + b * yI + c * zI > h1) continue;
            Point2D IScr = new Point2D((float)IScrx, (float)IScry);
            if (Tools2D.distance2(IScr, PScr) >= 1.0)
               lineSegment(g, Pe, new Point3D(xI, yI, zI), PScr, 
                  IScr, iP, -1, i + 1);  
         }
         if (!QInside && lambdaMax < 0.999) 
         {  double JScrx = PScr.x + lambdaMax * u1,
                   JScry = PScr.y + lambdaMax * u2;
            double zJ = 
               1/(lambdaMax/zQ + (1 - lambdaMax)/zP),
                  xJ = -zJ * JScrx / d, yJ = -zJ * JScry / d;
            if (a * xJ + b * yJ + c * zJ > h1) continue;
            Point2D JScr = new Point2D((float)JScrx, (float)JScry);
            if (Tools2D.distance2(JScr, QScr) >= 1.0) 
               lineSegment(g, Qe, new Point3D(xJ, yJ, zJ),
                  QScr, JScr, iQ, -1, i + 1);  
         }
         return; 
            // if no continue-statement has been executed
      }
      drawLine(g, PScr.x, PScr.y, QScr.x, QScr.y);
   }
}

0 个答案:

没有答案
相关问题