• Advertisement
Sign in to follow this  

Optimization: Depth Only Rendering Pass

This topic is 4023 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm working on a shader graphics engine. First, it disables the color channels and renders the scene to the z-buffer. Then, it turns the color writing back on, and renders the final scene. This works great in that it only has to pixel shade the pixels that are not rejected by the final z-buffer. I get a little z fighting because the pixel shaders are not outputting the same z-value as the fixed pipeline. Has anybody else had this happen? This happens to all my geometry in the scene, even the quads that are rendered using the world matrix set as the identity matrix. It can easily be fixed by adding a small offset to the z value in the vertex shader, but that solution doesn't seem ideal. I've heard messing with the z-bias render state is not a good solution either. Anything I'm missing? Thanks for the help.

Share this post


Link to post
Share on other sites
Advertisement
The trouble with Z Bias is that theres no real standard way of implementing it on the graphics cards so the units are fairly meaningless and so you can't reply on getting the same result every time. It's far safe to diddle the mvp matrix instead :)

Share this post


Link to post
Share on other sites
Been there, done that. Even LESSEQUAL gives you patterns of misplaces z-rejects over all surfaces. We solved it by multiplying projectedPos.z with 0.001f. We tried other formulas, viewPos.xyz * 0.001f being the only other method that does not produce heavy artifacts. But this version has problems with parts close to the far clipping plane. There's a seem at the far clipping plane only covered by the PreZ pass but not by the actuall renderings. And you get Z-fighting on distant scene parts with a certain angle to the camera. Better head for the projectedPos.z * 0.001f.

Another question while we're at it: Does the PreZ pass actually gain you anything performance-wise? My test system is Athlon 64 3200+, Geforce7800GT. Although the average pixel shader is 100 instructions in size, we lost roughly 30% framerate by adding that PreZ pass. Only simple test scenes and small indoor scenes do profit a bit by PreZ. From my present experience, I'd drop out PreZ happily if I could. The problem is that we also render out the depth into a texture at the PreZ pass. And there are a couple of post processing filters now that rely on accessing that depth. Bad luck, I guess.

Bye, Thomas

Share this post


Link to post
Share on other sites
Ummm, how about using the same geometry transformation during both passes. This is a solved problem, eh? Just because you're not writing color doesn't mean you have to turn off shaders, just write a very simple 'prepass' shader that only does transformation, and no color/lighting work. You should be able to use ZEQUAL and get EXACTLY the same rasterization on the lighting passes as you do during your z-prepass. Doom III worked this way. And yes, it is very often a performance win (assuming that your pixel shaders are expensive and/or you have a non-trivial amount of overdraw).

Share this post


Link to post
Share on other sites
Quote:

Ummm, how about using the same geometry transformation during both passes. This is a solved problem, eh? Just because you're not writing color doesn't mean you have to turn off shaders, just write a very simple 'prepass' shader that only does transformation, and no color/lighting work. You should be able to use ZEQUAL and get EXACTLY the same rasterization on the lighting passes as you do during your z-prepass.


No. As I said: I tried it. It doesn't transform exactly the same. Same matrices, same viewport, yet I got sparkling ZFail patterns everywhere. Happened both on a ATI Radeon 9800 Pro and a NVidia Geforce 7800 GT. I've read this claims in some docs as well, but theory doesn't match reality here.

Bye, Thomas

Share this post


Link to post
Share on other sites
u should never see zfighting by drawing the same geometry, ive been doing it for years + never an issue ( in fact in the gl spec IIRC its guarantted to work) . the only cases where it can fail is if the vertices are not the same
(eg clipplanes are enabled)

Share this post


Link to post
Share on other sites
This sounds to me a lot like deferred shading - is there a reason why you're not not using that instead? Or are you trying to support older hardware?

Share this post


Link to post
Share on other sites
Assuming you're using the same geometry for the depth only pass and the rest of the passes, the ONLY way you should be getting ANY sort of z-fighting artifact is, as others have mentioned, if you're using a different transform.

