Another Z-sorting question (for a 2D game)

Started by
5 comments, last by Dookie 17 years, 11 months ago
Hey guys, I gotta question for you... I'm working on a 2D quad rendering engine using Direct3D, and it uses a few indexed vertex buffers each containing enough vertices to define 128 or more quads each (one IB for particles, one for 'sprite' quads, one for 'bullet' quads). I'm trying to figure out how to sort the drawing order of my quads so they will render one-in-front-of-the-other based on its z-value. Currently, the quad rendering order is based on how the vertices are numbered within each vertex buffer (quad 2 is drawn on top of quad 1 because verts 0, 1, 2, 3 are rendered before verts 4, 5, 6, 7). Drawing order also depends on which vertex/index buffer is rendered first ('bullets' draw over 'sprites', because the 'sprite' buffer is rendered first). Z sorting is not enabled; 'D3DRS_ZENABLE' and 'EnableAutoDepthStencil' are not used. So if I want a quad to specifically draw on top of another quad, I have to make sure it's using vertices that are numbered greater than the quad of which I want to draw over. What a pain! What I want to do is simply type in a larger value for 'z' and then Direct3D will do the render sorting for me. My customvertex definition uses 'D3DFVF_XYZRHW', so there's a 'z' value for my vertex buffers. However, when I use these: d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; ... d3dDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE ); I see what looks like the 'z' values are all competing for priority (a very interlaced-looking scene, with objects trying to render on top of others without quite succeeding). It doesn't matter what value I use for 'z' - It looks like all of the 'z' values for all of the quads are identical, so the game doesn't know how to sort the quads in order to render them correctly. It looks awful! Is there anything else I need to do? My renderer is pretty simple, with no camera or matrices or anything. Simple 2D quads, rendered from a few indexed vertex buffers. My customvertex definition is as follows: D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1) Let me know if there's any more code you need to see to help me solve this z-sorting problem, and I'll post it. Thanks in advance for the help!
"The crows seemed to be calling his name, thought Caw"
Advertisement
What values of Z are you using? They should be in the range 0.0 (close to screen) and 1.0 (far away). I've never had any problems with this trick - its done exactly what you want to happen for me [smile]

Are you clearing the depth buffer each frame? Changing any other render states (ZFUNC, ZWRITEENABLE...?)

For XYZRHW vertices you should have RHW=1 to get a correct output.

Can't think of any other reasons off the top of my head..

Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

Thanks for the quick reply, jollyjeffers. It seems that I wasn't clearing out the z-buffer on each render pass... After I added this to my renderloop:

d3dDevice->Clear( 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

the z-sorting worked. You rock!

Everything works for the most part, but there's a strange rendering artifact that I can't seem to fix. Would you help me on this too? Here's what's happening - Let's say my vertex buffers are rendered in this order: background, ships, bullets, foreground. All of the quads use an alpha channel to 'cut out' parts of the texture. Now here's the problem... If I pass a z-sorted ship over the background, then all is well. If I pass a z-sorted ship over another z-sorted ship, then all is well. But if I pass a z-sorted ship over the foreground, then the alpha channel that cuts out the ship from the rest of its texture interferes with the rendering of the 'foreground' texture (the alpha of the ship also cuts out the 'foreground' texture, so you see the 'background' texture behind the ship itself instead of the 'foreground' texture). Weird! How do I resolve that problem? BTW, here's how I'm blending my ship quads' texture:

d3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
d3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

Thanks again!
"The crows seemed to be calling his name, thought Caw"
Unfortunately, you can't rely on HW z-sorting optimizations when it comes to alpha blending. You have to render alpha-blended sprites back to front after the others.
Good to hear you solved your first problem [smile]

Quote:Original post by Jonas B
Unfortunately, you can't rely on HW z-sorting optimizations when it comes to alpha blending. You have to render alpha-blended sprites back to front after the others.
Yup, this is the case - commonly referred to as being "draw order dependant"

There isn't really an API feature for solving this - you have to manually sort your alpha-blended sprites from back-to-front. Typically you'd render your opaque geometry first (no need to sort this) and then render the semi-transparent stuff afterwards. You can often cheat a bit by turning off D3DRS_ZWRITEENABLE and/or D3DRS_ZTESTENABLE - technically it can generate incorrect results, but its usually hard to spot them [wink]

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

Thanks for the info guys, that's very helpful!

Alrighty, I'll play around with drawing my opaque stuff first, then drawing my alpha'd stuff last. I might play around with the 'D3DRS_ZWRITEENABLE / D3DRS_ZTESTENABLE' idea, but I'll first try to get it to render properly by working on the order of which things are drawn.

Thanks again for the help, I really appreciate it!
"The crows seemed to be calling his name, thought Caw"
Well, I'm still having troubles with that z-sorting stuff... I'm still getting the background cut out along with the alpha when drawing objects that are on a transparent background (using alpha blending). I've played around with the orders of which things are drawn, but too many game objects use alpha channels to cut out parts of the texture so I can't eliminate the problem. My current blend method is this:

d3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
d3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

and when Object_1 is drawn over Object_2 AND Object_2's 'z' value is less than Object_1, then Object_2 is drawn over Object_1, except that Object_2's alpha cuts out Object_1 (similar to the problem I've described above - draw order dependent).

Is there another blend method I can use to make parts of my texture transparent without having to worry about 'draw order dependent' situations? Or is there another way I can write my textures so I don't have to use the alpha blend method mentioned above?

Thanks!
"The crows seemed to be calling his name, thought Caw"

This topic is closed to new replies.

Advertisement