Skip to content
Perspective-Correct Interpolation
step 1/5

Reading — step 1 of 5

Read

~1 min readRasterization

Perspective-Correct Interpolation

A textbook lie: barycentric weights give correct per-vertex interpolation in object space, not in screen space.

If you naively interpolate UV coordinates linearly across pixels in screen space, the result is wrong. A long perspective-foreshortened triangle (like a floor receding into the distance) will show stretched, smeared textures. The fix is in every GPU since the late 90s but easy to forget when writing a software renderer.

The problem: perspective divide (/ w) is nonlinear. Two attributes that vary linearly in 3D no longer vary linearly across the projected 2D image — they vary as a rational function of screen position.

The fix — interpolate A / w and 1 / w instead of A directly:

At each pixel with screen-space barycentric (u, v, w):
    one_over_w = u/w0 + v/w1 + w/w2
    A_over_w   = u*(A0/w0) + v*(A1/w1) + w*(A2/w2)
    A          = A_over_w / one_over_w

(Here w0, w1, w2 are the clip-space w values of the three vertices — typically the pre-divide depth.)

A / w and 1 / w do vary linearly across the projected triangle. Their ratio recovers the true 3D attribute at that pixel. This is what real GPUs compute under the perspective qualifier on a varying.

Depth (z) can be interpolated either way: linear in screen space gives 1/w (already linear); linear in eye space requires the rational trick.

UVs absolutely need this — without it, textures shear on perspective triangles. Colors can usually get away without it (we often shade in screen space) but you'll see banding on long triangles.

This is the single most common bug in homemade software rasterizers. Once you fix it, your textures stop looking like 1996.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…