Skip to main content
GameDev.net gamedev.net
🔒 Locked

Z pre-pass

Started by tscott1213 Apr 28, 2005 at 6:26 PM 9 replies 3.6k views
Original Post
tscott1213
tscott1213
Hey all, I am working on an effect using HLSL that requires a z-prepass (also, my understanding is that every frame in Doom III starts with a z-prepass so I want to understand how to do this). However, I am pretty new to HLSL so I have a couple of questions. 1) I am rendering to a texture, so will there be a z-buffer and will it be retained until I either switch render targets or clear the buffer? 2) As I mentioned, I need to do a z-prepass and then start doing actual color writes onto the texture. How can I write only to the z-buffer so that the first pass is quick? 3) Do I need to write a different z-prepass shader for every model that uses a different vertex buffer type. Or, should I create a second vertex buffer for each model that contains only position data so that I am not sending as much vertex data during the z-prepass step? Thanks for the help. Todd
Woodchuck
Woodchuck
A Z-prepass consist of drawing all the geometry in a transparent manner to set up the zbuffer with the value of the final render. No shaders, no textures, choose the fastly method to render your geometry in the backbuffer.
I think you need to use a z-bias after when you will render the geometry with shaders and textures.

With this technic you ensure that all the expensive shadered pixels you write will really be in the final render.
tscott1213
tscott1213
Ok,

My intention was to not use the fixed function pipeline in which case I would do the following:

1) set the renderstate for D3DRS_COLORWRITEENABLE to false
2) set the renderstate for D3DRS_ZENABLE to true
3) set a vertex shader to transform position
4) set the pixel shaders to simply output some color (it wont be used anyway)
4) draw all the geometry in the scene

However, it sounds like you are (quite reasonably) suggesting that I just use the fixed function pipeline since it is such an easy rendering pass, right?

The graphics cards manufacturers are always talking about removing the FFP eventually (when backwards compatibility is not an issue), if they were to remove the FFP how would we accomplish the z prepass?

Thanks
Todd

superpig
superpig
I wouldn't use the fixed function pipeline for this, partly because there can be issues when you later try drawing programmable-pipeline geometry (things like different precisions causing slightly different z values). I think all Woodchuck was saying was that you should make the shaders as streamlined as possible - no texture coordinates or diffuse being passed out by the VS, and no blending done by the PS.

As for your original questions:

1) There will be if you set one. The fact that you're rendering to a texture is irrelevant as far as the renderer is concerned; it's just writing to a color/depth pair of surfaces. You should be able to switch the color surface around without interfering with the depth surface.

2) Try D3DRS_COLORWRITEENABLE, but also use alphablending of (zero, one). I'm told it's detected by some cards (ATI, IIRC) and special-cased for an extra speed boost.

3) You could put all your position data in a seperate stream, certainly.
Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse
tscott1213
tscott1213
I was going to disable alphablending entirely, no?

Your point 3 is a great idea I wasn't considering. Just to make sure I understand, your saying for each piece of geometry I create two vertex buffers: one with position data and another with everything else (which may differ by geometry). Then, I can do the z-prepass with the position vertex buffer and I can do the actual render by setting stream 1 with the position vertex buffer and stream 2 with the customized vertex buffer data.

Finally, is there a way to output to two textures in a single pass?

What I am trying to do here is expand a bit on the Vulcan Fire Effect in GPU Gems to make it more usable in a game. For performance, the flames are first rendered to a texture that is 1/4 the size of the screen. This greatly increases speed given that there is so much alpha blending going on. The 1/4 sized texture needs depth data so that the flames are properly occluded by objects in the foreground, but the screen z-buffer can't be used because it is not the same size as the texture. This poses a bit of a problem because z-prepassing the entire scene to a texture just for the flames could get costly.

Thanks
Todd
Woodchuck
Woodchuck
Can't you get the depthstencilbuffer surface, perform a stretchrect into a texture and do the z-test by yourself ? (a z-fail resulting on a float4(0,0,0,0) that will be rejected by the alpha test)

[Edited by - Woodchuck on April 28, 2005 10:16:31 PM]
tscott1213
tscott1213
Woodchuck,

Thank for you very much for all the help....I don't quite understand your proposal.

Are you saying: 1) render the entire scene except the flames to the screen, 2) get the screen's depthstencil buffer surface, 3) stretch that surface into a texture 1/4 of the size of the screen, 4) use that information while rendering the flames into a texture to do the z-test myself, 5) render the flames into the screen buffer using an alpha test.

If this is possible, it sounds like a great idea. Can I render the depthstencil buffer into a texture?

Thanks again.
Todd
Woodchuck
Woodchuck
That's it.

You can have the depthstencilbuffer surface with the IDirect3DDevice9::GetBackBuffer method and strectch it with the stretchrect method (seems it's allowed).

EDIT : IDirect3DDevice9::GetDepthStencilBuffer method instead...;D

[Edited by - Woodchuck on April 29, 2005 12:32:59 PM]
tscott1213
tscott1213
I'm going to try to make this work.

I'll compare the performance to 1) no attempt at optimization and 2) doing a full z-prepass to the small texture.

I'll post the resulting FPS in case you or others are interested.

Thanks for the help.

You too superpig.
I am going to look at setting up my engine to do the z-prepass the way you mentioned.

Todd
superpig
superpig
Sadly, StretchRect won't help you - if you look at the docs page for it, you'll see under "Depth and Stencil Restrictions" it says "No stretching or shrinking is allowed."

I think the only way to do that sort of thing is to track your own Z information in a float texture.
Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse
tscott1213
tscott1213
I was thinking about this some more last night because I was concerned that locking the depthstencil surface was going to be slow...

I am now thinking that since I am planning to do a z-prepass every frame anyway, I will render the depth during the z-prepass into a texture the size of the screen and sample that texture when rendering the flames.

This way the z-prepass can be used for the rest of the scene but I still have depth data that I can use for a surface that is not the size of the screen.

Todd

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.