2017-05-04 95 views
0

我一直在写一个简单的3d渲染器,并一直在研究绘制顺序。该引擎将3d多边形(按正确绘图顺序的3d点组)渲染到2d空间中,返回代表给定多边形投影的2d点列表。我这样做的方法可能有点非正统的,因为我想看看我是否能够做我自己,所以我重视我的代码如下预测:如何用简单的多边形使用ZBuffer?

public class Camera { 
/*position is the position of the camera, x, y, z; 
cameraRotation is the rotation of the camera, in the order of rotation about x, rotation about y, rotation about z 
the camera initially faces the +x direction 
*/ 
private double focalAngle; 
private double[] position, cameraRotation, cameraDirectionVector, cameraXVector, cameraZVector; 
private double[][][] rotationMatrices = new double[3][3][3]; 
private double[][] compoundedRotationMatrices; 

public Camera(double[] positionIn, double[] cameraRotationIn, double focalAngleIn){ 
    position = positionIn; 
    focalAngle = focalAngleIn; 
    cameraRotation = cameraRotationIn; 
    updateRotation(); 
} 

private void updateRotation(){ 
    updateRotationMatrices(); 
    updateCameraDirectionVector(); 
} 

private void updateRotationMatrices(){ 
    compoundedRotationMatrices = Matrix.getCompoundedRotationMatrix(cameraRotation[0], cameraRotation[1], cameraRotation[2]); 
} 

private void updateCameraDirectionVector(){ 
    double[] xVector = {1,0,0}; 
    double[] yVector = {0,-1,0}; 
    double[] zVector = {0,0,1}; 
    cameraDirectionVector = Matrix.vecMultiply(compoundedRotationMatrices, xVector); 
    cameraXVector = Matrix.vecMultiply(compoundedRotationMatrices, yVector); 
    cameraZVector = Matrix.vecMultiply(compoundedRotationMatrices, zVector); 
} 

public ArrayList<int[][]> getPolygonProjections(ArrayList<double[][]> polySets, double screenWidth, double screenHeight){ 
    ArrayList<int[][]> outPoints = new ArrayList(); 
    for(int i = 0; i < polySets.size(); i++){ 
     int[][] polyPoints = new int[2][polySets.get(i).length]; 
     /*in the calculation of proejctions, divide by zeros and NaNs can pop up, 
     polygonsLegitimate boolean keeps track of whether the polygon being drawn can be drawn without error, 
     and the while loop stops calcuating the polygon once it determines it cannot be properly drawn 
     */ 
     boolean polygonsLegitimate = true; 
     int j = 0; 
     while(j < polyPoints[0].length && polygonsLegitimate){ 
      int[] xy = getVectorProjection(polySets.get(i)[j], screenWidth, screenHeight); 
      if(xy != null){ 
       polyPoints[0][j] = xy[0]; 
       polyPoints[1][j] = xy[1]; 

      }else{ 
       polygonsLegitimate = false; 
      } 
      j++; 
     } 
     if(polygonsLegitimate){ 
      outPoints.add(polyPoints); 
     } 
    } 
    return outPoints; 
} 

private int[] getVectorProjection(double[] vector, double screenWidth, double screenHeight){ 
    double[] subVector = Vector.subtract(vector, position); 
    double zDepth = getZDepthOfVector(subVector); 
    if(zDepth > 0){ 
     double sliceSize = getSliceSizeAtDepth(zDepth); 
     double cameraXProj = Vector.dot(subVector, cameraXVector); 
     double cameraZProj = Vector.dot(subVector, cameraZVector); 
     double xPercent = (cameraXProj+(sliceSize/2))/sliceSize; 
     double zPercent = (cameraZProj+(sliceSize/2))/sliceSize; 
     int[] xy = {(int)(xPercent * screenWidth),(int)((((1-zPercent) * screenWidth))-(screenHeight/2))}; 
     return xy; 
    } 
    return null; 
} 

public double getZDepthOfVector(double[] vector){ 
    return Vector.dot(cameraDirectionVector, vector); 
} 

private double getSliceSizeAtDepth(double zDepth){ 
    return 2.0*Math.cos(focalAngle)*zDepth; 
} 

目前,我决定通过排序绘制顺序三维多边形除以多边形最靠近角落到相机的距离,然后按最远多边形到最近多边形的顺序绘制。然而,由于抽签顺序是完全基于多边形到相机的最近点的距离来确定,有防止算法有时正常工作了几cornercases,如本视频:

https://youtu.be/olTOTOCw42M

我已经在Z缓冲区做了大量的研究,而且这个概念很简单 - 实际上与我正在做的非常相似。就我的理解而言,对于每个渲染像素,将比较同一像素上呈现的所有点,并显示距离摄像机最近的z深度。然而,考虑到在这种情况下,我正在使用的唯一要点就是组成每个多边形拐角的那些点,我不知道一个好方法来比较多边形中包含的任何点的z深度而不仅仅是在角落。

我有这个问题有两个可能的解决方案:)

1拆分每个多边形成多个更小的多边形。当我嘲笑Python中的渲染器时,我从未在Z深度排序中添加,但是我确实将每个多边形划分为多个较小的多边形,这样我可以非常容易地分别点亮每个多边形,结果如下所示:

