Moving to 3D rendering

I’m part of a University team working with XNA and building a 2D engine around it to support projects in a course. It’s been a lot of work, but it’s also been pretty interesting. XNA is pretty much Managed DirectX redesigned for C#. This includes garbage collection, automatic references and all of the rest of the features of C#. Along with the language move, XNA removes a ton of the annoyances of working with Manged DirectX. Having worked a little bit with MDX in the last couple of years, I definitely am liking XNA.

Over the last week I’ve been considering moving to 3D-based rendering (along with many other engine cleanup tasks). The easy method of 2D rendering in XNA is to use a SpriteBatch. Once you’ve loaded your texture (which is a single line of code), the code to render it looks like this:

spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
spriteBatch.Draw(myTexture, new Rectangle(spriteX, spriteY, 50, 50), Color.White);
spriteBatch.End();

You basically tell it what texture to render and where (even specifying tint), and it draws it. This is great, and you could probably make tons of 2D games using it. However, having dipped my feet in the world of 3D a couple semesters ago (CptS 442), I’ve seen the power of transformations, and wished to harness it for my engine. As it turns out, linear algebra was actually one of the most useful math courses here. It took a lot of work, but I’m now convinced that moving to 3D was a great idea.

Behind the interface of a visual component (how our visual information is stored) is a set of vertices with corresponding texture coordinates, a scale transformation and a translation. When the visual manager goes to draw everything for the frame, it sorts visual components by texture, then loads the first texture into memory. It places each object by multiplying the matrices together:

DrawTransformation = Scale * Translation * View * Projection;

Best of all, since every visual component using the same texture is drawn in a batch, there are only as many draw calls to the gpu as there are textures! Depth is even handled by the depth-buffer (I’ve specified a depth value for visual components that roughly cooresponds to a Z-value).

Now, if I want to add a rotation to an object, or perhaps even add a world translation (similar to camera position – useful for side-scrollers), all I have to do is add another tranformation matrix to the positioning call. Sure, I could have just used the SpriteBatch and done most of this that way, but using 3D allows me to use lighting and other 3D-effects if I want to in the future.

Finally, the way I’ve set up my View and Project matrices, world coordinates translate almost directly to screen coordinates (i.e. pixels). By default, placing an object at (20,20) will place it 20 pixels from the left and top of the drawing window. This makes it extremely easy when programming a game to make sure things are placed correctly.

I’m not sure if the other engines do this or allow it, but I think it’s much better than just blitting to the screen, and you should at least consider looking into transformations on your points if you plan to make anything other than a static-screen game.

Leave a Reply