Skip to main content
gamedev.net
🔒 Locked

Batching sprites

Started by DarkZoulz Aug 1, 2006 at 2:58 PM 19 replies 3k views
Original Post
DarkZoulz
DarkZoulz
As i'm having alot of trouble sorting sprites by z order with ID3DXSprite. I'm going to write my own solution. I figure it's for the best, as I want to use effects that can affect seperate sprites too. As ID3DXSprite batches all the sprites together and then renders them, I guess you can't apply effects to single sprites. On the subject of batching. I would very much like my implementation of sprites to do the same as it's a speed boost. The way i'm thinking is you rebuild a vertex buffer each frame with the sprites that you want to batch, using a dynamic buffer. Is this a good idea or is there any better way (How is the ID3DXSprite class built?).
DXnut
DXnut
Although the internals of what the DX interfaces do is a mystery, you can kinda guess at it. A sprite is an interface that automates the creation of 2D rectangles that a texture is mapped onto. So, it creates the two triangles that make up that rectangle, gives each vertex the UV texture coords for the texture mapping, handles the application of a matrix to the sprite for various transformations including billboarding, and batches the rendering of them.

You can always do these things manually yourself for a situation where you want a different render state.

I don't see where it says it does the z-ordering of them for you. You may have to sort them yourself and do the ::Draw command in the sorted order.

However, sorting is not mandatory, since the depth tests done near the end of the pipeline will just replace pixels for the ones that are in front of the others. But it would make it a little more efficient.

--------------------------Most of what I know came from Frank D. Luna's DirectX books
DarkZoulz
DarkZoulz
The ID3DXSprite interface does seem to supply sorting, as you can specify the flags SORT_DEPTH_FRONTTOBACK and SORT_DEPTH_BACKTOFRONT. You can even sort after texture with SORT_TEXTURE flag.

But setting the z component of the translation matrix I use to translate the sprite, to anything else than 0 results in the sprite just disappearing. I have a z-buffer and has enabled it through the ZENABLE renderstate.

I can just sort my std::vector of sprites according to my own "z-order", but i'd rather use the actual z-buffer for sorting.
nagromo
nagromo
I'm pretty sure just using the z-buffer for sorting gives bad results when you're using alpha blending. If you draw the sprites in front first, they will fill in the z-buffer and the stuff behind them won't be shown.

The results of alpha blending are different depending on the order in which they're drawn, so manually sorting on the CPU is important if you're using partial transparency.
DXnut
DXnut
Good point nagromo! I forgot to mention that if you use alpha blending with sprites (or any thing else), you want to draw stuff that does not use it (is rendered totally solid) first, and then sort the other stuff (far to near, or back to front if you prefer) first so each thing gets blended with what is behind it as you draw 'em.

**EDIT***

It just occurred to me that if you were render an opaque tree, turn on alpha blending, and draw a ghost sprite behind it, would it still blend the ghost with the tree? You would want it to if the ghost were in front of the tree. Does DX know to only alpha blend things with the things behind it?
--------------------------Most of what I know came from Frank D. Luna's DirectX books
DarkZoulz
DarkZoulz
But if I can control at which z-depth a sprite is rendered, I can sort sprites so that they are rendered correctly. A sprite on z value 0.0 will be rendered infront of a sprite at 0.1 for instance.

Anyway, the thing I was wondering about mostly is how batching sprites would work.
DXnut
DXnut
If your camera is stationary out on the -z axis pointing at the origin, then sorting them by their world z position makes sense. Otherwise you will need to do a distance to camera test:

D3DXVECTOR3 CamToSprite = SpritePos - CameraPos;

float dist = D3DXVec3Length(&CamToSprite);

For batching, it is hard to say, since you must draw each sprite with its associated texture. Normally you would do:

For each sprite
SetTexture();
Draw sprite();
End

I doubt they do more than this internally, though there are ways you could do it with shaders.
--------------------------Most of what I know came from Frank D. Luna's DirectX books
DarkZoulz
DarkZoulz
I'm not using any camera. My view transform is set to a identity matrix. I won't have any use for it as i'm doing everything in a orthogonal projection.

I think they are doing some kind of batching internally. Making a drawprimitive call per sprite (just sending 4 vertices) would be quite slow, or? Isn't it better to "add" all the sprites to one vertexbuffer and just draw that?
DXnut
DXnut
Quote:
Original post by DarkZoulz
I'm not using any camera. My view transform is set to a identity matrix. I won't have any use for it as i'm doing everything in a orthogonal projection.

