zNear/zFar: how to do depth partitioning?

Hello Folks,

i’m pretty new to OpenGL and the engine i use saved me from getting into dirty details sofar… The problem i can’t solve is pretty classic and can be solved, but i would like to ask the skilled opengl programmers for exact command sequence to solve it.

Problem:
i have to render far away and very close objects. Moving zNear at required (very close) distance causes distant objects to flicker wild.

Solution:
depth buffer partitioning performing multipass rendering with different near/far settings and overlaying results. Basic process:

  1. clear the context
  2. render background
  3. adjust near/far for distant objects
  4. apply projection
  5. render distant objects
  6. adjust near/far for close objects
  7. apply projection
  8. render close objects

I got the steps performed by the engine, but in the second pass all distant geometry is clipped away, the background is black and don’t show off. Ergo results of the first pass are overlayed and wasted totally. I would like to ask for detailed opengl command sequences to get bot rendering pass results overlayed properly.

Big thanks in advance
Paul

Hmm. Hard to tell what you’re doing wrong. Sounds like between steps 5 and 6 you’re clearing the color buffer or something. You should only be clearing the depth buffer here (and maybe stencil if you use it).

In step 1 you should clear the depth/stencil as well – and clear the color buffer here two if collectively your background, near, and far don’t set all pixels (or samples, if doing MSAA).

Also, the “near” of the far subfrustum should be the same as “far” of the near subfrustum. Just pick a split distance.

Is it possible to provide exact opengl function call sequence? I then recheck the call sequence in the engine and fix the problem then. Something like:

glEnable();
glEnable();
glFrustum();
drawFarGeometry();
glClear()
glDisable();
drawNearGeometry();

Nobody can provide you with “exact opengl calls” becuase nobody is writing your application except you.

However, we can guide you on the process you need to follow.

  1. clear the colour buffer|Depth buffer|stencil buffer
  2. Set Projection matrix using near and far for distant objects
  3. Set camera view frustrum
  4. render background
  5. Clear depth and stencil buffers
  6. Set Projection matrix using near and far for close objects
    Set near value to ‘old far’ value
  7. Set camera view frustrum
  8. render close objects

The assumption now is that you have depth sorted your scene before attempting to draw any objects and you are able to split the scene into two parses using the arbitary far split value.

I experimented with clearing depth buffer in the second pass with partial success. First pass renders background, terrain and water, second pass should render the near model. Current output is background + near model, but terrain doesn’t show off. So basically pass overlay succeeded, but i “lost” my terrain. As the old telling goes “one image says more than 1k words”, here the different result renderings:

The problem itself: heavy z-fighting and flickering with single pass rendering, zNear=0.06, zFar=151326.9
http://www.flickr.com/photos/43342833@N04/5995604542/in/photostream

Recent trial with double pass: distant [zNear=100, zFar=151326.9], close [zNear=0.06, zFar=100]
http://www.flickr.com/photos/43342833@N04/6055406732/in/photostream

Previous try with logarithmic z via vertex shader (z-fighting):
http://www.flickr.com/photos/43342833@N04/6005673829/in/photostream/

Targeted rendering (produced on low end graphics on rare frames without flickering):
Imgur

Any ideas? Why terrain doesn’t show off?

Did you clear just the depth and the stencil? That is: glClear(GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);

here is the exact code sequence performed in the cleanup before second pass begins

GLContext context = context(ctx);
GL gl = context.getGL();
JoglContext jctx = (JoglContext) ctx;
gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT);
gl.glDepthMask(true);
gl.glClearColor(r, g, b, jctx.getAlphaClearValue());
gl.glClear(GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT);
gl.glPopAttrib();

Why are you pushing the depth buffer attributes? Just set them back when you render again.

I’m not 100% certain, but the content of the depth buffer itself may be restored by popping the depth buffer attribute.

I notice you have set your near and far to:
zNear=0.06, zFar=151326

The near is very near!
Perhaps you will get less Z fighting if you use 1.0 instead and you won’t need multi-pass depth rendering at all.
Also, have you ensured you have at least a 24-bit depth for your context?

yes, the zBuffer is set to 24bits and i need close zNear to get cockpit elements visible. With zNear 1 most of the cockpit will be invisible.

yep, a small near will be needed for cockpits, etc.
I was think that you don’t need such a small value when rendering the main part of the scene - infact it causes issues such as Z fighing.
Can you not just draw the cockpit and instruments to an offscreen buffer and then overlay that as a 2D quad, or is this a proper 3D model cockpit? If so, then yes a second pass will be inevitable using a small near and small vfar.

You should render the near objects first unless they require blending. Use glDepthRange to map your near and far objects to distinct ranges of depth buffer values, don’t clear the depth buffer in between. For something small like a cockpit you don’t need to reserve a large range, e.g. glDepthRanged(0.0, 0.01) for near objects and (0.01, 1.0) for far objects should be ok.