3
\$\begingroup\$

I've been programming for a while, and I'm concurrently learning how to make a basic game and slimdx, and wanted to talk to someone to hopefully get a few pointers. I've read that Tetris is the "Hello, world" of game programming, which made sense to me, so I decided to give it a shot.

I've been able to code up a basic version in a few hours, which I'm quite happy with, but I had a few questions about 3D programming. Right now I'm using Direct3D to do display the blocks without any textures (just colored squares). I have a data structure (2d array of bytes, where each byte denotes the presence of a block and its color) which is the "game board," and on every render() call I create a new vertex buffer of the existing squares in the game board, and draw those primitives.

This feels very inefficient, and I wondering what would be the idiomatic way of doing this in a 3D world, with matrix/rotations/translation operations. I know 3D is overkill for such a project, but I want to learn any 3d concepts that I can while I'm doing it. I understand that what you'd usually want to do is keep the same vertices/vertex buffers but manipulate them with matrices to achieve rotations/translations, etc. To do so, I assume what would happen is I'd have one vertex buffer for the "active" piece, since that'll be constantly rotated and moved, and have one vertex buffer for the frozen pieces on the bottom of the board, which is pretty much stationary, but will need to be changed/recreated when the active piece becomes frozen.

Right now I'm just clearing and redrawing on every render call, which seems like the easiest way to do things, although I wonder if there's a more efficient way to deal with changes.

Obviously there are a lot of questions I'm asking here, but if you can even just point me a step or two ahead in terms of how I should be thinking, it'd be great. Thanks

\$\endgroup\$
1
  • 4
    \$\begingroup\$ I'd recommend starting on a 2D version of Tetris. Use something like the SDL library for graphics which makes the blitting fairly easy. If you code it well, you should then be able to replace the rendering part of the source with a 3D version at a later stage. I started with Pong, then Space Invaders :) Good luck! \$\endgroup\$
    – lochok
    Commented Feb 20, 2012 at 0:24

1 Answer 1

2
\$\begingroup\$

There are two approaches you can do to improve performance in this case:

The first one is a very simple fix to what you are doing right now. Do NOT recreate the vertex buffer of the existing pieces/cubes because there is not reason to do this.

Assuming all the pieces have the same geometry what you want is to have only one vertex buffer that describes the geometry of a given piece. Then in your Render loop you would "place" this in the world by changing the world transform. Something like this:

for (int piece = 0; i< numPieces;++i)
{
    // Setup the world, view, and projection matrices
    SetupMatrices(piece);

    // Render the vertex buffer contents
    g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
    g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
    g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 * 50 - 2 );

    // End the scene
    g_pd3dDevice->EndScene();
}

That will perform better than what you are doing and is probably good enough. The only problem is that you will be sending the same geometry (the vertices) to the GPU many times (Every time you do a DrawPrimite). This is wasteful as well so you can actually do something called "hardware instancing" where you send the list of vertices once and a list of all the transforms you want the GPU to do. Here is a nice article explaining how to do it: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter03.html

\$\endgroup\$
1
  • \$\begingroup\$ I might be totally wrong on this, but I think calling DrawPrimitive does not actually send the vertices every time - SetStreamSource does. However, DrawPrimitive does incur some other overhead, so your advice to use instancing is still sound. As far as I know, what geometry instancing buys you is to get rid of the overhead of the actual draw calls that you don't need to issue for every object and it benefits the driver/hardware because it can "plan" farther ahead when it knows what you are going to draw - which is good for batching. \$\endgroup\$
    – Koarl
    Commented Mar 22, 2012 at 9:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .