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
which is different from what I expect (using depth=1.0f/(w1 * v1[2] + w2 * v2[2] + w3 * v3[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?