http://imgur.com/a/U3Xke

然而,这是非常昂贵的,因为许多投影点被多次投影,因为它们的值是通过计算相邻多边形的投影来确定的。也许有一个合理的方法来解决这个问题,但对我来说,看起来太粗糙是没有道理的。

2)找到每个三维多边形所在的平面,将其限定为多边形的形状,然后求解与这些平面通过视角定向的各个扫描线的交点,然后选择与距摄像机最近的z深度显示在该扫描线的像素处。这样,不是每个多边形的投影点用java的多边形填充方法填充,每个像素将被单独渲染。然而,我不确定如何“绑定”一架飞机,使其不会超出多边形的边界,对我来说理解起来有点棘手,因为目前数学对我而言有点过于先进。如果这是应该完成的方式,我可以学习,我只是想确保这是一种可行的方法。 3)将每个多边形分成许多点的集合,而不是分成更小的多边形:我认为这种方法会有缺陷,因为一个好的渲染所需的点的数量(即每个像素一个3d点,不需要相同多边形形状上的多个3d点渲染到完全相同的像素上,或者具有太少的3d点以致像素在渲染过程中被“跳过”)随Z深度和用于计算将这些点放置在何处的公式每次移动相机似乎都很难制定并且运行起来很昂贵。

回答

0

使用排序表,Playstation 1使用的算法。

将Z范围分成N个相同大小的部分。

  • 创建N个指向多边形的指针数组。
  • 每帧都将该数组清零。
  • 对于每一个三角形要绘制:
    • 计算出相应的Z-指数我。
    • 将它插入订单[i]就像链接列表一样。
  • 经过反向(后到前)的阵列,绘画三角形你遍历

C代码

Triangle *Order[256]; 

void Clear() { 
    memset(Order,0,sizeof(Order)); 
} 

void Insert(Triangle *tri) { 
    int index = (tri->averageZ-zNear) * 256/(zFar - zNear); 
    tri->next = Order[index]; 
    Order[index] = tri; 
} 

void Paint() { 
    for(int i=255;i>=0;i--) 
     for(Triangle *tri=Order[i];tri;tri=tri->next) 
      DrawTriangle(tri); 
} 

来源:小煜 “RYG” 吉森(Farbrausch的成名)有一个题为“当光速不够快”的演讲,他提出了这个想法,包括这个代码。

0

我认为你误解了Z缓冲区的想法,最接近真相的是你的解决方案没有。 3) - 将你的多边形分割成单个像素。

Z缓冲区每像素工作,是的,有很多Z比较,但它是如何工作。您不能将其简化为仅使用多边形的特定顶点。

我假设你有一些网格让我们说'颜色'结构,你要填充你的渲染。这将成为您的目标图像。您需要添加另一个同样大小的浮动网格 - 这将是您的Z缓冲区。在开始时,你用一些大的值填充你的Z缓冲区,比如1​​000000.

现在忽略多边形的排序--Z缓冲区会为你解决它。您可以稍后添加排序以测试不同绘图订单之间的性能差异,但不需要使其工作。

现在您需要光栅化阶段,在这里您可以传递多边形边角并获取该多边形覆盖的所有像素列表。您可以使用扫描线来计算它,正如您在2)中所述。我建议你为单个三角形编写光栅化,并将所有的多边形分割成三角形,这将使你的代码更简单。如果你愿意的话,你可以返回这个阶段的像素列表(在这种情况下,列表将会很慢,但对于学习目的来说很好)。最好在这个阶段直接填充像素网格,而不是将这些数据存储在内存中)但是你需要一个重要的改变 - 除了X和Y之外,像素需要正确的Z值。

当你有这样的光栅化像素列表时,你只需将它们放入像素网格,这就是Z测试发生的地方。迭代每个像素,并使用像素屏幕位置(X,Y)从Z缓冲区中读取当前Z值。如果该值大于当前像素的Z值,则在彩色缓冲区中写入像素颜色,在Z缓冲区中写入像素Z.

+0

这对我的问题有更多的了解,但我怎样才能单独计算在某个像素上绘制的多边形上的3d点的Z值?我知道一个光线是通过与给定像素的x和y位置相交的角度从相机的位置投射出来的,但是我怎样才能确定这个光线通过像素与多边形相交的Z深度(这只是一个列表3D点在每个角落)? – pete2fiddy

+0

为了便于说明,在选项3中,我实际上是在讨论如何将3d多边形点分成许多3d点,以便在投影后将一个点用于屏幕上的一个像素。然而,我不确定如何去解决这个问题(而且这看起来也不正确) - 从我所知道的情况来看,不是将多边形分成多个3d点,而是要让我画出它因为我现在只使用它的角点,然后确定多边形的每个绘制像素之后的多边形的Z深度,然后进行Z深度比较。 – pete2fiddy

+0

您可以通过插值Z值从多边形顶点计算像素Z. Raycast对此会慢很多。从现在开始,将您的聚合物分解成三角形并考虑三角形。现在你正在绘制一个三角形,它的三个角都在屏幕上,每个都有X,Y,Z值。对于此三角形内的每个像素,可以使用像素到角点的距离来插值Z值。它被称为重心坐标,你可以在这里阅读它https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes – kolenda

相关问题