Learning 2D Graphics: Skins And Transparency
Over the course of the past week or so, I've completed the chapter of 3D Game Engine Programming that covers the basics of the code for handling 2D graphics: a skin manager to handle materials, textures, and color effects like chroma key and transparency. Along the way I've accumulated a great many thoughts I'd like to share, from tricks I've picked up to open questions I have to some theoretical concepts I've gained knowledge about.
As was done with lighting and quaternions earlier in the book, Zerbst and Duvel provided some highly welcome conceptual and algorithmic explanations of the various features relevant to the code I was working on. First among them was an explanation of height maps and other kinds of texture mapping. As with quaternions, these were a tool I'd seen reference to in my use of the Unity3D engine, but before now I'd only understood their general usage. Now, I'm happy to say I understand why the textures for height maps, bump maps, etc. look the way they do: the darker the color in the texture, the lower the surface appears!
The book also delved a bit into the details of how transparency effects are applied. Specific focus was given to explaining the order of applying colors and transparency to textures--from back to front--and the common gotchas that can happen if this ordering process is not well thought through or not well accounted for in other areas of the code.
On Performance: Data Management
Another heavy focus of this chapter was data management. This makes sense, after all, since the primary coding that is done throughout this chapter is the construction of a skin manager. Given how many 2D resources are used in any game, it is tremendously important to be able to manage textures and materials in an efficient, performant manner. Thanks to this focus on the part of the book, I picked up a few particularly handy tricks for how to do this. They are relatively simple, I grant, but for me at least they are the sort of things that are far more clear in hindsight, and not something I would have thought of on my own.
Firstly, Zerbst and Duvel point out that since any game is going to use many textures, materials, and skins, it makes no sense to only allocate memory for one piece of data at a time. Far better to allocate in large chunks (the authors recommend 50 at a time), as it will not only reduce the amount of processing that must be done as new textures are being loaded, but it will also ensure that game data is not nearly so fragmented in memory. This way, there will be a performance savings every time the game needs to access memory for a set of textures or other data. The age of the book, however, does leave the open question of whether it would make more sense to allocate in larger chunks than 50. Will a modern game be loading enough textures to make it worth the cost of the engine becoming more of a memory hog?
The second handy tip that I learned from this portion of my work on the game engine is to store indices, not data. This will allow for vast reductions of redundancy. Why store the same texture dozens of times for all of the materials that will use it, when the material can instead save an index number that will simply point to that texture's location in the array holding all textures. This way, nothing need be stored more than once, and a large amount of resources will be saved.
As I continue my journey through Zerbst and Duvel's book, I am on the lookout for more ways in which to judge whether advice that was valid when the book was published in 2004 is still valid today. This chapter on 2D graphics, in particular, has left me with some important questions, some of which I have a guess to answer, and some not:
-Is the "skin" design pattern, a data structure that consists of a material and eight textures, outdated? If not, is it common for skins to hold more than eight textures now? I suspect the answer to that second question is no, since as I understand it the skin's extra textures are for things like height and normal maps. To my knowledge, modern game graphics wouldn't require significantly more sets of maps than in previous years
-Do modern game engines need to support vector graphics as well as bitmaps? Since formats like PNG, GIF, and TIFF are reducible to bitmaps, I doubt it. To my knowledge, vector graphics are not used widely outside of the web and mobile markets, which exist outside the target game type for this engine.
-Zerbst and Duvel implement a conversion from the 24-bit color that is standard on today's systems to 16-bit color. Since this was apparently done mostly to support older (by the standards of 2004!) computers, I didn't feel that it was necessary for my implementation of the ZFX Engine. I still wrote the conversion as a learning exercise, but it remains unused in the engine code. Was this the right choice, or is 16-bit color still used for textures that require no transparency?
A final note: As I've written this blog post, I've additionally learned that if I'm going to be doing these longer posts, I need to start taking pictures! Screencaps of my code, visuals of the concepts I'm learning, etc. This post turned out a bit longer than I thought, and I don't want to keep hitting my readers with giant walls of text!
Progress So Far: Completed a skin manager to handle textures, materials, and alpha blending