3
$\begingroup$

I have doubts on 1/z depth buffer interpolation. According to this website, the correct 1/z interpolation formula is

$\dfrac{1}{P.z} = \dfrac{1}{V0.z} * \lambda_0 + \dfrac{1}{V1.z} * \lambda_1 + \dfrac{1}{V2.z} * \lambda_2. $

Here is my 1/z interpolation implementation in my barycentric triangle rendering algorithm for my software renderer

    void DrawFilledTriangleBarycentric(const vec3f& v1, const vec3f& v2, const vec3f& v3, const Colour& colour) {
        ...
                // Barycentric weights
                float w1 = ((px - v2[0]) * (v3[1] - v2[1]) - (py - v2[1]) * (v3[0] - v2[0])) / area;
                float w2 = ((px - v3[0]) * (v1[1] - v3[1]) - (py - v3[1]) * (v1[0] - v3[0])) / area;
                float w3 = ((px - v1[0]) * (v2[1] - v1[1]) - (py - v1[1]) * (v2[0] - v1[0])) / area;

                if ((w1 >= 0.0f) & (w2 >= 0.0f) & (w3 >= 0.0f))
                {
                    float z = w1 * v1[2] + w2 * v2[2] + w3 * v3[2];
                    float depth = 1.0f / z;

                    PutPixel(x, y, depth, colour.argb);
                }
        ...
    }

especially this part

float z = w1 * v1[2] + w2 * v2[2] + w3 * v3[2];
float depth = 1.0f / z;

v1[2], v2[2], and v3[2] are z values. I am wondering whether I should change it to

float z = w1 * (1.0 / v1[2]) + w2 * (1.0 / v2[2]) + w3 * (1.0 / v3[2]);
float depth = z;

But if I do I got the following output

1

which is different from what I expect (using depth=1.0f/(w1 * v1[2] + w2 * v2[2] + w3 * v3[2]))

2

These are the triangles I am trying to render

DrawFilledTriangleBarycentric(vec3f(10, 50, 10), vec3f(400, 100, 10), vec3f(290, 380, 10), RED);
DrawFilledTriangleBarycentric(vec3f(50, 350, 2), vec3f(130, 40, 20), vec3f(380, 200, 5), GREEN);

Edit: I think I got it now. Depth testing method actually depends on what projection I use. If I use orthographic projection, z is linear but 1/z is not so I can use naive z buffer without problems. If I use perspective projection, z is no longer linear but 1/z becomes linear. In this case, inverse z testing is necessary. Am I right here? no?

$\endgroup$
1

1 Answer 1

3
$\begingroup$

You are right. In the examples you provided you only seem to render "pre-transformed" triangles which is why I think you were missing the point made in the article. Which depth testing is the correct one depends on what those triangles representeded before being transformed.

Interpolating 1 / z instead of z is needed to get the correct depth for perspective-transformed geometry.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.