Hello,
I am trying to get Reverse Z working for my application but am not quite getting there. I managed to get the scene rendering again (except the skybox but I think that’s just a shader issue) but all my models are inside out and the front objects are being rendered behind the back objects. My setup is +Z forward and matrices should be column major.
I can’t quite figure it out!
I wonder if anyone would be kind enough to take a glance at some of my matrices? And setup?
I change the OpenGL stuff like this at app startup.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_GREATER);
glClearDepth(0.0f);
glDepthRange(1.0, 0.0);
And then my perspective matrix is changed to this.
void dMat4::SetIdentity() {
for (int i = 0; i < 16; i++) {
data[i] = (i % 5 == 0) ? 1.0 : 0.0;
}
}
void dMat4::SetPerspective(double fov, double aspect, double near, double far) {
auto tanHalfFov = std::tan(fov * 0.5);
SetIdentity();
data[0] = 1.0 / (aspect * tanHalfFov);
data[5] = 1.0 / tanHalfFov;
data[10] = 0.0;
data[11] = 1.0;
data[14] = near;
data[15] = 0.0;
}
I also have an GL_DEPTH_COMPONENT32 depth buffer.
Does my perspective matrix look okay? Thanks for any insight you might have. 
Your perspective matrix results in ZNDC=Zeye/near. So Zeye=near ⇒ ZNDC=1 and Zeye=∞ ⇒ ZNDC=0.
You’ll want either glDepthRange(0, 1) or glDepthFunc(GL_LESS). I.e. exactly one of those should be at the default setting (probably glDepthRange). glDepthRange(0, 1) and glDepthFunc(GL_GREATER) is preferred if you’re using a floating-point depth buffer, as having depth→0 as |Zeye|→∞ means that the increasing floating point precision closer to zero counteracts the decreasing depth scale factor as Zeye increases. This is the main reason for using reverse Z.
You’ll also want glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE). This setting. As well as changing the clip range to ZNDC∈[0,1], it also changes the interpretation of glDepthRange so that it maps [0,1] to [near,far] rather than [-1,1] to [near,far]. You’ll never get negative ZNDC values for Zeye∈[near,∞), so without the GL_ZERO_TO_ONE setting you’ll only use half the depth buffer.
Okay thankyou.
I must be doing something wrong somewhere else then. Because this code makes everything disappear.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_GREATER);
glClearDepth(0.0f);
glDepthRange(0.0, 1.0);
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
Does your data have positive Zeye? OpenGL convention (i.e. glFrustum/glPerspective) is that the eye-space positive Z axis is out of the screen, so only geometry with negative Zeye is visible?
Is your fov parameter in radians? glPerspective uses degrees, but both glm::perspective and your SetPerspective function require radians. Getting the units wrong often results in a FoV greater than 180° which makes the tangent negative.
Other than that, I can only suggest using transform feedback to capture the transformed vertices. Visible geometry will have 0<Zclip<Wclip.
Ah good catch. fov was degrees, I’ve fixed that now. Thanks.
I honestly don’t know much about this stuff. (learning on the fly) But I wanted my engine to be +Z forward (into the screen) and I have it setup up to be like that. This might be why I’m having trouble setting reverse Z up. I might not have my engine setup as well as I think it is.
I have also compared my SetPerspective function to glm::infinitePerspective(glm::radians(fov), aspect, near) and the data matches.
I’ll see if I can give that a go.
One thing I should note is that with the below setup my skybox is visible but filled geometry is not. Wireframe mode works for all geometry though. I don’t know what that means I’ve got wrong though. Is the perspective matrix, float depth buffer and the below OpenGL setup all that needs to change for Reverse Z to work? Should I be looking at shaders you think?
//glEnable(GL_CULL_FACE);
glEnable(GL_MULTISAMPLE);
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
//glCullFace(GL_BACK);
glFrontFace(GL_CW);
//Forward Z Depth Buffer
// glEnable(GL_DEPTH_TEST);
// glDepthFunc(GL_LESS);
// glClearDepth(1.0f);
//Reverse Z Depth Buffer
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_GREATER);
glClearDepth(0.0f);
glDepthRange(0.0, 1.0);
//glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Also: try disabling back-face culling.
I’ll try that. Thanks for your help. I’ll keep experamenting!
Okay I found my first problem. The shader for drawing the final quad to screen need the z value change from 0 to 1.
Old shader.
void main() {
TexCoords = inTexCoords;
gl_Position = vec4(inPosition, 0.0, 1.0);
}
New shader.
void main() {
TexCoords = inTexCoords;
gl_Position = vec4(inPosition, 1.0, 1.0);
}
The filled geometry is still hidden but at least this code works now.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_GREATER);
glClearDepth(0.0f);
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
The fact that this shader doesn’t use the perspective and view matrix tells me that its a matrix problem for the other geometry. Still don’t get why wireframe looks okay. Culling is disabled and the depth of the wireframe models looks fine.
I think my skybox was just covering all the scene geometry. 
It’s working now. Thanks for your time. 