<p>You are right.
In the examples you provided you only seem to render &quot;pre-transformed&quot; 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 <em>before</em> being transformed.</p>
<p>Interpolating 1 / z instead of z is needed to get the correct depth for perspective-transformed geometry.</p>

CC BY-SA 4.0
2022-08-18T22:35:24.377Z
2022-08-18T22:35:24.377Z
Michele M.
<p>I have doubts on 1/z depth buffer interpolation. According to <a href="https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/visibility-problem-depth-buffer-depth-interpolation" rel="nofollow noreferrer">this website</a>, the correct 1/z interpolation formula is</p>
<p><span class="math-container">$\dfrac{1}{P.z} = \dfrac{1}{V0.z} * \lambda_0 + \dfrac{1}{V1.z} * \lambda_1 + \dfrac{1}{V2.z} * \lambda_2.
$</span></p>
<p>Here is my 1/z interpolation implementation in my barycentric triangle rendering algorithm for my software renderer</p>
<pre><code>    void DrawFilledTriangleBarycentric(const vec3f&amp; v1, const vec3f&amp; v2, const vec3f&amp; v3, const Colour&amp; 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 &gt;= 0.0f) &amp; (w2 &gt;= 0.0f) &amp; (w3 &gt;= 0.0f))
                {
                    float z = w1 * v1[2] + w2 * v2[2] + w3 * v3[2];
                    float depth = 1.0f / z;

                    PutPixel(x, y, depth, colour.argb);
                }
        ...
    }
</code></pre>
<p>especially this part</p>
<pre><code>float z = w1 * v1[2] + w2 * v2[2] + w3 * v3[2];
float depth = 1.0f / z;
</code></pre>
<p><code>v1[2]</code>, <code>v2[2]</code>, and <code>v3[2]</code> are z values. I am wondering whether I should change it to</p>
<pre><code>float z = w1 * (1.0 / v1[2]) + w2 * (1.0 / v2[2]) + w3 * (1.0 / v3[2]);
float depth = z;
</code></pre>
<p>But if I do I got the following output</p>
<p><a href="https://i.sstatic.net/2rVBG.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/2rVBG.png" alt="1" /></a></p>
<p>which is different from what I expect (using <code>depth=1.0f/(w1 * v1[2] + w2 * v2[2] + w3 * v3[2])</code>)</p>
<p><a href="https://i.sstatic.net/ForGR.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/ForGR.png" alt="2" /></a></p>
<p>These are the triangles I am trying to render</p>
<pre><code>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);
</code></pre>
<p>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?</p>

CC BY-SA 4.0
2022-09-05T09:19:33.867Z
You may find this reply on a different thread of use: https://computergraphics.stackexchange.com/a/8022/209
Simon F
<interpolation><z-buffer>
Correct way to interpolate 1/z?
Jimmy Yang
# Correct way to interpolate 1/z?

(Asked by: username_0 on 2022-08-17)

I have doubts on 1/z depth buffer interpolation. According to [this website](https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/visibility-problem-depth-buffer-depth-interpolation), 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](https://i.sstatic.net/2rVBG.png)](https://i.sstatic.net/2rVBG.png)

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

[![2](https://i.sstatic.net/ForGR.png)](https://i.sstatic.net/ForGR.png)

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?

**Tags:** interpolation, z-buffer

> **Comments:**
> **username_1**: You may find this reply on a different thread of use: https://computergraphics.stackexchange.com/a/8022/209  

---

## 1 answers

### Answer by username_2 on 2022-08-18. Score: 3

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.


---

