Multipass rendering with depth compare EQUAL

Started by
5 comments, last by kalle_h 9 years, 5 months ago

I'm doing deferred lighting, where I have a gbuffer pass, followed by a main pass. For alpha tested objects, I would like to do the alpha test in the gbuffer pass, and then skip alpha test in the main pass by using a depth compare function of EQUAL. This way the main pass should only render on top of pixels that passed the alpha test during the gbuffer pass.

The problem is that I can't get the depth values to match exactly between passes. It works sometimes, on some machines, in some situations, but not all the time. As far as I know, I am passing the exact same data for all verts and relevant shader parameters (matrices, etc). Each pass has a different vertex shader, but they compute the output position in exactly the same way. Is there any way to make this work reliably in D3D9? Or will I just have to use LESSEQUAL in the main pass, with a possible depth bias?

Advertisement

At work that is exactly how we handle alpha tested geometry: alpha test during the depth prepass, EQUAL depth testing during the main forward pass (we have a Forward+-like setup). This has always worked for use in DX11, altough we only run on Nvidia hardware so I can't say that I've tested it on a wide range of GPU's. You definitely need to make sure that your position calculations exactly match in both vertex shaders, although it seems you've already considered that. Have you double-checked the resulting shader assembly from both shaders to ensure that they're using the same sequence of instructions to compute the position? You'll especially want to check for any usage of the mad instruction, since that will have different precision relative to issuing separate multiply + add instructions. If that is the case, then you can try using the precise keyword to force the compiler to be more strict about the instructions that it uses.

Are you also using the very same D3DPT_ and vertex/index setup in each pass? I got hit by this once on some hardware: thinking I was clever, I used a trianglelist with an index buffer in one pass, but added a special case where I could avoid using (and updating) a dynamic index buffer and used a triangle fan for certain primitives in another. The result was tiny mismatches in Z and the consequent Z-fighting. Not so clever after all...

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Thanks for the replies.

I'm targeting D3D9 on the PC, so sadly no precise keyword. No trickery with changing primitive types. I've looked at the D3D bytecode, and it appears to match, but I could be missing something.

I'll keep looking.


Each pass has a different vertex shader, but they compute the output position in exactly the same way. Is there any way to make this work reliably in D3D9?

Just to verify one thing - you don't mix shaders and fixed function pipeline? For some reason I had lots of accuracy problems when doing it.

Cheers!

No fixed function.

I ended up just using LEQUAL for the main pass, and running alpha test again, at least on PC D3D9. I'd still be curious if anyone has any ideas.

Does it work if you use the same vertex shader on both passes?

This topic is closed to new replies.

Advertisement