2D animation in 3D

Started by
3 comments, last by blaze02 17 years, 10 months ago
Hello all, I am making a 2d pacman clone using direct3d 9. I made my own sprite class using textured quads. It works fine but now I want to add animation to my game. I've done animation in directdraw before so I have a little experience. This is more of a technical question. Right now I can think of two ways to do it. All my frames are in one bitmap so I was either going to change the texture coords each frame or make a quad for each frame. As far as I know I'll have to lock the vertex buffer to change the texture coords and that is supposed to be expensive. That will be a lot of locking, but it seems elegant - one quad and one texture as opposed to say 6 quads (for each frame) and one texture. I guess the multiple quads wouldn't be that bad, but I just want to know what others think and if there is maybe another way. Thanks for any responses. I've looked into d3dxsprite but haven't found a good tutorial. It looks like a rect can be specified for the texture when drawing which would be the equivalent to the first method of changing the text coords. I'm just wondering if it is the same as far as overhead or if the d3dxsprite is quick. [Edited by - NES4ever on July 20, 2006 8:20:23 AM]
Advertisement
It looks like the way to do it is by using the texture matrix. There is no locking involved and I only need the one quad and texture. It took a bit of research so if anyone happens upon this you can email me. Below is the code I used.

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_COLORVALUE(0.5f,0.5f,0.5f,1.0f), 1.0f, 0 );

g_pd3dDevice->BeginScene();

D3DXMATRIX Position;
D3DXMATRIX Rotation;
D3DXMATRIX Combo;

// Render geometry here...
g_pd3dDevice->SetFVF( D3DFVF_PANELVERTEX );

g_pd3dDevice->SetTexture(0, sprMap.pTexture);
g_pd3dDevice->SetTextureStageState(0,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);

// draw chomper
D3DXMatrixTranslation(&Position,sprChomper.x,sprChomper.y, 0.0f);
g_pd3dDevice->SetTransform(D3DTS_WORLD,&Position);

D3DXMATRIX ident;
D3DXMatrixIdentity(&ident);
// translates using the coords below
ident._31 = 1.0; // x coord
ident._32 = tminc; // y coord. this is just a float that increments by .5


//D3DXMatrixTranslation(&Position,0.25f,0.25f,0.0f);
g_pd3dDevice->SetTransform(D3DTS_TEXTURE0,&ident);

g_pd3dDevice->SetStreamSource(0, sprChomper.pVertices, 0, sizeof(PANELVERTEX));
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);

//reset matrix in case another prim needs to be drawn
ident._31 = 0.0;
ident._32 = 0.0;
g_pd3dDevice->SetTransform(D3DTS_TEXTURE0,&ident);

g_pd3dDevice->EndScene();

g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

}
When you're drawing so few sprites, it doesn't really matter what method you use.

I'd recommend changing the texcoords. If you make your VB dynamic it's pretty efficient. Also, I'd use Triangle Lists rather than Fans. With these changes it becomes easier to scale to much higher sprite counts and more complicated usage while still keeping things pretty simple at the beginning.

With Triangle Lists you will be able to draw more than one quad at a time, all of the ghosts for example. In fact, if you can combine all your sprites into a single texture page you'd be able to draw your whole screen in a single draw call!

D3DXSprite is very efficient. It batches up drawing calls does a lot of magic behind the scenes. If you already have your own system working though, you'll get more of a long term benefit from building and improving on that.
Stay Casual,KenDrunken Hyena
Thanks for the reply. If I have all the characters (pacman & the ghosts) in one triangle list how do I position them individually each frame? If I use a translation matrix won't it apply to all the characters? Right now each has their own VB. When rendering I set the stream source, do the translation and then draw the character. Then I move on to the next character. So five drawPrimitive calls, which isn't insane, but what if I had alot more sprites that are moving each frame? I'd like learn a more efficient method even if it is overkill for this current game. Is it possible with one triangle list to set the stream source, make five individual character translations and then one drawPrimitive call?
I think you'll need to move to indexed primitives if you want to draw the entire scene in one call. I just moved to a quad batching system that uses a dynamic vertex buffer. My vertices include a color also. It works pretty well. I can draw anything that uses the same texture in one draw call. This includes all the particles that fade transparency and change color. They can all be drawn together. Eventually we will set up a texture atlas to draw everything except our models in one DrawIndexedPrim call.

I had one good question though. Everybody says to pad your vertex up to 32 bytes for video card cache reads along 32 byte boundaries. But with my 24 byte vertex (pos:12byte; diffuse:4byte; texcoords:8byte), 25% less data needs to be sent to the video card. On the other hand, with a 24 byte vertex, half of the cache reads will cross 32byte boundaries.

So my question: Is it worth sending 25% less data across the bus if 50% of the vertices lie across 32 byte boundaries?

Or am I thinking about it wrong? If I pad my vertex, is DX smart enough to delta compress the data (not send the stuff I don't change)? It doesn't seem like it could do that.

Coding is FUN!
-------Harmotion - Free 1v1 top-down shooter!Double Jump StudiosBlog

This topic is closed to new replies.

Advertisement