the precision issue in 16 bit Z-Buffer

Hi ,all:
I am working at a project that aims to develop a virtual globe system by using WebGL.
We have made the system work, but there is z-fighting problems.
I have heard from others that there exists a solution that use a perspective projection matrix,a matrix different from the projection matrix used in the OpenGL,which can resolve/relieve the precision problem.
Does anyone known the equation of the projection matrix? Thank you very much!

An easier option might be to use a higher precision depth buffer. All reasonably civilized hardware will support a minimum of 24-bit, so - have you tried 24-bit and, if so, does the problem go away?

hi,mhagain,
chrome does provide 24 bit z-buffer,but some other browsers only support 16 bit z buffer.mhagain,thanks for your reply!

There is one way to work around this, and that is to use glPolygonOffset. See also webgl - How to correctly render coincident polygons in OpenGL (ES) - Stack Overflow.

Maybe this is applicable to your problem?

If you need an ultra depth buffer you can slice things into sections from front to back and draw them then from back to front.

Anything that is in both sides will be drawn twice but clipping should marry the results with any luck. If your globe is not very detailed like an actual planet, then this is probably the wrong way to go. But then 16bit can be killer. Any implementation of WebGL would probably conservatively use the highest precision depth buffer available. On a desktop that will be 24bits for consumer adapters.

[QUOTE=kamimail;1242484]hi,mhagain,
chrome does provide 24 bit z-buffer,but some other browsers only support 16 bit z buffer.mhagain,thanks for your reply![/QUOTE]

This doesn’t make much sense. I’ll admit that I’m not familiar with particulars of WebGL so I could be horribly wrong, but availability of depth buffer formats should depend on your hardware and driver, not your browser.

mhagain is dead on correct. You can open up WebKit and observe that WebGL implementation is more or less (with some variation depending on the backend) just a wrapper (the class is GraphicsContext3D) over GLES2 with some extra junk about making a context current (or something else) when getting ready to draw to it and some extra jazz to get the image data from it to the rest of WebKit so it can draw the 3D canvas.

Additionally, there is mainstream portable hardware that only has a 16-bit depth buffer: NVIDIA’s Tegra2, though they have something funky to help work around the z-fighting issues: http://www.khronos.org/registry/gles/extensions/NV/EGL_NV_depth_nonlinear.txt , but AFAIK, unless you have a special build of WebKit (or whatever browser you are using) you are not going to be able to coax the WebGL implementation to take advantage of it.

use ortho projection instead. With perspective projection all the precision is at the front. The further away from the camera you go the less precision.

Ortho projection isn’t much good if you’re drawing a scene that you want viewed with perspective though, is it?

Just a thought. To get the most out of the depth buffer the clip space should be restricted to just the bits of the scene that are actually on display.

So if you need to show a globe. The near clipping plane should be right in front of the globe, and the far clipping plane should be right beyond the horizon.

Hi, Everyone,
Thanks for all replies!
mhagain, according to the specification in WebGL 1.0, the size of default depth buffer is 16 bit integer.:slight_smile:
I have struggled this problem throught this weekend.due to the limitations in WebGL,Nether Lineard Depth Buffer nor [i]Logarithmic Depth Buffer[/i] is appropraite to be applied in my situation.
maybe ,the only way is to adjust the projection plane dynamicly.

I developed some stuff for WebGL a little while back and now that you mention it the depth dept. did seem really cramped, but I figured I just did not know what I was doing. Anyway I calculated the near/far planes because I needed accuracy for doing things like filling in back faces and shadows.

I never explicitly set the depth buffer anywhere as I recall (since you don’t seem to have to specify that with OpenGL??) so it may well be 16bit if so.

You might look into passing creation parameters. It may different for every browser. But there are some things you can control that way. Let us know how it goes please.

EDITED: http://www.swordofmoonlight.net/canvas.php?shadow=1

I think what he means is that tweak the projection matrix so the rows that produce x and y and w are as usual, but tweak the row that makes the z-coordinate to act orthogonal and tweak your shader to do the right thing too:

C code


mat4 /*or whatever you use for 4x4matrices */ proj;

proj=createProjectionMatrix(args);
/*
 tweak row that produces the z-coordinate:
*/
proj.row(3).element(0)=0.0f;
proj.row(3).element(1)=0.0f;
proj.row(3).element(2)= 2.0f/(far-near);
proj.row(3).element(3)=-1 -2.0f*near/(far-near);


GLSL


mat4 projection;
vec3 eye_coordinates;

gl_Position.xyzw=projection*eye_coordinates;
gl_Position.z*=gl_Position.w; //essentially kill the perspective divide on the z-coordinate.

Though this will drop the z-fighting far away, up close the z-fighting is going to become an issue…