Note that using the FFP transform and doing the multiply yourself in a vertex shader are NOT THE SAME! There are some options and ways you can work around this, but, like someone already said, simply write a depth-only shader that transforms the vertices exactly as is done for the rest of the shaders.

Share this post


Link to post
Share on other sites
Quote:
Original post by blaze02
I get a little z fighting because the pixel shaders are not outputting the same z-value as the fixed pipeline.


In OpenGL you can say ftransform() in your vertex shader and it guarantuees that the transformation output will be identical to the fixed pipeline. Doesn't DirectX offer a similar function()?

Share this post


Link to post
Share on other sites
Strange then. Both PreZ and main geometry were done by shaders. Same world matrices, same view matrix, same projection matrix. Different render targets, but of the same size. Still I got z-fighting artifacts. It has been a while since I last checked it, though. I better recheck that when I'm home again before insisting on it.

Bye, Thomas

Share this post


Link to post
Share on other sites
Are you turning off z-writes for the color write? Since you've already drawn all the depth information you only need to do a z compare when rendering the colour buffer.

Share this post


Link to post
Share on other sites
perhaps youre doing something like
A/
MultMatrix( mat )
draw mesh

B/
draw mesh
in shader -> mat * vert

whilst logically they should result in the same, in reality cause of the different storage methods it wont

Share this post


Link to post
Share on other sites
Quote:
Original post by krausest
In OpenGL you can say ftransform() in your vertex shader and it guarantuees that the transformation output will be identical to the fixed pipeline. Doesn't DirectX offer a similar function()?


Nope.

(Any idea how widely supported the ftransform() function is in GLSL?)

Share this post


Link to post
Share on other sites
This is a normal problem when trying to combine fixed-function z pass and shader color pass. Dont do it, because it wont work on certain cards. Both pases should use shaders and there will be no problem.

Share this post


Link to post
Share on other sites
I'm currently doing z-prepass in my renderer, and it's working just fine on a 7800. I am using shaders for prepass and main pass.

[edit - This is using DX9, btw.]

Share this post


Link to post
Share on other sites
What is the test scene that you are using? If there is not a whole lot of movement frame to frame, and if you are not clearing the z-buffer to 1.0, I have had situations where it seems like you are getting z-fighting, but it is really that the z-buffer is never getting cleared.

Can you describe your exact sequence that you are using for rendering? Are you doing any depth surface moving around or copying? Try to be as specific as possible when you describe the problem.

Also, have you tried using PIX to step through a frame one draw call at a time and see what is happening? If you haven't ever done it - learn how, it is worth it. You could also use NVPerfHUD if you have an NV card. The solution should show itself if you start taking a closer look. Good luck!

Share this post


Link to post
Share on other sites
Quote:
Original post by superpig
Quote:
Original post by krausest
In OpenGL you can say ftransform() in your vertex shader and it guarantuees that the transformation output will be identical to the fixed pipeline. Doesn't DirectX offer a similar function()?


Nope.

(Any idea how widely supported the ftransform() function is in GLSL?)

It's part of the spec, you can't have a GLSL implementation without it.

Share this post


Link to post
Share on other sites
Quote:
Original post by OrangyTang
Quote:
Original post by superpig
Quote:
Original post by krausest
In OpenGL you can say ftransform() in your vertex shader and it guarantuees that the transformation output will be identical to the fixed pipeline. Doesn't DirectX offer a similar function()?


Nope.

(Any idea how widely supported the ftransform() function is in GLSL?)

It's part of the spec, you can't have a GLSL implementation without it.


Hm, ok. So how widely available is standards-compliant GLSL? [grin]

Share this post


Link to post
Share on other sites
Goat knows. I've never heard of ftransform() not working though. IIRC GLSL corresponds to DX shader model 2.0 and up (ie. GF FX hardware onwards).

Share this post


Link to post
Share on other sites
As others have said and it can't be emphasized enough: do not use the fixed function pipeline anymore, for anything. If you use shaders in both passes the results will be identical, and you can even set the compare mode to "equal" if you want.

Theoretically in GL ftransform will work too, but it's unnecessary.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement