Sign in to follow this  
Deliverance

How do DoomIII/Quake4 handle transparent objects?

Recommended Posts

I was wondering how does the DoomIII engine handle transparent objects(the window glass that is). Do they use a BSP tree to sort back-front or make use of another technique? [Edited by - Deliverance on October 20, 2006 12:00:06 PM]

Share this post


Link to post
Share on other sites
I don't know about more recent versions, but I think Quake II did it that way (draw all non-transparent objects, then draw transparent ones in reverse distance order).

Share this post


Link to post
Share on other sites
Quote:
Original post by Bob Janova
(...then draw transparent ones in reverse distance order).

By reverse distance order, you mean front to back, or back to front?

Share this post


Link to post
Share on other sites
Quote:
Original post by Moe
Quote:
Original post by Bob Janova
(...then draw transparent ones in reverse distance order).

By reverse distance order, you mean front to back, or back to front?
Back to front. It's very easy to make a mess of things trying to go the other way with the depth buffer and the transparency.

Share this post


Link to post
Share on other sites
I guess you could even be a bit more specific and say:
1. Draw non-transparent geometry front to back
2. Draw transparent geometry back to front.

I have heard that you can squeeze out a bit more performance by rendering non-transparent geometry from front to back, as anything that is occluded by already rendered geometry is immediately rejected on modern hardware (or so I have heard).

Share this post


Link to post
Share on other sites
I never understood the front to back thing for non transparent. You have to watch texture changes too. It's all so contradictory. [totally] I'm pretty sure I've read an artigle by Kilgard or someone that the depth buffering would take care of it for 'free'.

Share this post


Link to post
Share on other sites
Well, the purpose of rendering non-transparent geometry from front to back is early rejection. Suppose we have two walls and a character between those walls (assuming we are facing wall 1):

------- <-Wall 1

* <- character

------- <- Wall 2

0 <- us

If we draw wall 1 first, then the character, then wall 2, (or in other words, back to front) we are really drawing 3 things over the same piece of the backbuffer. If we draw wall 2 first, then when we go to draw the character or wall 1, the video card hardware can 'sense' that there is already something rendered there, and can reject what is supposed to be drawn. Its the early rejection test that speeds things up. Rather than rendering the same pixel 3 times, we do it once.

Share this post


Link to post
Share on other sites
D3/Q4 lay down the Z buffer in the first rendering pass, so they don't have to worry about material sorting. So first you draw non-transparent things front to back with color writes disabled and without any real pixel shader. Then you your Z compare func and render your non-transparent things, sorted by material. Lastly you swing back and draw all your transparent things back to front.

Share this post


Link to post
Share on other sites
With back to front order of drawing two non-transparent polys the card has to test and modify the z buffer twice, as well as calculate the pixels colour twice.
With front to back it has to modify the z buffer values once, but test them twice, and modify the pixel colour once.

Share this post


Link to post
Share on other sites
Quote:
Original post by Promit
D3/Q4 lay down the Z buffer in the first rendering pass, so they don't have to worry about material sorting. So first you draw non-transparent things front to back with color writes disabled and without any real pixel shader. Then you your Z compare func and render your non-transparent things, sorted by material. Lastly you swing back and draw all your transparent things back to front.


I hope this thread isn't considered too old now, but I found this comment fascinating. Why would these engines take the time to go through a rendering pass just to record the Z buffer? I don't follow what this speeds up in later passes. You'd still sort materials during rendering to reduce state changes, so what effect does that have on the first pass?

Share this post


Link to post
Share on other sites
Quote:

I hope this thread isn't considered too old now, but I found this comment fascinating. Why would these engines take the time to go through a rendering pass just to record the Z buffer? I don't follow what this speeds up in later passes. You'd still sort materials during rendering to reduce state changes, so what effect does that have on the first pass?

