<p>The <span class="math-container">$Z$</span> of NDC space is related to <span class="math-container">$1/Z_\text{view}$</span> but not the same. With a typical projection matrix,  they're related by an affine remapping,
<span class="math-container">$$
Z_\text{NDC} = a \, \frac{1}{Z_\text{view}} + b
$$</span>
where <span class="math-container">$a, b$</span> are some constants related to the near and far planes. So, in general you wouldn't be able to substitute <span class="math-container">$Z_\text{NDC}$</span> for <span class="math-container">$1/Z_\text{view}$</span> in the interpolation expressions. The <span class="math-container">$a$</span> factor isn't a problem, as it would factor out and cancel, but if <span class="math-container">$b \neq 0$</span> then it will produce some extra terms and throw off the interpolation.</p>
<p>If I'm hearing you right, it sounds like you're concerned about the idea of needing to prepare every single vertex attribute value (multiplying by <span class="math-container">$1/Z_\text{view}$</span>) before interpolation and then reverse that afterward. Well, there is an easier way: we can create perspective-corrected barycentric coordinates <span class="math-container">$w'_0, w'_1, w'_2$</span>, defined by
<span class="math-container">$$
w'_i \equiv \frac{w_i / Z_i}{w_0/Z_0 + w_1/Z_1 + w_2/Z_2}
$$</span>
Then we can interpolate any attributes by <span class="math-container">$w'_0 A_0 + w'_1 A_1 + w'_2 A_2$</span>, and it will be perspective-correct interpolation. You can verify this is equivalent to your original interpolation formula in your question. If we have more than three scalar attributes to interpolate (which we usually do), this would be the cheaper way to do it.</p>

CC BY-SA 4.0
2020-08-05T06:53:34.850Z
2020-08-05T06:53:34.850Z
Nathan Reed
<p>Usually, if we want to interpolate some vertex attributes, say <span class="math-container">$A_1$</span>, <span class="math-container">$A_2$</span> and <span class="math-container">$A_3$</span>, we have to first divide them by their corresponding <span class="math-container">$z$</span> in view space, then we interpolate them using barycentric weights and finally we multiply them by the interpolated <span class="math-container">$z$</span> at the current pixel. To interpolate this <span class="math-container">$z$</span>, we have to inverse the 3 <span class="math-container">$z$</span> of each vertex, then interpolate them and finally inverse the result to have the interpolated <span class="math-container">$z$</span>.</p>
<p>In other words, the interpolated attribute <span class="math-container">$A$</span> is equal to:
<span class="math-container">$$
A = z \left(w_0 \times \frac{A_1}{Z_1} + w_1 \times \frac{A_2}{Z_2} + w_2 \times \frac{A_3}{Z_3}\right)
$$</span></p>
<p>where <span class="math-container">$w_i$</span> are the barycentric weights, <span class="math-container">$Z_i$</span> are the depths of each vertex and <span class="math-container">$z$</span> is the interpolated depth:
<span class="math-container">$$
z = \frac{1}{w_0 \times \frac{1}{Z_1} + w_1 \times \frac{1}{Z_2} + w_2 \times \frac{1}{Z_3}}
$$</span></p>
<p>Now my question is: instead of going back and forth between attributes and their reciprocals, can we just use the vertices'<span class="math-container">$z$</span> in normalized device coordinates, that is, the <span class="math-container">$z$</span>s that have been divided by <span class="math-container">$w$</span>, after the perspective projection?</p>
<p>If I understand correctly, we interpolate the reciprocal of vertex attributes, because it's linear in screen space, but what about the <span class="math-container">$z$</span> in NDC space, after the homogeneous divide? If we can manage to use it, we already have a <span class="math-container">$z$</span> that we can linearly interpolate, because it has been homogenized?</p>
<p>In the book &quot;Game Engine Architecture&quot;, page 667, they say:</p>
<blockquote>
<p>with w-buffering, we cannot linearly interpolate depths directly. Depths must be inverted prior to interpolation and the re-inverted prior to being stored the w-buffer.</p>
</blockquote>
<p>In other words, we don't need to invert <span class="math-container">$z$</span> back and forth to find the interpolated depth: we just have to use the <span class="math-container">$z$</span> in NDC space, that has been divided by view-space <span class="math-container">$z$</span>. So we can directly interpolate the <span class="math-container">$z$</span> in NDC space to have perspective-correct depth, but how can I use this interpolated depth to interpolate other vertex attributes?</p>

<transformations><perspective><interpolation>
Interpolate vertex attributes with $z$ AFTER homogeneous divide
Voko
# Interpolate vertex attributes with $z$ AFTER homogeneous divide

(Asked by: username_0 on 2020-08-04)

Usually, if we want to interpolate some vertex attributes, say $A\_1$, $A\_2$ and $A\_3$, we have to first divide them by their corresponding $z$ in view space, then we interpolate them using barycentric weights and finally we multiply them by the interpolated $z$ at the current pixel. To interpolate this $z$, we have to inverse the 3 $z$ of each vertex, then interpolate them and finally inverse the result to have the interpolated $z$.

In other words, the interpolated attribute $A$ is equal to:
$$
A = z \left(w\_0 \times \frac{A\_1}{Z\_1} + w\_1 \times \frac{A\_2}{Z\_2} + w\_2 \times \frac{A\_3}{Z\_3}\right)
$$

where $w\_i$ are the barycentric weights, $Z\_i$ are the depths of each vertex and $z$ is the interpolated depth:
$$
z = \frac{1}{w\_0 \times \frac{1}{Z\_1} + w\_1 \times \frac{1}{Z\_2} + w\_2 \times \frac{1}{Z\_3}}
$$

Now my question is: instead of going back and forth between attributes and their reciprocals, can we just use the vertices'$z$ in normalized device coordinates, that is, the $z$s that have been divided by $w$, after the perspective projection?

If I understand correctly, we interpolate the reciprocal of vertex attributes, because it's linear in screen space, but what about the $z$ in NDC space, after the homogeneous divide? If we can manage to use it, we already have a $z$ that we can linearly interpolate, because it has been homogenized?

In the book "Game Engine Architecture", page 667, they say:

> with w-buffering, we cannot linearly interpolate depths directly. Depths must be inverted prior to interpolation and the re-inverted prior to being stored the w-buffer.

In other words, we don't need to invert $z$ back and forth to find the interpolated depth: we just have to use the $z$ in NDC space, that has been divided by view-space $z$. So we can directly interpolate the $z$ in NDC space to have perspective-correct depth, but how can I use this interpolated depth to interpolate other vertex attributes?

**Tags:** transformations, perspective, interpolation


---

## 1 answers

### Answer by username_1 on 2020-08-05. Score: 3 | Accepted answer

The $Z$ of NDC space is related to $1/Z\_\text{view}$ but not the same. With a typical projection matrix, they're related by an affine remapping,
$$
Z\_\text{NDC} = a \, \frac{1}{Z\_\text{view}} + b
$$
where $a, b$ are some constants related to the near and far planes. So, in general you wouldn't be able to substitute $Z\_\text{NDC}$ for $1/Z\_\text{view}$ in the interpolation expressions. The $a$ factor isn't a problem, as it would factor out and cancel, but if $b \neq 0$ then it will produce some extra terms and throw off the interpolation.

If I'm hearing you right, it sounds like you're concerned about the idea of needing to prepare every single vertex attribute value (multiplying by $1/Z\_\text{view}$) before interpolation and then reverse that afterward. Well, there is an easier way: we can create perspective-corrected barycentric coordinates $w'\_0, w'\_1, w'\_2$, defined by
$$
w'\_i \equiv \frac{w\_i / Z\_i}{w\_0/Z\_0 + w\_1/Z\_1 + w\_2/Z\_2}
$$
Then we can interpolate any attributes by $w'\_0 A\_0 + w'\_1 A\_1 + w'\_2 A\_2$, and it will be perspective-correct interpolation. You can verify this is equivalent to your original interpolation formula in your question. If we have more than three scalar attributes to interpolate (which we usually do), this would be the cheaper way to do it.


---