I think they are doing some kind of batching internally. Making a drawprimitive call per sprite (just sending 4 vertices) would be quite slow, or? Isn't it better to "add" all the sprites to one vertexbuffer and just draw that?


Yes, but you would have to do something so that each quad's vertex knows what texture to sample during the tesselation stage. You could add a float to the vertex declaration that would serve as an index to a texture. Then you put an array of textures into your shader. You would just pass that index from the vertex shader to the pixel shader. In the pixels shader you would do the tex2D() instruction on the texture array based on the index for each pixel.

So, your batch would be limited by the number of textures (samplers) that the hardware supports. This is going to be dependent on the PS version, and the size of the textures, which will make the batch size graphics card dependent. I cannot see DX doing all the tests for this inside the sprite interface. Also, it has no idea if you are using the fixed function pipeline or shaders.

If anyone knows differently, please jump in!

**EDIT**

It just occurred to me that they could store all the vertices for all sprites in one vertex buffer and bump through it doing a SetTexture and DrawPrimitive() call for each one. That way they only do the other stuff (like SetStreamSource() and SetFVF() only once per frame).
--------------------------Most of what I know came from Frank D. Luna's DirectX books
DarkZoulz
DarkZoulz
It think they are making a vertexbuffer for each texture used, so when it's rendered it would make a drawprimitive call for each texture used. It think this is to preserve compability with the fixed-function pipeline.

I want my sprite solution to be compatible with the fixed-function pipeline too. But if supported I want to be able to use pixelshaders for seperate sprites. That is actually why i'm considering rolling my own sprite implementation in the first place.
DXnut
DXnut
It doesn't need a separate buffer to render each one with the FF pipeline. You can put them all in one buffer and use DrawPrimitive to draw one at a time.

But, you might want to put the books down for a while, turn the computer off, and work on you social skills. Your rating is below 1000, so obviously others have rated you negatively. I am not going to rate you at all. But I see no appreciation at all from you for my attempts to help you understand the concepts. I also see no attempt by you to even try to understand the concepts I have tried to explain to you. No one is going to want to work with someone who is unappreciative, rude, and/or a bonehead, regardless of how smart you think you are. Food for thought.
--------------------------Most of what I know came from Frank D. Luna's DirectX books
DarkZoulz
DarkZoulz
Quote:
Original post by DXnut
It doesn't need a separate buffer to render each one with the FF pipeline. You can put them all in one buffer and use DrawPrimitive to draw one at a time.

But, you might want to put the books down for a while, turn the computer off, and work on you social skills. Your rating is below 1000, so obviously others have rated you negatively. I am not going to rate you at all. But I see no appreciation at all from you for my attempts to help you understand the concepts. I also see no attempt by you to even try to understand the concepts I have tried to explain to you. No one is going to want to work with someone who is unappreciative, rude, and/or a bonehead, regardless of how smart you think you are. Food for thought.


Are you actually judging me by my gamedev.net rating??? And your calling me rude? Look, I appreciate any help I can get, and I don't know where you got the notion of me trying to be rude or unappreciative? If I somehow seem to be giving of that signal, I apologize.

Dispite the fact that I appreciate any answers I get, the fact is that you have not even tried to answer my question at hand. Instead of talking about sprite batching you started talking about sorting (which was metioned as a side note).

EDIT:
I just checked my personal rating and I have been rated 5 times, all positive. Why I have a rating below 1000, I don't know.
DXnut
DXnut
No, you were not "rude" to me. But in a real work environment where you are dealing with people face to face, you ask someone for help, they don't give the and they don't give you the exact answer you want, it would be rude to just walk away without at least saying "thanks". I always made a point of at least thanking a person when I interupted them at their desk to ask them a question, even if all they said was "I don't know". I was extrapolating how I see your interaction here to a work environment, which will also include emails and phone calls.

If you show no appreciation, you will soon find that people lose interest in wanting to help you and will just start shrugging you off with "I don't know".

I see no one else jumping in this thread. Maybe people on this site are already doing that?
--------------------------Most of what I know came from Frank D. Luna's DirectX books
DarkZoulz
DarkZoulz
Quote:
Original post by DXnut
No, you were not "rude" to me. But in a real work environment where you are dealing with people face to face, you ask someone for help, they don't give the and they don't give you the exact answer you want, it would be rude to just walk away without at least saying "thanks". I always made a point of at least thanking a person when I interupted them at their desk to ask them a question, even if all they said was "I don't know". I was extrapolating how I see your interaction here to a work environment, which will also include emails and phone calls.

