我应该如何在3D引擎中实现视图裁剪平面?

问题描述

该项目完全是用Java从头编写的。自Covid成立以来,我一直很无聊,所以我想要可以占用我时间的东西,并教给我一些很棒的东西。我已经在这个问题上停留了大约一个星期。当我尝试使用近平面剪裁方法时,它会将新的顶点倾斜到屏幕的另一侧,但有时效果很好。

Failure Screenshot

Success Screenshot

所以我想也许是因为有时它会起作用,所以我只是没有在管道中的正确时间进行剪辑?

我从面部剔除和照明开始,

然后我将“摄影机视图”变换应用于顶点,

然后我在近平面上修剪

最后,我应用投影矩阵并裁剪掉屏幕上所有剩余的三角形

代码

这将计算交点。抱歉,如果我很杂乱或者很长一段时间,我没有编码方面的经验,我的专业是物理学,而不是CS。

public Vertex vectorIntersectPlane(Vector3d planePos,Vector3d planenorm,Vector3d linestart,Vector3d lineEnd){

    float planeDot = planenorm.dotProduct(planePos);
    float startDot = linestart.dotProduct(planenorm);
    float endDot = lineEnd.dotProduct(planenorm);
    float midPoint = (planeDot - startDot) / (endDot - startDot);

    Vector3d linestartEnd = lineEnd.sub(linestart);
    Vector3d linetoIntersect = linestartEnd.scale(midPoint);

    return new Vertex(linestart.add(linetoIntersect));
}

public float distanceFromPlane(Vector3d planePos,Vector3d vert){

    float x = planenorm.getX() * vert.getX();
    float y = planenorm.getY() * vert.getY();
    float z = planenorm.getZ() * vert.getZ();

    return (x + y + z - (planenorm.dotProduct(planePos)));
}

//When a triangle gets clipped it has 4 possible outcomes
// 1 it doesn't actually need clipping and gets returned
// 2 it gets clipped into 1 new triangle,for testing these are red
// 3 it gets clipped into 2 new triangles,for testing 1 is green,and 1 is blue
// 4 it is outside the view planes and shouldn't be rendered
public void clipTriangles(){

    Vector3d planePos = new Vector3d(0,ProjectionMatrix.fNear,1f);
    Vector3d planenorm = Z_AXIS.clone();

    final int length = triangles.size();

    for(int i = 0; i < length; i++) {

        Triangle t = triangles.get(i);

        if(!t.isDraw())
            continue;

        Vector3d[] insidePoint = new Vector3d[3];
        int insidePointCount = 0;

        Vector3d[] outsidePoint = new Vector3d[3];
        int outsidePointCount = 0;

        float d0 = distanceFromPlane(planePos,planenorm,t.getVerticesvectors()[0]);
        float d1 = distanceFromPlane(planePos,t.getVerticesvectors()[1]);
        float d2 = distanceFromPlane(planePos,t.getVerticesvectors()[2]);

        //Storing distances from plane and counting inside outside points
        {
            if (d0 >= 0){

                insidePoint[insidePointCount] = t.getVerticesvectors()[0];
                insidePointCount++;
            }else{

                outsidePoint[outsidePointCount] = t.getVerticesvectors()[0];
                outsidePointCount++;
            }
            if (d1 >= 0){

                insidePoint[insidePointCount] = t.getVerticesvectors()[1];
                insidePointCount++;
            }else{

                outsidePoint[outsidePointCount] = t.getVerticesvectors()[1];
                outsidePointCount++;
            }
            if (d2 >= 0){

                insidePoint[insidePointCount] = t.getVerticesvectors()[2];
                insidePointCount++;
            }else{

                outsidePoint[outsidePointCount] = t.getVerticesvectors()[2];
            }
        }
     
        //Triangle has 1 point still inside view,remove original triangle add new clipped triangle
        if (insidePointCount == 1) {

            t.dontDraw();

            Vertex newVert1 = vectorIntersectPlane(planePos,insidePoint[0],outsidePoint[0]);
            Vertex newVert2 = vectorIntersectPlane(planePos,outsidePoint[1]);
            vertices.add(newVert1);
            vertices.add(newVert2);
            
            //Triangles are stored with vertex references instead of the actual vertex object. 
            Triangle temp = new Triangle(t.getVertKeys()[0],vertices.size() - 2,vertices.size() - 1,vertices);
            temp.setColor(1,t.getBrightness(),t.getAlpha());
            triangles.add(temp);

            continue;
        }


        //Triangle has two points inside remove original add two new clipped triangles
        if (insidePointCount == 2) {

            t.dontDraw();

            Vertex newVert1 = vectorIntersectPlane(planePos,insidePoint[1],outsidePoint[0]);
            vertices.add(newVert1);
            vertices.add(newVert2);

            Triangle temp = new Triangle(t.getVertKeys()[0],t.getVertKeys()[1],vertices);
            temp.setColor(0,1,t.getAlpha());
            triangles.add(temp);

            temp = new Triangle(t.getVertKeys()[0],t.getAlpha());
            triangles.add(temp);

            continue;
        }
    }
}

解决方法

我发现了问题,没有为新的裁剪三角形提供正确的顶点参考。不管三角形是否在视图内,它们都被赋予了三角形的第一个顶点。