Compiling an entity to a single vertex buffer

posted in Jemgine
Published August 09, 2011
Advertisement
I've copied this from my 'real blog', at jemgine.omnisu.com, as I almost always do. Perhaps, though, I should claim this as the 'real blog', since it has far more readers. This is about my 2d game engine, Jemgine, which I talk about all the time and nobody cares about. It's written in C# with XNA, and I guess I sort of assumed anyone reading this already knew a bit about the engine. In Jemgine, entities are made up of many elements grouped together. Mostly polygons and sprites, but also occasionally lines and circles and 'quads', which are sort of a hybrid of a polygon and a sprite. Anyway, the original blog entry...


Compiling an entity into a single vertex buffer-


This is something I've wanted to do in Jemgine for a long time. Currently (Well, until last night) to draw an entity (And, I mean every entity) meant iterating over all of an entity's attached elements, discovering if they were renderable, and then drawing them. Drawing each attached element usually involved at least a texture switch, and a draw call - sometimes more than one! Drawing a lot of entities was not an option. As it stands, it never became a problem for me. It still worked plenty fast enough. But I didn't like it, and I imagined having a static background entity made of thousands of sprites, something quite impossible with the existing method. I already knew a better way, it's just a matter of actually doing it. And, actually, it's not that hard at all. Keep in mind that this is optional, as it breaks many things. Any given entity can be compiled to a single vertex buffer, or drawn using the brute force method.

Here's how it's done in basic steps:
At build time,
-Gather all the textures used by the entity. One thing I did not account for in this stage (or any others) is elements whose' texture changes. Texture-switching effects will have to be achieved using the old brute-force rendering method. I also didn't account for Lines and Splines having a default texture, or round ends. These textures won't be included.
-Combine all of those textures into a single atlas texture. There's a problem here, if the texture created exceeds the maximum size the hardware can support. It also potentially wastes, via duplicating textures, video memory. Not much to do about it. I could build a whole-map texture atlas, but imported maps would still have their own atlas, with their own potentially duplicated textures; and the whole-map atlas would be much more likely to be too big. To pack the textures, I use a simple BSP subdivision scheme. There are better algorithms. I especially like the one from this paper http://clb.demon.fi/files/RectangleBinPack.pdf which subdivides the free space left from each placement into two overlapping rectangles. I might implement something like this in the future.
-Now I go through every element and get from it a vertex list in the form of a triangle strip. I use a strip because most of the elements were already rendered using one, so the data was there ready to go. The vertex indexes are implicit in the triangle strip as well. Each element also has a color and a bone id. To the engine, these properties apply to the whole element. For the final shader, they have to be duplicated across every vertex that makes up that element. I use the texture atlas to re-map texture coordinates.

-Now, this list of verticies and indexes, and the texture atlas, are serialized to disk. The texture atlas has not been rendered yet, it's just a set of filenames and rectangles so far. I do this partly because I don't know how to get XNA's content pipeline to store generated textures and vertex buffers (I know it can) and partly because the texture atlas is much smaller stored this way.

At load time,
-Deserialize everything.
-Load the individual textures in the atlas and use a render target and spritebatch to compose them into a single texture.
-Create the vertex buffer and index buffer.

Each instance of an entity will share the atlas texture and the vertex buffers, assuming they have been instanced properly. Though, I should check on that. I might not be creating the objects at all for imported maps!

At render time,
-Collect bone transforms. An entity can still have multiple skeletons, but it must have no more than 32 bones total. This is a mostly arbitrary constant. To continue running on shader model 2.0, and thus in the reach profile, I can't have more than 256 shader constants. Each bone transform represents, I think, 4 constants.
-Set the world matrix to the entity's transform.
-Draw the entity in a single draw call!

0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement