Graphics Reference
In-Depth Information
Because for each screen raster (i.e., row of pixels) we hold
P
and
Q
constant
and vary
α
linearly, we can simplify the expression above to define a directly
parameterized function
u
(
α
)
:
)=
α·
z
Q
·
u
(
P
)+(
1
−α
)
z
P
·
u
(
Q
)
u
(
α
.
(15.8)
α·
z
Q
+(
1
−α
)
z
P
This is often more casually, but memorably, phrased as “In screen space, the
perspective-correct interpolation of
u
is the quotient of the
linear interpolation
of
u
/
z
by the linear interpolation of 1
/
z
.”
We can apply the perspective-correct interpolation strategy to any number of
per-vertex attributes, including the vertex normals and texture coordinates. That
leaves us with input data for our
shade
function, which remains unchanged from
its implementation in the ray tracer.
15.6.4.3 2D Barycentric Weights
To implement the perspective-correct interpolation strategy, we need only find an
expression for the 2D barycentric weights at the center of each pixel. Consider
the barycentric weight corresponding to vertex
A
of a point
Q
within a triangle
ABC
. Recall from Section 7.9 that this weight is the ratio of the distance from
Q
to the line containing
BC
to the distance from
A
to the line containing
BC
, that is,
it is the relative distance across the triangle from the opposite edge. Listing 15.25
gives code for computing a barycentric weight in 2D.
Listing 15.25: Computing one barycentric weight in 2D.
1
2
3
4
5
6
7
8
9
10
11
12
/
**
Returns the distance from Q to the line containing B and A.
*
/
float
lineDistance2D(
const
Point2& A,
const
Point2& B,
const
Point2& Q) {
// Construct the line align:
const
Vector2
n(A.y - B.y, B.x - A.x);
const float
d = A.x
*
B.y - B.x
*
A.y;
return
(n.dot(Q) + d) / n.length();
}
/
**
Returns the barycentric weight corresponding to vertex A of Q in triangle ABC
*
/
float
bary2D(
const
Point2& A,
const
Point2& B,
const
Point2& C,
const
Point2& Q) {
return
lineDistance2D(B, C, Q) / lineDistance2D(B, C, A);
}
Inline Exercise 15.10:
Under what condition could
lineDistance2D
return
0
,
or
n.length()
be
0
, leading to a division by zero? Change your rasterizer
to ensure that this condition never occurs. Why does this not affect the final
rendering? What situation does this correspond to in a ray caster? How did we
resolve that case when ray casting?
The rasterizer structure now requires a few changes from our previous version.
It will need the post-projection vertices of the triangle after computing the bound-
ing box in order to perform interpolation. We could either retain them from the
bounding-box computation or just compute them again when needed later. We'll
recompute the values when needed because it trades a small amount of efficiency