When doing GPU programming, it’s sometimes useful to determine the positions of the vertices of the
current triangle primitive in a fragment shader. The usual advice here is to use a geometry or
tessellation shader to gather up the positions and pass them along explicitly to the fragment
shader. It turns out, though, that there is a relatively straightforward solution without any extra
shader stages using the standard derivative functions
dFdy. It works as long as the
(non-perspective-correct) barycentric coordinates for the current fragment are available. I’m sure
I’m not the first one to come up with this technique, but a quick search didn’t find any
explanations of it, so I thought I’d write it up, because it turned out to be useful in Pathfinder.
An important caveat applies: Make sure that you’re sure you need to do this. It’s easy to go wild with this technique and end up with more varyings than the simple solution would call for. In general, this technique is most useful when it saves a geometry or tessellation shader invocation.
Here I assume that the barycentric coordinates of the current
fragment are known. They must sum to 1, so it suffices to know two of them to compute the other
one. If you need barycentric coordinates and cannot compute them from other varyings you have
around, then you can pass them to the fragment shader by declaring
noperspective in vec2 vLambda;
vLambda to , , and for the first, second, and third
vertices respectively. We also need the gradients and
. Following the example above, the function
dFdx(vLambda) will yield
dFdy(vLambda) will yield .
Let be the screen-space position of the current fragment (i.e.
let and be the positions of the fragments to the
immediate right and above, respectively. , , and are the
barycentric coordinates of the current fragment; likewise, , , and
are those of the fragment to the right, and , ,
and are those of the fragment above.
We know that for all triangle vertices , , and . Putting it all together, we formulate a system of equations:
After some algebra and the application of Cramer’s rule, we get:
Notice that shows up over and over again in these formulas. That value is the Jacobian determinant . Using to represent the row vector , we can more succinctly rewrite the above as:
Along with point positions, sometimes the triangle edge vectors , , and are useful. These have even simpler formulas:
The expressions for the vectors (for vertices ) are straightforward as well:
Below is some GLSL code to compute screen-space triangle vertex positions from