3d 如何将ZBuffer与简单多边形一起使用?

3d 如何将ZBuffer与简单多边形一起使用?,3d,rasterizing,zbuffer,3d,Rasterizing,Zbuffer,我一直在编写一个简单的3d渲染器,并一直在研究绘图顺序。该引擎将三维多边形(按正确绘图顺序排列的三维点组)渲染到二维空间,并返回表示给定多边形投影的二维点列表。我这样做的方法可能有点非正统,因为我想看看自己是否能够做到这一点,所以我在下面附上了我的投影代码: public class Camera { /*position is the position of the camera, x, y, z; cameraRotation is the rotation of the camera, i

我一直在编写一个简单的3d渲染器,并一直在研究绘图顺序。该引擎将三维多边形(按正确绘图顺序排列的三维点组)渲染到二维空间,并返回表示给定多边形投影的二维点列表。我这样做的方法可能有点非正统,因为我想看看自己是否能够做到这一点,所以我在下面附上了我的投影代码:

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;
}
公共级摄像机{
/*位置是相机的位置,x,y,z;
摄影机旋转是摄影机的旋转,按围绕x、围绕y、围绕z的顺序旋转
相机最初面向+x方向
*/
私人双焦点;
专用双[]位置,摄像机旋转,摄像机方向向量,摄像机X向量,摄像机Z向量;
私有双精度[][]旋转矩阵=新双精度[3][3][3];
私有双[][]复合属性矩阵;
公共摄像机(双[]位置向内,双[]摄像机旋转向内,双焦距向内){
位置=位置输入;
focalAngle=focalAngleIn;
cameraRotation=cameraRotation in;
updateRotation();
}
私有void updateRotation(){
updateRotationMatrices();
UpdateCameradDirectionVector();
}
私有void updateRotationMatrices(){
CompoundedRotationMatrix=Matrix.getCompoundedRotationMatrix(cameraRotation[0],cameraRotation[1],cameraRotation[2]);
}
私有void updateCameradDirectionVector(){
double[]xVector={1,0,0};
双[]yVector={0,-1,0};
双[]zVector={0,0,1};
CameradDirectionVector=Matrix.vecMultiply(CompoundedRotationMatrix,xVector);
cameraXVector=Matrix.vecMultiply(复合动态矩阵,yVector);
cameraZVector=Matrix.vecMultiply(复合动态矩阵,zVector);
}
公共ArrayList getPolygonProjections(ArrayList多边形集,双屏幕宽度,双屏幕高度){
ArrayList输出点=新的ArrayList();
对于(int i=0;i0){
double sliceSize=GetSliceSizeAtepth(zDepth);
double cameraXProj=Vector.dot(子向量,cameraXVector);
double cameraZProj=向量.dot(子向量,cameraZVector);
double xPercent=(cameraXProj+(sliceSize/2))/sliceSize;
double zPercent=(cameraZProj+(sliceSize/2))/sliceSize;
int[]xy={(int)(x百分比*屏幕宽度),(int)(((1-z百分比)*屏幕宽度))-(屏幕高度/2));
返回xy;
}
返回null;
}
公共双getZDepthOfVector(双[]向量){
返回向量.dot(CameradDirectionVector,Vector);
}
专用双GetSliceSizeAteph(双zDepth){
返回2.0*Math.cos(焦点)*zDepth;
}
目前,我通过按多边形最靠近摄影机的角的距离对三维多边形进行排序,然后按最远多边形到最近多边形的顺序进行绘制来确定绘制顺序。但是,由于绘制顺序仅根据多边形上最近点到摄影机的距离来确定,因此存在少数情况有时会妨碍算法正常工作,如本视频所示:

我对Z缓冲区做了很多研究,这个概念非常简单——实际上与我正在做的非常相似。据我所知,对于每个渲染像素,在同一像素上渲染的所有点都会进行比较,并显示离相机最近的Z深度。然而,在这种情况下,我处理的唯一点是对于构成每个多边形角点的那些点,我不知道有什么好方法来比较包含在多边形中的任何点的z深度,而不仅仅是在角点

对于这个问题,我有两种可能的解决方案:

1) 将每个多边形拆分为多个较小的多边形。当我在python中模拟渲染器时,我从未添加Z深度排序,但我确实将每个多边形拆分为多个较小的多边形,以便可以非常轻松地分别照亮每个多边形,结果如下所示:

然而,这是非常昂贵的,因为许多投影点被投影多次,因为它们的值是通过计算相邻多边形的投影来确定的。也许有一种合法的方法来实现这一点,但对我来说,这似乎太粗糙而不正确

2) 找到每个3d多边形所在的平面,将其绑定到多边形的形状上,然后求解通过视图角度定向的各个扫描线与这些平面的交点,然后选择与相机z深度最接近的交点,以显示在该扫描线的像素处。这样,而不是每个多边形的点使用java的多边形填充方法投影多边形,然后填充,每个像素将分别渲染。但是,我不确定如何“绑定”一个平面,使其不会超出多边形的边界,这有点像t
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);
}