If you show no appreciation, you will soon find that people lose interest in wanting to help you and will just start shrugging you off with "I don't know".

I see no one else jumping in this thread. Maybe people on this site are already doing that?


Well, first of all. This isn't a "real" work enviroment, it's a forum on the internet. There is no pressure on anyone to answer my questions. People do it if they feel they have time and out of the goodness of their hearts.

I am grateful for any reply I get to my questions, even if they don't answer the question at hand. I'm not sure what you want from me? Should I say 'thanks' in every reply I make? I tend to extend thanks at the end of a converstion, and I didn't know we where at the end of the conversation as I thought we where in the midst of discussing?

You are the one calling me rude and bonehead etc, and i'm the one with bad social skills?
DXnut
DXnut
I never called you any of those things. When I said

Quote:
No one is going to want to work with someone who is unappreciative, rude, and/or a bonehead, regardless of how smart you think you are.


I was making a general observation about how people will want to stop helping someone when over time they get the feeling that their help is not appreciated or the person shows no signs of understanding what they are telling them.

I see now that you have given me a 0 rating. So obviously, that has happened to me, and I now regret trying to help you understand sprites, and how DX may handle them given the tools available. You apparently didn't understand any of it?

It won't happen again.
--------------------------Most of what I know came from Frank D. Luna's DirectX books
Servant of the Lord
Servant of the Lord
Quote:
Original post by DarkZoulz
EDIT:
I just checked my personal rating and I have been rated 5 times, all positive. Why I have a rating below 1000, I don't know.


Just a note: It doesn't show people who rated you down. This is to block morons form stupidly retalieating and rating down those who rate them down.

That being said A) You should try and thank someone for help every other post or so. And B) That person shouldn't really care whether he's thanked or not and should just be helping people for the sake of being helpful and not for thanks or ratings.
DarkZoulz
DarkZoulz
Quote:
Original post by DXnut
I never called you any of those things. When I said

Quote:
No one is going to want to work with someone who is unappreciative, rude, and/or a bonehead, regardless of how smart you think you are.


I was making a general observation about how people will want to stop helping someone when over time they get the feeling that their help is not appreciated or the person shows no signs of understanding what they are telling them.

I see now that you have given me a 0 rating. So obviously, that has happened to me, and I now regret trying to help you understand sprites, and how DX may handle them given the tools available. You apparently didn't understand any of it?

It won't happen again.


You can say whatever you want, you implied that i'm being rude and a bonehead. I'm not stupid.

Look, i'm not going to argue anymore with you because it's a waste of time. I'm just going to say: I asked a question, and you started talking about something else and suddenly out of the blue told me I have bad social skills. I rated you negative because of this unprovoked attack, which in my book is regarded as disrespectful. If you didn't like me, then just rate me negative and move on.

All I can say is, I never intended to be unappreciative or rude. I'm sorry if you somehow thought so anyway.
Aardvajk
Aardvajk
There is an excellent article on GameDev here about sprite batching although you do need all the images on one texture in order to batch them together.

I was under the impression (perhaps wrongly) that ID3DXSprite sorted all the sprites by texture, then batched together each set of sprites that used the same texture to reduce the DrawPrimitive or DrawIndexedPrimitive calls but I'm not sure about that.
Evil Steve
Evil Steve
Quote:
Original post by EasilyConfused
I was under the impression (perhaps wrongly) that ID3DXSprite sorted all the sprites by texture, then batched together each set of sprites that used the same texture to reduce the DrawPrimitive or DrawIndexedPrimitive calls but I'm not sure about that.
You can get ID3DXSprite to sort by texture, it's optional. If you sort by depth and texture, it'll sort by depth first (For alpha blending I assume).
DarkZoulz
DarkZoulz
Yup, I know. I had problems getting the sorting to work with ID3DXSprite though, but I noticed I was clearing the z-buffer to 0.0f instead of 1.0f. *dooh* I have rolled my own sprite system now and batching is working. I just need to fix so that I can transform the sprites CPU side now.

Thanks for the article, EasilyConfused and everyone for their help.

Topic Locked

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

Sign in to reply to this topic.