How Quad-Reprojection works

I’m interested in the math behind it.
I assume it has to do with custom projection matrix, but nothing more.

@lucasm has a great post about Matrix transformations - which in part goes through the transformation of world space to screen space. I think this might give you some starting points for other questions or places to start exploring.

1 Like

Thanks, I saw it and have a better understanding of matrices, but I stil dont know how would the node work

Seeing this years later but figured I’d share what I’ve learned, though I haven’t learned the full picture.

In the camera COMP’s code, c++ side (so no idea what this looks like exactly) , a matrix is created that transforms the rectangle or square that represents your screen, directly into the full render resolution you expect it to receive.


I think the only reason a matrix can get us to this frame of reference is it assumes your screen is planar, and a quad, though the docs suggest non rectangular quads may work.

In an analyzed captured frame I saw that the TDMatrix struct had an extra mat4 called quadReproject. This is not noted in the docs, I assume because it’s only present in very specific cases where quad reprojection is in use.

struct TDMatrix
{
	mat4 world;
	mat4 worldInverse;
	mat4 worldCam;
	mat4 worldCamInverse;
	mat4 cam;
	mat4 camInverse;
	mat4 camProj;
	mat4 camProjInverse;
	mat4 proj;
	mat4 projInverse;
	mat4 worldCamProj;
	mat4 worldCamProjInverse;
	mat4 quadReproject;
	mat3 worldForNormals;
	mat3 camForNormals;
	mat3 worldCamForNormals;
};

There’s also a function called TDQuadReproject() in the shader code. You can see a reference to this in the docs I linked above as well, but the function looks like this:

vec4 TDQuadReproject(vec4 v, int cameraIndex)
{
	switch (cameraIndex)
	{
		default:
			return v;
		case 0:
		{
	vec2 zw = v.zw;
	v = uTDMats[0].quadReproject * v;
	v.z = (zw.x / zw.y) * v.w;
			break;
		}
	}
	return v;
}

So quadReproject * v puts the verts of our screen aligned to the render view, and then the next line v.z = (zw.x / zw.y) * v.w; I believe just fixes the aspect ratio so that it fills the render top perfectly.