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

ID3DXSPRITE Sorting Textures

Started by GodFear Jun 18, 2013 at 2:32 PM 2 replies 1.9k views
Original Post
GodFear
GodFear

Hi Fellow creators!

I've been using ID3DXSPRITE class on my 2D engine and have been happy with its performance. However i come to a point where i want to take it to the next level and implement a sprite class that will allow me with more controls on 2D rendering. Therefore i replace it with using custom vertex quads.

It has a Begin() function that initializes render states and projections, End() function that pushes the batched vertices into the locked d3d vertices and performing a single draw primitive call to draw all the quads at once. I also have a Flush() function to force rendering of currently batched quads.

On tests it performs well compared to ID3DXSPRITE by about 10% in frame rate when rendering 100 to 1000 sprites while using a single texture.

However when i try toggling texture on every draw call, my frame rate significantly dropped. This is expected as my sprite class is not smart enough to handle change in textures. Whenever a texture is changed, it immediately Flush() the currently batched sprites and starts batching the succeeding ones until a change in texture occurs or End()/Flush() is called.

I believe ID3DXSPRITE has a mechanism to batch sprites using the same textures (D3DXSPRITE__SORT_TEXTURE??).

Now my question is what's a good way to batch sprite quads in terms of textures?

belfegor
belfegor

I am using similar thing for my gui system so i am interested in this too.

Although i don't have much 2D elements yet i squeeze them in one texture atlas but have problem when i need to wrap around because of texture filtering, perhaps i should move sampling coords a bit "inside". For fonts i must switch texture so that means draw call for each.

I have some other idea but i have not tried yet, since i use shaders i can set volume textures and store slice index in VB maybe?

Any restrictions with volume textures that could be problem? I can't find any information googling.

GodFear
GodFear

I guess what i can do is add a list of my custom vertex array in my sprite manager.

Each array mapped (like a hash table) by corresponding texture it's assigned to be rendered to. So every time a Draw() is called, the passed texture is added into the list if it's not in the list yet, and the given quad information on the Draw() call is added into the custom vertex array associated with the texture.

So in the End() function, i'll loop through my list and set texture and push its corresponding vertex array into single draw primitive call. Basically do this on all texture/custom vertex arrays in my list. rinse and repeat.

As for sequence, i can use depth buffer to sort it out. Since in orthogonal projection, the near/far Z plane can be any value, i can just set far Z value as my initial quad count and near Z value to my last quad count.

That sums it up pretty much i guess. Unfortunately i don't have the motivation right now to implement it as i realized i don't really need it. I can just go ahead via old school way of batching my sprites based on texture when rendering.

But yeah, this is really a good point on GUI's.

GodFear
GodFear

Well i eventually implement texture batching features in my index/vertex based custom sprite class. Now if i flip textures my frame rate does not suffer a lot and it's a lot faster now than id3dxsprite so i am very happy with it. I just have to use depth buffer to properly follow the draw sequence. The good thing is that when setting projection matrix, there seem to be no limit to near and far Z plane so i can just set a start value and increment/decrement from there as i perform sprite draw calls.

So here's a pseudo code on how i implement it. There are 3 functions, Begin(), Draw(), End().

Also note that i created a sprite batch list that works like a hash table and texture is its key.

Begin() - just like id3dxsprite, i call this before i do any sprite draws.

- initialize render states

- reset draw counter. i increment this value as i call Draw()

- clear sprite batch list

Daw() - draw a sprite. it does not really draw the sprite immediately. Instead it queues it up in the sprite batch list to be drawn later on End() call

- check if passed texture is already in sprite batch list. If it is, add this sprite quad into the list with this texture. if passed texture is new, create a new batch in this list with this texture as its key.

- use the draw counter as z value of the quad

- increment draw counter

End() - sort through sprite batch list and draw them

- set projection transform. set near and far z plane as start value of draw counter and current value of draw counter

- loop through each sprite batch in the list and push them into our vertex buffer. then perform draw primitive call. the z values will set which sprite is in front or back

If anyone's implemented their own sprite class and is somehow different from this i appreciate if you can compare. I'll be glad to know a better way to implement it.

Topic Locked

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

Sign in to reply to this topic.