Some 2D Questions

Started by
5 comments, last by Sean_Seanston 15 years, 2 months ago
Just some questions about developing 2D games with Direct3D: 1. I've heard about dynamic vertex buffers and how they're supposed to be better than static buffers for things such as drawing many sprites that change often as you would in a 2D game. So I've read up about them and think I pretty much understand the idea but I'd like to make sure. I read this old-ish topic here: http://www.gamedev.net/community/forums/topic.asp?topic_id=517407 So, am I right in thinking what that basically means is... To use this kind of method for creating a 2D game you'd create 1 dynamic vertex buffer, possibly in some sort of graphics related class, and a dynamic index buffer and just use those 2 for storing the vertices/indices of every quad you're using before rendering? So that everything that's rendered just goes through that 1 dynamic vertex buffer. 2. I struggled for a while trying to find a way to blit a certain part of a texture to the screen on a quad so I could do animation with sprite sheets but in the end I managed to get it working. At least it gives the right result, but what I'm wondering is; have I done it right? Just want to make sure I didn't do something that's considered very bad or will have a huge effect on performance or anything. I have an init() function that initializes a Sprite by loaded its texture etc. and into that function I take a RECT*. The RECT contains the dimensions of the box to be eventually rendered. The Sprite object has its own RECT for the area to be displayed and the values of the one passed in are copied into that one. In here I have this:
Engine::TLVERTEX* vertices = NULL;
	Engine::instance()->vertexBuffer->Lock( 0, 4 * sizeof( Engine::TLVERTEX ), ( void** )&vertices, 0 );

	//Setup vertices
	vertices[0].colour = 0xffffffff;
	vertices[0].x = 0.0f;
	vertices[0].y = 0.0f;
	vertices[0].z = 1.0f;
	vertices[0].u = texLeft;
	vertices[0].v = texTop;

	vertices[1].colour = 0xffffffff;
	vertices[1].x = 1.0f;
	vertices[1].y = 0.0f;
	vertices[1].z = 1.0f;
	vertices[1].u = texRight;
	vertices[1].v = texTop;

	vertices[2].colour = 0xffffffff;
	vertices[2].x = 1.0f;
	vertices[2].y = -1.0f;
	vertices[2].z = 1.0f;
	vertices[2].u = texRight;
	vertices[2].v = texBottom;

	vertices[3].colour = 0xffffffff;
	vertices[3].x = 0.0f;
	vertices[3].y = -1.0f;
	vertices[3].z = 1.0f;
	vertices[3].u = texLeft;
	vertices[3].v = texBottom;

	Engine::instance()->vertexBuffer->Unlock();
Where the variables texLeft etc have been set to the position of the left side of the rectangle divided by the width of the texture (to get the position right on the actual image we're drawing obviously). Then the draw() function draws it and uses the dimensions of the RECT to do various things to make it appear in the right place etc but nothing really relevant here. Is that alright? I know that not using Lock() every frame is a good thing and I saw somebody else suggest a similar method on another side but I just want to make sure ^_^
Advertisement
The theory sounds about right. It's worth checking out the available lock flags to enable certain driver optimisations, of particular note to you is D3DLOCK_DISCARD since you've no need to read back from the buffer and you're writing to whole of the locked region.
You really want a buffer larger than 4 verts, or you'll be drawing sprites one by one. You want a buffer large enough to hold hundreds or thousands of sprites at once.

You want to avoid locks and draws. Basically you want to

lock,
copy in as many sprites as you can,
unlock,
draw,
repeat.

The "as many sprites as you can" can be a limit from various reasons. You're out of vertex buffer space. You need to render with a different texture, effect, blending mode, etc, for the next sprite.

If you're doing this for a learning exercise, great. If you're doing this to keep an consistent API for cross platform 2D work, great. If you're doing this because you think you need to, you don't. Create an ID3DXSprite object, and have it batch render everything for you.
Quote:Original post by Namethatnobodyelsetook
You really want a buffer larger than 4 verts, or you'll be drawing sprites one by one. You want a buffer large enough to hold hundreds or thousands of sprites at once.


Ya, Evil Steve mentioned around 65,000 in the other topic. In fact, it looks kinda like now I should redo my code for drawing a source rectangle of a texture but that's another matter...

Just a few more things though. I've been following this article here:http://www.gamedev.net/reference/articles/article1972.asp

And reading the part about batching just now made me unclear about some things.

If I'm making a 2D game with this dynamic buffer system, do I need any other vertex buffer at all? It's just that he has another vertex buffer in his batching code... he doesn't seem to actually use it though. Meh.

Is the dynamic buffer just good for drawing the same texture or parts of the same texture or can I use it to store different textures and still only call DrawIndexedPrimitive() once?

He says Furthermore, when drawing multiple quads from the same texture, it is possible to put them all in one large vertex buffer and draw them all in a single call. so that threw me.
Bump.
- Put all your vertices in to one big buffer all in one go (even ones using different textures)
- Unlock the vertex buffer
- The Draw() functions allow you to specify a range within the entire vertex buffer you just created - so you can Draw(), SetTexture(), Draw(), SetTexture(), on the same vertex buffer without locking or unlocking the vertex buffer. Obviously it's best if you can keep sprites of the same texture contiguous in the drawing, to reduce your settexture and draw calls.
Construct (Free open-source game creator)
Ok I've set it up so I can use batching and only lock/unlock once per frame, but what I'm wondering is: where would rotating fit into this?

Obviously each quad needs to be able to rotate independently so is it a case of applying the rotation before I add a quad to the vertex buffer and then using a separate draw() call for each sprite that might need to be rotated?

Messing around here and doing stuff but coming into some problems... if I knew what I should be heading toward that'd help :D

This topic is closed to new replies.

Advertisement