Как реализовать плоскость отсечения вида в 3D Engine?

Этот проект написан полностью с нуля на Java. Мне просто было скучно с тех пор, как начался Covid, поэтому я хотел что-то, что отнимет у меня время и научит чему-то классному. Я застрял на этой проблеме уже около недели. Когда я пытаюсь использовать метод отсечения ближней плоскости, он искажает новые вершины в противоположную сторону экрана, но иногда это работает просто отлично.

Снимок экрана с ошибкой

Скриншот успеха

Итак, я подумал, что, может быть, раз это иногда срабатывает, я просто не выполняю отсечение в нужное время в конвейере?

Я начинаю с выделения лица и освещения,

Затем я применяю преобразование вида камеры к вершинам,

Затем я обрезаю ближний самолет

Наконец, я применяю матрицу проекции и обрезаю все оставшиеся вне экрана треугольники.

Код:

Это вычисляет точки пересечения. Извините, если это сумбурно или длинно, я не очень разбираюсь в кодировании, моя специальность - физика, а не 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 planeNorm, 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, 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, planeNorm, t.getVerticesVectors()[1]);
        float d2 = distanceFromPlane(planePos, planeNorm, 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, planeNorm, insidePoint[0], outsidePoint[0]);
            Vertex newVert2 = vectorIntersectPlane(planePos, planeNorm, insidePoint[0], 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,0,0, 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, planeNorm, insidePoint[0], outsidePoint[0]);
            Vertex newVert2 = vectorIntersectPlane(planePos, planeNorm, insidePoint[1], outsidePoint[0]);
            vertices.add(newVert1);
            vertices.add(newVert2);

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

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

            continue;
        }
    }
}

person Grant Fields    schedule 21.08.2020    source источник
comment
У вас есть потенциальное деление на ноль в vectorIntersectPlane   -  person Mauricio Cele Lopez Belon    schedule 22.08.2020


Ответы (1)


Я понял проблему: новым обрезанным треугольникам не давали правильные ссылки на вершины. им просто давали первую вершину треугольника, независимо от того, была ли она внутри представления или нет.

person Grant Fields    schedule 23.08.2020