the brute force approach would be to put your vertex in a v3, then use v3transform() [i think thats the name of it] with the world, view, and projection mats. this would give you the x,y,z coords of the vertex in object space (before you start), world space (after world transform), and camera space (after view transform), as well as the 2d screen coordinates of the vertex (after projection transform). then you just use the values from the section of the pipeline you want. you could even create a projection matrix that doesn't include the screen translation, just the projection, and get the x,y,z coords for homogeneous screen space (after projection, but before translation to screen coords). but again this is solving for things that the graphics pipeline is already solving for (duplication of effort).

Using that technique is probably too prohibitive for the light collection stage in the Forward+ renderer. But i appreciate your detailed response and info on these various transformations.

I have stumbled upon MJPs light indexed implementation and the HLSL contains the tile frustum building code. I understand how the equation works now but don't quite understand how it ended up with that equation exactly. His implementation is much simpler to understand and directly builds the frustum planes from the projection matrix with some vector bias offset relative to each tile the thread group is in.

From what i recall(from memory), the code looks like this.

... float2 tileOffset = displaySize / ( 2 * float2(tileSize, tileSize) ); float2 tileBias = tileOffset - threadGroup.xy; float4 c1 = float4( projection._11 * tileOffset, 0.0f, tileBias.x, 0.0f ); float4 c2 = float4( 0.0f, -projection._22 * tileOffset, tileBias.y, 0.0f ); float4 c4 = float4( 0.0f, 0.0f, 1.0f, 0.0f ); float4 frustumPlanes[6]; frustumPlanes[0] = c4 - c1; // left frustumPlanes[1] = c4 + c1; // right frustumPlanes[2] = c4 - c2; // top frustumPlanes[3] = c4 + c2; // bottom // near, far frustumPlanes[4] = float4( 0.0f, 0.0f, -1.0f, -fNear ); frustumPlanes[5] = float4( 0.0f, 0.0f, 1.0f, fFar ); // normalize planes for ( int i = 0; i < 6; ++i ) frustumPlanes[i] = (PlaneNormalize(...)); ...

Sigh... I wish i'm much more comfortable with math.