Multi-pass rendering problem

I fear this will take some advanced explaining…

Ok, I had my simple engine up-and-rendering away happily, opaque & transparent meshes using GLSL and stuff. So far so good. However, the rendering used multiple lights in one pass, all calculated & accumulated in the GLSL code. This turned out to be a bad design decision, mostly because it just requires too many input attributes. I hit a limit (OpenGL ES).

So I decided to turn it into multi-pass rendering, with each light’s contribution blended additively to the rendered mesh.

Having read a bit about how go go about it, I came up with this schematic approach:

Pass 1:
[ul][li]Ambient lighting (+ one light, optionally)[]Blending disabled[]Z-test enabled, GL_LEQUAL (or GL_LESS)[]Z-write enabled[/ul][/li]
Pass 2-n: (depending on number of affecting lights)
[ul][li]Additive blending (i.e. GL_FUNC_ADD, GL_ONE, GL_ONE)[
]Z-test enabled, GL_EQUAL[*]Z-write disabled[/ul][/li]
First off, does this look like a working assumption?

However, as always, things just doesn’t work as expected, do they? :frowning:

My test app renders a few opaque primitives with a single shader and three lights (different colors, to be identifiable). It has mouse control to orbit the camera around the scene and also zooming. Nothing is animated.
So, when using the optional light in the 1st pass it will render 3 passes.

Now to my problem: When the app starts, without moving the mouse, I can see all everything rendered correctly. But as soon as I rotate the mouse the rendered meshes are kind of “peeled” away and disappears. A tad difficult to describe this phenomenon. This “peeling” is probably a side-effect of tessellation.
If I zoom inwards they become visible again. But if I zoom out, or rotate, they disappear. Also, to see them again I must zoom in further than I did the first time, and so on. After a while of this zoom in+out further and further, I can’t see the rendered objects at all any more.

These symptoms leads my fumbling mind to the conclusion that this is related the Z-buffer somehow.

If I disable Z-testing for all passes I can see everything all the time, but then of course, the rendering will not be correct.

And yes, I am clearing the Z-buffer using glClear().
And also, this behaviour is identical on multiple platforms & drivers, so I’m quite sure the culprit is somewhere in my application.

I can’t attach images at this time, but will attempt to do so later if my explanation is insufficient (probably).

Any tips on things to test & verify are gladly appreciated!
Or even flames for my stupidity :wink:

Small update.

It appears my state setting code wasn’t quite correct; the glDepthFunc() was probably never updated.

However, the problem remains essentially the same.
The only differance is that now the 1st pass is only visible as long as I’m zooming in. If I stop, 1st pass disappears. The other passes are visible. The behaviour when rotating is the same; the meshes disappear, until I zoom in again.

I think you are right - it’s something along the lines of depth test.
I can only suggest you try disabling/altering 1 part of the engine at a time to find the offending line in your app.

Meanwhile, check the following has been done prior to rendering each pass; don’t assume that the state is already set by another part of the engine - set the state values explicitly.

glenable glDepthMask (true)
glenable glDepthTest
glDepthFunc (GL_LESS) - first pass
glDepthFunc (GL_LEQUAL) - second pass

…prevent any possible clipping or culling (not entirely relevant but may be helpful)

glDisable (GL_MULTISAMPLE) - have you multisample buffers? Are you resolving these between passes (if applicable?)
glDisable (GL_ALPHA_TEST)
glDisable (GL_SISSOR_TEST)
glDisable (GL_CULL_FACE)
glDisable (GL_CLIPPLANE0)

I have multi-pass Z-only rendering in my engine, and the depth function is set as above on each pass.
The only difference is I diable glColorMask on the first pass.

Yep. Been trying that for a while now without result.
But as you said, maybe I’m assuming too much… :frowning:

Thanks! Will try those settings. Many of them I don’t use though. But I guess it couldn’t hurt being paranoid :slight_smile:

Hmm. Well, what do you know? Enabling Z-write on the 2nd (and later) passes did it. The one thing I did NOT think it could ever be.

Now it’s working, but I’m not at all sure I understand why this is needed. I mean, why would subsequent light-contributing passes need to write to the Z-buffer?

Much happier, but slightly confused…

Glad to have helped. I guess you still need depth writes because your first pass is the ambient and this is essentially the entire scene.

Yeah, the first pass includes the ambient term so it should update all pixels of the scene, color and Z. That’s why I don’t understand why the subsequent Z-writes are needed. It will only be writing the same Z-value to the Z-buffer… hmmm.

Yeah, the first pass includes the ambient term so it should update all pixels of the scene, color and Z. That’s why I don’t understand why the subsequent Z-writes are needed. It will only be writing the same Z-value to the Z-buffer… hmmm.

This thread (see linked post in particular) discusses mp-rendering, and what he writes about the passes and Z-write is just like you’d expect, and like I would want to do it too.

And I guess, with a Z-only first pass, that Z-writing is disabled for the subsequent passes. Should be the same in this case…

Found this very interesting forum topic.
It seems to describe a very similar problem…
And I’m quite sure I don’t enable glDepthMask() before calling glClear() …

EDIT: Yesss, it works!! Now I can have z-write enabled only for the first pass and disabled for all other. :slight_smile: