D3D depth-sorting help for 2D game

Started by
7 comments, last by Dookie 17 years, 11 months ago
Hey guys! I'm playing around with the z buffer to help with sorting sprite draw priorities. My sprites are alpha-blended quads that are all stored in one vertex buffer, which has an associated index buffer. It works pretty well, but the sprites are drawn based on the vertex number sequence (vertices 0-5 are drawn before verts 6-11, so the second quad is drawn on top of the first). So I asked myself, "How do I sort sprites dynamically?" My first 'sort' idea used a sort algorithm and lots of memcpy calls on every gameloop iteration... so it's pretty easy to see why this method stinks. I researched using the z-buffer for sorting my quads, so hopefully all I'd have to do is adjust the 'z' value for the vertices that make up my quad to get them to draw in the order my game requires. However, when I started using the z-buffer, I ran into 'draw-order dependency' issues (alpha would cut out EVERYTHING behind the quad, including background scenery, instead of just the unwanted parts of the texture for the quad itself). When using a z-buffer for alpha-blended primitives, I've seen mention of a 'depth sorting' idea but I can't find any code that demonstrates how it's done (or even if it would work for my application). So right now, I don't have any viable depth sorting solution for my game :( Here's some code, if it helps:
struct CUSTOMVERTEX
{
	FLOAT	x, y, z, rhw;
	DWORD	color;
	float	tu, tv;
};
...
...
...
void DrawSprites()
{
	UINT vNum = MAX_SPRITES * 6;
	UINT iNum = vNum / 3;

	// Set up the texture...
	d3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
	d3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
	d3dDevice->SetTexture( 0, SP_Group.g_QuadsTB.Texture );

	// Now draw the primitives from the SP_Group struct
	d3dDevice->SetStreamSource( 0, SP_Group.g_QuadsVB, 0, sizeof(CUSTOMVERTEX) );
	d3dDevice->SetIndices(SP_Group.g_QuadsIB);

	d3dDevice->DrawIndexedPrimitive (D3DPT_TRIANGLELIST,
			0,
			0,
			vNum,
			0,
			iNum);
}
Would any of you help me figure out depth sorting so I can get my alpha-blended quads to draw in an order based on each quad's 'z' value? Thanks in advance for the help!
"The crows seemed to be calling his name, thought Caw"
Advertisement
I think you have to issue one draw call for each sprite, in the correct back-to-front order (maybe sorting the quads in the vertexbuffer according to depth would work too, I'm not sure).
Quote:Original post by Dookie
Would any of you help me figure out depth sorting so I can get my alpha-blended quads to draw in an order based on each quad's 'z' value?

You can't, anything other than additive blending requires the sprites to be drawn in the correct order (ie. be in the correct sequence in your vertex buffer). Only opaque, alpha-tested or additivly blended sprites can be drawn in any order.
Thanks for the replies, guys!

OrangyTang, you mentioned 'alpha-tested' objects... What are those? I'm wondering if that would work for me, since all I'm doing is using the alpha to cut out the background (simple cutouts, I'm not using it for varying degrees of transparency).
"The crows seemed to be calling his name, thought Caw"
Alpha testing is where you set a threshold (usually 0.5) and fragments with an alpha above that are drawn, and below are rejected. You usually see it used for trees and wire mesh fences. Because you're not actually doing any transparency the object is still basically opaque so depth testing works as normal.

You could use it for sprites, but you wouldn't be able to get nice anti-aliased edges that you could with proper blending.
Thanks for the info, OrangyTang. I might play around with alpha testing and see if it'll work with my game. If it looks too bad (no smooth edges, etc) then I'll probably have to play around with more sort order routine ideas...

About sort order routines (figuring out what gets drawn in front of what, then render in that order), would you point me in the direction of some code examples I could look at that demonstrate sort ordering? Ideally, I'd like to figure out how to perform efficient sort ordering so I can get my game objects to render properly when alpha blending is enabled.
"The crows seemed to be calling his name, thought Caw"
I use a SortedDictionary for z sorting alpha-blended sprites. Problem is it doesn't allow to identical keys, so I work around that by offsetting the z slightly (overriding the Add method).

(I've been meaning to write a SortedDictionary class that doesn't have this restriction, but my current solution works with no significant performance hit, so I'll save that for one seriously rainy day)
Thanks for the info, Jonas B. I'll do a search on 'SortedDictionary' and see what I find, it sounds very useful!

Here's my last question on this (hopefully)... I'm testing the 'D3DRS_ALPHATESTENABLE' idea and am having a little luck with it. Look at the above 'DrawSprites()' function. If I use 'D3DBLEND_ONE' / 'D3DBLEND_ZERO', then the sprites display perfectly (background is cut out, and the sprite displays fine without any z-buffer anomalies). But here's my problem (it's probably a silly-simple solution): My particle rendering function is identical to the 'DrawSprites()' function, except I'm using additive blending ('D3DBLEND_ONE' / 'D3DBLEND_ONE'). However, the texture isn't additively blended; rather, it's staying opaque as the color fade is performed until I end up with black-colored particle sprites before they finally get destroyed. Is there a way I can get additive blending to work with a nice fade-to-transparent with 'D3DBLEND_ONE' / 'D3DBLEND_ONE'? I think it has something to do with 'D3DTSS_COLOROP / D3DTSS_COLORARG1 / D3DTSS_COLORARG2', but I don't know what combination of those arguments to use to get the desired result.

Thanks again!
"The crows seemed to be calling his name, thought Caw"
Nevermind, I think I got it all figured out. I simply did this:

d3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
d3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );

and got my 'particle' transparencies back (when using blending method 'D3DBLEND_ONE / D3DBLEND_ONE'). Since all of the particles will be drawn over all of the game objects all of the time, and the particles' 'z' value will always be closest to the viewer than anything else on the screen, I shouldn't get any priority problems (knocks on wood). Everything else uses blend method 'D3DBLEND_ONE / D3DBLEND_ZERO', so z-sorting works terrific for them. And my game's performance has gone up a bit from my old method of sort ordering, from 325fps to 330fps on my P4-1.8GHz Win2K system with Radeon 9600 vid card. Coolness!

Thanks again for all the help, you guys ROCK!
"The crows seemed to be calling his name, thought Caw"

This topic is closed to new replies.

Advertisement