Jump to content
  • Advertisement
Sign in to follow this  
Aardvajk

These vertex buffer things

This topic is 4397 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So I'm trying to put a naive implementation of a 2D sprite-based library for Direct3D 8 together and am starting to get my head round vertex buffers. I am happy to lock buffers and manipulate them in code at the moment, although I understand it is more efficient to move objects round with matricies, and that locking and unlocking the buffers is expensive. Would I be better off having a seperate vertex buffer for each sprite so I only have to lock it to alter the alpha or colours, and call SetStreamSource before each drawing operation, or is this not a good way to approach it? The alternative I suppose would to just have one four-point vertex buffer that is used to draw any quad and locked and altered before each draw operation. Bit new to all this, as you can probably tell. Also, while I am here, I was wondering about texture co-ordinates. If I had, say, a 500x500 image sat on a 512x512 texture and I just wanted to use the 500x500 bit, the u value would have to be (I think) 500/512, which is, according to by desk calculator, 0.9765625... etc. What level of floating point precision do you need to specify texture co-ords to and how much does floating point inaccuracy become a problem? Appreciate I could just test this to find out but am at work at the moment just mulling it over in my mind. Ta.

Share this post


Link to post
Share on other sites
Advertisement
For sprites you WANT to rebuild your vertex buffer. Using matrices would require a seperate draw call per sprite, which has a ton of overhead. Instead, use a dynamic vertex buffer and rebuild your vertex data each frame. You can also use ID3DXSprite to take care of all the details about this for you.

I wouldn't worry about floating point accuracy for UVs. A regular float has 23 or 24 bits of precision, so unless your texture sizes are approaching 16 million by 16 million, you won't have trouble.

Share this post


Link to post
Share on other sites
I see (sort of). Thanks. Could I just get a bit of clarification on what you mean about the seperate draw calls though?

At the moment I just have one four-point vertex buffer. For each sprite I unlock the buffer, set it to the co-ords for the sprite in question, lock it, call DrawPrimitive then return and deal with the next sprite in the same way.

Do I have the wrong end of the stick from an efficiency point of view? Surely that is a seperate draw call per sprite as well?

And cheers for the reassurance about texture co-ords. I will try to steer clear of 16million by 16million textures [smile].

[EDIT] Oh, and I'm aware of DXDSprite but I'm just trying to learn a bit about verticies and stuff at the moment so am trying to implement it myself as a learning exercise.

Share this post


Link to post
Share on other sites
each individual draw call is quite expensive. Especially when they start to pile up.

You can draw more than one sprite at a time by using a bigger buffer, and drawing more than one sprite in a single call. You'd need to have the use the same texture, but that usually isn't much of a problem.

You then lock the buffer (which can hold, say, 100 sprites), fill all 100 into it in one go. Then unlock it, and draw 100 in one draw call.

This would provide much much better performance than calling Draw for each sprite.

Hope this helps.

Share this post


Link to post
Share on other sites
Yes, your current implementation is bad from a performance point of view. See this paper, from here. Notice how when triangles per batch is at 10, you're maximum triangles per second is really low.

Basically, you want to give the GPU as much to do at once as possible, because there is a huge CPU overhead on each draw call. When drawing a single sprite at a time, you're completely limited by the CPU overhead. The GPU is pretty much perpetually idle, waiting for the next thing to do.

When you need to switch textures, blending modes, etc, you'll need a seperate draw call, but when you *can* draw multiple sprites in a single call, you should. You're aiming to limit yourself to doing a maximum of 300-500 draw calls per frame. Lets say you're using 32x32 tiles, and rendering a 800x600 display. Just drawing your map tiles you'd be performing over 400 locks, and draw calls. Instead, assuming all your map tiles are on one or two textures, you can do this as one or two draw calls. Just lock, build all the vertices for the map, unlock and draw.

Share this post


Link to post
Share on other sites
Ah. Thanks for all the info.

So if I had a big texture with all my sprites etc tiled onto it, I could create a big vertex buffer (I believe I'd have to use a triangle list rather than a triangle fan as I have at the moment), lock it, set all the x and y's by the various sprite's positions, set the u and v's by the sprite's "frame", set all the alpha and vertex colours, lock the buffer again then just do one DrawPrimitive call?

Sorry for being lazy, and tell me to push off and read the docs if you want, but would the Z ordering of sprites work the same way as if I was DrawPrimitive-ing individually (first drawn, furthest away) or would I have to give the verticies z values to maintain the correct order?

I tell you what though, I feel like I'm really starting to get my head round these (very basic) concepts now. God bless the internet and all you helpful people.

Paul

[EDIT] Blimey - I'm going to need a vertex index buffer as well, aren't I? Just gets worse and worse.

Share this post


Link to post
Share on other sites
Yup. A triangle list would be the way to go, and yes, an indexed triangle list would be preferred. The triangle order should behave as though they were drawn one after another if you don't want to include Z values. If you have many tiles, requiring several textures, it can be advantageous to use Z values since you can draw all the tiles of one texture at once, instead of having to swap back and forth between textures causing you to do more draw calls.

Also, if your sprites don't need blending, just an on/off alpha, you can use alphatest. When a pixel fails the alphatest, it isn't drawn to the back buffer or depth buffer. For example, if alpharef was 255, and alphafunc was D3DCMP_EQUAL, any pixel with an alpha != 255 would not draw, leaving the previous pixel there. Using this along with actual Z values can allow you to draw arbitrary shaped sprites in any order to get optimal batching (ie: one batch per texture). When you start doing "real alpha blending", you'll be forced into making sure everything is drawn in a specific order.

Also, ensure you're using a DYNAMIC vertex buffer and index buffer. These are meant for this type of use.

Share this post


Link to post
Share on other sites
So can anyone point be at a good explanation of index buffers then? I've been looking at the DirectX Graphics tutorials in the Resources section and I must admit I am a bit confused. I am loathe to start using code I don't understand.

I understand (I think) the principle that two triangles in a list making up a quad have two common verticies and I sort of understand that the vertex index would express this somehow but I'm still struggling with this a bit.

[EDIT] Oh, no, I get it now. Sorry.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!