AFAIK rendering a z-only pass helps with overdraw. Of course you will still need to sort subsequent passes by material in case to minimize state changes, but the actual number of the pixels that will be send to the pixel shader (due to early z-rejection) will be much less than if you were rendering the scene in random order (no f2b or b2f) and having the objects sorted only by material.

And if you think that z-only rendering is optimized on most cards (given that you follow the rules for that), then it seems a very nice optimization, especially if you are going to do multiple passes (which is needed when rendering stencil shadow volumes).

HellRaiZer

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
the engines do this, because it has some good advantages:

1)
early z culling:
between the vertex and the pixelshader, there is a test. before executing a big pixelshader (or this part of the ffp), a pixel can be dropped if its z-value is behind the actual z-buffer value. this helps if objects are partially visible and you have to draw them, you dont draw all the pixels that are occluded. also, occluded objects dont get drawn (implementing occlusion culling in an engine is often slower than this).

2)
material sorting:
as said, you dont have to worry about materials in a z-prepass. its damn fast to fill the z-buffer without drawing anything. and you can sort front to back (to use early z-culling even in the z-prepass) without material sorting. in the next step, you can optimally batch all your geometry by shaders and textures. this is a heavy speed-gain.
without a z-prepass, you have to decide: less overdraw (sorting front to back) or less draw calls (material sorting). with a z-prepass, you get the advantages of both.

3)
post screen effects:
when applying post screen effects like fog, the flickering caused by heat, or soft particles, you will have to render the z-buffer into a texture. in the z-prepass, you can also fill the texture with almost no extra cost.

there is only one drawback:
when you dont use (3) and you have almost no occluded objects (e.g. in a large flat terrain), you have a (more or less significant) slowdown.

Share this post


Link to post
Share on other sites
Quote:
I hope this thread isn't considered too old now, but I found this comment fascinating. Why would these engines take the time to go through a rendering pass just to record the Z buffer?

on nvidia hardware depth only pass pixels are twice as fast to draw (prolly also on ati)
thus u render a lightning fast depthpass
+ then all following passes only get written if there depth values are equal to this depthpass (thus after zpass u only fill the pixels once (plus extra for the lights with blending))

the alternative is slower eg u can write a pixel into the framebuffer eg 200instructions long (which takes a while) but its all for nothing since another closer pixel overwrites it

benchmark of course but often a zonly pass is a win
(also sorting front to back doesnt really buy u much (from my testing maybe 2% ie pissall ))

Share this post


Link to post
Share on other sites
A key point with depth-only/depth-friendly rendering which no-one has mentioned is that most modern hardware can (and usually does) store the depth buffer in a compressed format. If an area of the depth buffer is empty, or contains only a plane equation, it's much smaller than a full bitmap of depth values for the same area. This means it's quicker (less bandwidth) to fetch depth values for any pixels in this area.

The goal is therefore to preserve the depth buffer compression for as long as possible during rendering. This means trying to lay down the simplest depth values first, which means big polygons.

One rendering order I've seen recommended (and used successfully) to take advantage of this is as follows:

* Clear depth buffer to 'far' (very fast, since it's a compressed write)

* (Edit: forgot something important. Make sure you clear stencil together with depth or you probably won't get any depth compression!)

* Render opaque objects with relatively large polygons from front to back. Things like terrain and basic level geometry go here.

* Render opaque objects with relatively small polygons from front to back. Things like characters and clutter geometry go here.

* Render skybox or distant scene (to save filling all those pixels now covered by foreground)

* Render transparent objects how you like - back to front is good.

To combine this depth-friendly ordering with other performance guidelines like sort by shader, take advantage of the fact that the opaque depth sort need not be precise - stick each object into one of a dozen depth bins, then within the bins render in the state-efficient order of your choice.

You don't have to be very clever about partitioning large polygon and small polygon objects either - we just assumed anything static was large, and anything dynamic was small, and got a decent speedup using the above technique.

HTH,

Cheers,

Will

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this