New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing depth range convention in projection matrices #377

Open
rdb opened this Issue Aug 15, 2018 · 3 comments

Comments

Projects
None yet
3 participants
@rdb
Member

rdb commented Aug 15, 2018

I propose making the default Panda convention for depth range 0..1 instead of OpenGL's -1..1 range.

The OpenGL range was presumably originally chosen for consistency with the X and Y axes (which understandably range from -1 to 1 as well). However, this was before the advent of floating-point depth buffers, which are most precise for values around 0, so all the best depth precision is now uselessly stuck in the middle of the depth range: (source)

This is particularly relevant when doing the reverse Z trick, which involves flipping around the near/far clip planes in combination with floating-point depth buffer and infinite draw distance in order to get a truly ridiculous level of depth precision.

Depth calculations also become less precise when doing math with the projection matrix on the CPU, I've found, including determining the correct coordinates for the bounding volume. Calculations with a projection matrix generated for a 0..1 range are much more precise when the near and far values are far apart, due to the way the math works out.

Direct3D and Vulkan do not suffer from this issue, as both have defined the depth range to go from 0 to 1. This avoids the precision problem. As of OpenGL 4.5 we can use glClipControl to also set the depth range from 0 to 1 in OpenGL (presently implemented via the gl-depth-zero-to-one config var). WebGL and OpenGL ES have no such equivalents.

My proposal is that at the very least, we change the internal projection matrix calculations in Panda3D itself to only assume a 0-1 depth range for now, and consider that the "Panda convention". The OpenGL renderer will rescale the matrix to report depth in the -1 to 1 depth range before sending it to the driver, unless gl-depth-zero-to-one is set, in which case the matrix will not need to be modified.

I would suggest leaving the clip-space-related shader inputs with the existing -1..1 range so that existing shadow shaders are not broken. The clip space will continue to map depth to -1 to 1 range, and apiclip space will be whatever matches the current API and gl-depth-zero-to-one setting.

This change may break any code that is directly dealing with lens projection matrices, as well as any code that is using lens extrude calls with an explicit depth value.

@theclashingfritz

This comment has been minimized.

theclashingfritz commented Aug 16, 2018

+1 I argee with this change. Precision in depth is very important and the system OpenGL uses causes alot of clipping issues when things and close but not overlapping.

@Moguri

This comment has been minimized.

Collaborator

Moguri commented Aug 16, 2018

+1 from me. What happens if gl-depth-zero-to-one is set but the OpenGL implementation does not support it?

@rdb

This comment has been minimized.

Member

rdb commented Aug 26, 2018

@Moguri if gl-depth-zero-to-one is set but OpenGL doesn't support it, it is ignored and Panda3D will convert the projection matrix to use the old depth range, the way it works today. However, I suppose that people who write shaders that rely on a particular depth range might find it difficult to write a shader that works regardless of whether gl-depth-zero-to-one is respected. Hmm.

One way we could theoretically deal with this when we switch to an entirely SPIR-V based shader pipeline, is to rewrite all shaders to change gl_Position by injecting some extra bytecode to the end of the vertex shader, so that we can just pretend that the clip space Z range is always 0..1 and "fix" it at the last possible moment if it's not. It'd be hacky, but it's probably the most robust way to handle this sort of thing, and it's likely we will end up massaging SPIR-V shaders for some other portability reasons anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment