0
\$\begingroup\$

Let's say that I have standard left-handed WorldToView and ViewToScreen row-major matrices in the same vein as the DirectX D3DXMatrixPerspectiveLH functions, like so:

EXVector vView = NormalizeVector(LookAt() - m_Position);

float fDotProduct = DotProduct(m_WorldUp, vView);

EXVector vUp = NormalizeVector(m_WorldUp - fDotProduct * vView);

// Generate x basis vector (crossproduct of y&z basis vectors)
EXVector vRight = CrossProduct(vUp, vView);

// Generate the matrix
row0.Set(vRight.x, vUp.x, vView.x, 0);
row1.Set(vRight.y, vUp.y, vView.y, 0);
row2.Set(vRight.z, vUp.z, vView.z, 0);
row3.Set(-DotProduct(m_Position, vRight),
         -DotProduct(m_Position, vUp),
         -DotProduct(m_Position, vView), 1);

EXMatrix mWorldToView(row0, row1, row2, row3);

Here's the left-handed mViewToScreen / projection matrix:

float zNear  =    0.001f;
float zFar   = 1000.000f;
float Aspect = DisplayHeight() / DisplayWidth();

float sinfov, cosfov; qsincosf(VFOV() / 2, sinfov, cosfov);
float cotfov = cosfov / sinfov; // cos(n) / sin(n) = 1/tan(n)

float w = Aspect  * (cotfov);
float h =   1.0f  * (cotfov);
float Q = zFar / (zFar - zNear);
float R = -Q * zNear;

row0.Set(w, 0, 0, 0);
row1.Set(0, h, 0, 0);
row2.Set(0, 0, Q, 1);
row3.Set(0, 0, R, 0);

EXMatrix mViewToScreen(row0, row1, row2, row3);

Many things like map/object culling depend on this fact:

// View to cull matrix
Q = (       zFar + zNear) / (zFar - zNear);
R = (2.0f * zFar * zNear) / (zFar - zNear);

row0.Set(w, 0, 0, 0);
row1.Set(0, h, 0, 0);
row2.Set(0, 0, Q, 1);
row3.Set(0, 0, R, 0);

EXMatrix mViewToCull(row0, row1, row2, row3);

Does anyone know how to derive the infamous "reverse depth with infinite far plane" from the original blog post for mViewToScreen and mViewToCull? Every single reference I have found (nlguillemot and nVidia, for example) is in the right-handed space.

Normally I am able to figure things out visually, but 4D matrices are a headache.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Well, I feel stupid now. Turns out I had to use a positive 1 in the last member of the third row instead of the -1 displayed in the right-handed examples, that fixes it. The best thing being that I don't even have to touch the cull matrix.

This sign flip was one of the first things I tried, but didn't work because the solution was mixed with other problems. I have just found it again by accident while reverting my changes and after testing every other combination you can imagine:

row0.Set(w, 0,     0,  0);
row1.Set(0, h,     0,  0);
row2.Set(0, 0,     0,  1 /* -1 */);
row3.Set(0, 0, zNear,  0);

EXMatrix mViewToScreen(row0, row1, row2, row3);

And, of course, remember to depth-test your fragments with GL_GREATER (or GL_GEQUAL) instead of GL_LESS (or GL_LEQUAL) and clearing depth to 0.0f, instead of 1.0f (which is the default value for the horizon). That's all the same for everyone.

Pair that with a floating point buffer and you should have improved depth precision and no far clipping.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .