- Home /
How do projection matrices work in Unity?
I'm working on a screen-space reflection shader for Unity but I'm running into some incorrect values when transforming from clip space to camera space.
To get a better grasp on how this transformation works I've ran some tests:
Matrix4x4 projectionMatrix = GL.GetGPUProjectionMatrix(targetCamera.projectionMatrix, false);
Vector4 clipSpace = projectionMatrix * new Vector4(0.0f, 0.0f, -targetCamera.nearClipPlane, 1.0f);
float depth = clipSpace.z / clipSpace.w;
Result: depth = 0.0.
Matrix4x4 projectionMatrix = GL.GetGPUProjectionMatrix(targetCamera.projectionMatrix, false);
Vector4 clipSpace = projectionMatrix * new Vector4(0.0f, 0.0f, -targetCamera.farClipPlane, 1.0f);
float depth = clipSpace.z / clipSpace.w;
Result: depth = 1.0.
So far, this makes sense. In clip space the Z component represents linear depth from the near clip plane to the far clip plane.
But then I ran this test, expecting the result to be about 0.5f:
Matrix4x4 projectionMatrix = GL.GetGPUProjectionMatrix(targetCamera.projectionMatrix, false);
Vector4 clipSpace = projectionMatrix * new Vector4(0.0f, 0.0f, -targetCamera.farClipPlane * 0.5f, 1.0f);
float depth = clipSpace.z / clipSpace.w;
Result: depth = 0.995.
Apparently my assumption was not correct. It seems the Z value in clip space follows some sort of curve where it rapidly increases to values above 0.9 and then slowly increases to 1.0 at the far plane. What am I missing here? Is my test case incorrect?
Note: In my test setup I used a perspective camera with the near plane at 0.1 and the far plane at 20
It's been a while (my Red OpenGL book has been a cat pillow for years) but I thought that was correct - those z values are purposely more fine-grained at near values, since that's where bad-looking overlaps tend to appear (but I wouldn't have guessed that 99% is used for the 1st half of the range.)
For the standard stuff, Unity tends to copy it exactly.
The test looks a tiny bit off (should be (near+(far-near)*0.5,) but it's only a difference from 10.0 to 10.05.
Answer by FortisVenaliter · May 04, 2017 at 08:19 PM
What you're expecting would be linear depth mapping. That hasn't been used for a while because it does cause clipping issues, as Owen mentioned. Instead, the calculation is based on the reciprocal. Read this article from NVIDIA for a pretty good description of why it works that way, including equations for how it's calculated.
Your answer
Follow this Question
Related Questions
Reproduce WorldToViewportPoint function 2 Answers
Vertical Perspective / Horizontal Orthographic 1 Answer
How to get Transformation Matrix 0 Answers