2

Java でソフトウェア レンダラーをプログラミングしており、各ピクセルの深度計算に Z バッファリングを使用しようとしています。ただし、動作に一貫性がないようです。たとえば、ユタ州のティーポットのサンプル モデルでは、ハンドルの回転方法によってはハンドルがおそらく半分描画されます。

私のzバッファアルゴリズム:

for(int i = 0; i < m_triangles.size(); i++)
{
    if(triangleIsBackfacing(m_triangles.get(i))) continue; //Backface culling
        for(int y = minY(m_triangles.get(i)); y < maxY(m_triangles.get(i)); y++)
        {
            if((y + getHeight()/2 < 0) || (y + getHeight()/2 >= getHeight())) continue; //getHeight/2 and getWidth/2 is for moving the model to the centre of the screen
            for(int x = minX(m_triangles.get(i)); x < maxX(m_triangles.get(i)); x++)
            {
                if((x + getWidth()/2 < 0) || (x + getWidth()/2 >= getWidth())) continue;
                rayOrigin = new Point2D(x, y);
                if(pointWithinTriangle(m_triangles.get(i), rayOrigin))
                {
                    zDepth = zValueOfPoint(m_triangles.get(i), rayOrigin);
                    if(zDepth > zbuffer[x + getWidth()/2][y + getHeight()/2])
                    {
                        zbuffer[x + getWidth()/2][y + getHeight()/2] = zDepth;
                        colour[x + getWidth()/2][y + getHeight()/2] = m_triangles.get(i).getColour();
                        g2.setColor(m_triangles.get(i).getColour());
                        drawDot(g2, rayOrigin);
                    }
               }
          }
     }
}

三角形と光線の原点を指定して、点の z 値を計算する方法:

private double zValueOfPoint(Triangle triangle, Point2D rayOrigin) 
{
    Vector3D surfaceNormal = getNormal(triangle);
    double A = surfaceNormal.x;
    double B = surfaceNormal.y;
    double C = surfaceNormal.z;
    double d = -(A * triangle.getV1().x + B * triangle.getV1().y + C * triangle.getV1().z);
    double rayZ = -(A * rayOrigin.x + B * rayOrigin.y + d) / C;
    return rayZ;
}

射線の原点が投影された三角形内にあるかどうかを計算する方法:

private boolean pointWithinTriangle(Triangle triangle, Point2D rayOrigin)
{
    Vector2D v0 = new Vector2D(triangle.getV3().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
    Vector2D v1 = new Vector2D(triangle.getV2().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
    Vector2D v2 = new Vector2D(rayOrigin, triangle.getV1().projectPoint(modelViewer));
    double d00 = v0.dotProduct(v0);
    double d01 = v0.dotProduct(v1);
    double d02 = v0.dotProduct(v2);
    double d11 = v1.dotProduct(v1);
    double d12 = v1.dotProduct(v2);

    double invDenom = 1.0 / (d00 * d11 - d01 * d01);
    double u = (d11 * d02 - d01 * d12) * invDenom;
    double v = (d00 * d12 - d01 * d02) * invDenom;

    // Check if point is in triangle
    if((u >= 0) && (v >= 0) && ((u + v) <= 1))
    {
         return true;
    }
    return false;
}

三角形の表面法線を計算する方法:

private Vector3D getNormal(Triangle triangle)
{
    Vector3D v1 = new Vector3D(triangle.getV1(), triangle.getV2()); 
    Vector3D v2 = new Vector3D(triangle.getV3(), triangle.getV2());
    return v1.crossProduct(v2);
}

間違って描かれたティーポットの例:

ここに画像の説明を入力

私は何を間違っていますか?些細なことに違いない気がします。三角形がまったく描画されていることを考えると、それが pointWithinTriangle メソッドであるとは思えません。背面カリングも正しく機能しているように見えるので、それは間違いです。私にとって最も可能性の高い犯人は zValueOfPoint メソッドですが、何が問題なのかを知るには十分ではありません。

4

2 に答える 2

1
  1. これは本当に遅いに違いない

    座標を反復するためだけに、反復/ピクセルごとに非常に多くの冗長な計算が行われます。投影された 3 つの頂点を計算し、それらの間を反復処理する必要があります。代わりに、次を参照してください。

  2. zValueOfPoint私はあなたの機能が嫌いです

    その中のメインループからの座標の使用を見つけることができないx,yので、どうすればZ値を正しく計算できますか?

    それとも、三角形全体の平均 Z 値を計算するだけですか? または私は何かを逃していますか?(私自身はJAVAコーダーではありません)とにかく、これがあなたの主な問題のようです。

    Z 値が間違って計算された場合、Z バッファは適切に機能しません。シェーディングされたティーポットではなく、一貫性のない、または絶え間ない混乱である場合、レンダリング後に深度バッファーを画像として見ることをテストするには、明らかです...

  3. Z バッファの実装

    それは問題ないようです

[ヒント]

x + getWidth()/2いくつかの変数に対して一度だけ計算してみませんか?とにかく現代のコンパイラがそれを行うべきであることは知っていますが、コードも読みやすく短くなります...少なくとも私にとっては

于 2014-10-15T08:05:42.207 に答える