Sunday, April 29, 2012

Texturing for Games - Basics

Texturing in video games is a slightly different animal than for film or rendered projects.  There are a couple of requirements to keep in mind and we'll go over why they are so restrictive.

1. Memory Footprint - The larger the texture the more memory it takes up

Of all the assets you import, textures take up more memory than most.  One of the surest ways to reduce over-all memory usage (from assets) is to reduce texture sizes.  This is pretty basic and obvious as a whole, but i want to treat the topic with a little more finesse than "Use smaller textures!".

So your standard asset now a-days will have, let's say, a diffuse(color) map, a spec, normal, and mayhaps an emissive.  Along with these you will end up with various masks and specialty textures related to specific assets. By default habit we end up usually starting with a diffuse texture then building the rest from there.  This often ends with each of these maps being the same resolution even though they shouldn't necessarily.

This is a very dynamic subject that must be checked on a per asset basis but here is some general info as I have found.  The basic idea is to try each separate mask as multiple resolutions until you get what you need to get the look you want with minimal texture resolutions.  There are many tricks that we can do to REALLY reduce texture sizes and texture lookups but that will be for later posts.

Example Time:


  • Diffuse on my character is a 1024x0124, i like the look and stick with it
  • I generate a spec map out of this but my spec needs little detail so i find that i can import it as a 512 and not get any compression issues.
  • My normal map requires some detail for pores and such but in general it needs little.
    At this point i usually end up with a detail normal (pores and such) that i overlay onto a specific normal for my character.  Now usually this wouldn't be very efficient but i use this normal on many characters so i only have to import it once.  So i have 2 textures, a universal 256x256 detail and a 512x512 normal map but only the 512 is character specific.
  • My characters armor has emissive(glow/incandescence)  for some sweet running lights.  On average emissive textures can be much lower res due to the nature of how they are handled.  Emissive textures are interesting cases solely because often they will use very small sections of a UV layout and texture sheet.  Some engines deal with this in different ways (Unreal Engine 3 has a nifty export tool to just export that important parts and it does some shader magic to make them line up), but otherwise we do our own tricks involving special UV channels to stress important areas specifically. In the end i get a 256 emissive texture.
  • By reducing these sizes instead of just going with the first resolution i chose i am using a little over half as much memory as my original sizes would have.

2. "Power of 2" rule - Textures have specific resolutions

So we talk about texture sizes in these specific sizes, each one being a power of 2 (starting with 2 and multiplying each result by 2 again).  The reason we do this is for some programming mumbo jumbo related to shifting bits around but we don't care much about that.  I will point out some things associated with it that are good to know in general though.

Some game engines do not require a power of 2 texture!  This seems like total awesome freedom at first but when we look at it closer we find there are problem with this!

Any texture that is imported, compressed, and built for use in game will be power of 2 eventually.  The engine itself will convert your texture to work properly which may result in some problems.  Essentially it is adding empty (black) space around the edge of your texture until it reaches the next power of 2.

Example: A 545x580 will end up being a 1024x0124!

So this is an extreme example but very important.


  1. That is all wasted space, why not fill it or increase your UV layout to match and get some free texture space back?
  2. This sort of thing leads to misjudging available memory usage/etc which may be important.
  3. In some engines, this conversion is done at RUN TIME! This means that when that texture is loaded into memory it has to up-convert it, which causes noticeably slower load times.
  4. Mipmaps may be corrupted.  Mipmaps are essentially smaller versions of the texture for use in LODs.  Like with reducing texture sizes in any program you get blurring between pixels.  When your pixels lay at the edge or similar colors it is not always noticeable but imagine your bright red pixel now has a bunch of solid black padding around it.

3. Compression - Post-import textures are converted for use in the game engine, resulting in various compression types. LOD, etc

This is just a quick note on compression.  Some engines do some hardcore compression to your textures and sometimes the only solution is to make sections bigger.  This is something you need to learn through intimate late nights with your chosen engine.  As a quick example, unreal ueses DXT compression mostly and it is just plain mean to dark gradients.

4. MultiTexture  per-channel masks

Sometimes an asset may have several black and white masks used for any number of specific circumstances.  If these masks don't mind certain compression risks they can each be stored into a single texture, taking advantage of the red, green, and blue channels as their own textures.  This takes up the amount of memory a single texture would for a total of 3 masks.

5. Alpha channels

Based on your game engine, compression on Alpha channels may be handled differently.  Some engines will double the texture sizes when an alpha channel is added because they assume you want less compression on them.


Friday, April 27, 2012

Modelling for Games - Draw Calls

Games have a couple of restrictions and good practices for making models import and run smoothly.  Often these issues are just taken on faith and you work within your restrictions.  The problem is sometimes these limitations are only so strict due to lack of knowledge of where the restriction comes from.  I'll cover a couple of these in the next few posts, starting with Draw Calls!

What is a Draw Call?

Draw calls are essentially the game engine sending up groups of triangles to be handled by the rendering engine.  The sending of the data is handled by the CPU (processor) and the actual rendering is handled by the GPU (graphics card).

Where do they come from?

Draw calls are "generated" a little differently per game engine.  I will use Unreal Engine 3 as an example.  Each material/shader adds to the amount of draw calls (as well as lights and such but ignore that for now).  Therefore a single model with 3 materials applied to different faces is indeed 3 draw calls.

For characters this isn't so bad since they are usually limited, but for static meshes this could become a problem.  Thankfully most engines have a system for "batching" similar objects/materials together.  If a bunch of static objects with the same materials exist then they will be combined into a single draw call since they all get rendered the same way.

Why so expensive?

There are a couple of really technical reasons for draw call expense, but we won't cover everything nor do i know it.

There is a certain amount of overhead to every draw call regardless of the number of triangles or complexity of shaders.  So lots of tiny draw calls end up slowing things down due to this overhead.

Rough Example:

Picture you are moving a bunch of books off of an assembly line to a library.  The only boxes you have are made of steel.  Each box is so heavy that filling it with books only slightly affects the weight, therefore most of the weight of each box is the box itself.  Filling each box only half way is a waste of a trip since filling it to full would be little different weight-wise.

The weight of the box represents the initial cost of a draw call in general.  Always present despite the content.

The people shipping the boxes are the CPU, having to pick up the content and send it out for rendering.

The people unloading at the library are the GPU, getting these Draw Calls and rendering them and making them presentable.

The people packing the boxes of books are YOU.  Based on how well you create your models is a determining factor of draw call amount.

Unloading the boxes is pretty simple, especially if they are only half full.  The loaders(CPU) are doing a ton of work moving these half empty boxes while the unloaders(GPU) are barely doing anything, just sitting around waiting for the next boxes to come in.

Conversely if the boxes are packed too full, the loaders(CPU) would have many fewer boxes to carry but the unloaders(GPU) would be running around crazy trying to unload them fast enough since they have so much content in them.

Typically in my experience, the GPU is pretty darn fast.  No box carries enough books to really be worried about.  Therefore the process usually becomes CPU bound as too many small Draw Calls are sent.

The loss of frames per second is associated in this case with one of these systems being bottle necked and waiting on the other.

Why not just combine everything together?

To solve draw calls all together we could (and people have) do some combining of assets.

Let's say I have a series of meshes that make up a computer: a mouse, keyboard, monitor, and tower.  I originally made them each separately on separate textures to be placed by Level Design.

I know they will always be set up the same way every time though so to reduce draw calls i can combine them all into a single mesh with a single material.  The textures are a bit tricky but they can fixed up by taking each texture and laying it out next to the others in new larger square texture and then offset the UVs of my new combined model to fit up with the new texture locations.  This is called "Atlasing" your textures.

An Atlas of 4 ground textures combined into a single image:


Nothing wrong with that example other than a loss of control for placing the assets separately, but that can be decided based on the needs of a project.

Combining can be detrimental if done improperly.  It may seem silly but just because some polygons are off screen or hidden behind something does not mean that the game is not handling them.  There is a system in place calling "Culling" to try and emulate this.

Culling will essentially test objects to see if the engine should even render them and there are many many methods for accomplishing this.  Exempt from the exact way that objects get tested for Culling, they usually follow certain rules such as:

"If any part of the object would not be culled, none of it may be culled".

So essentially if your entire subterranean level is a single big cave mesh, that entire mesh will be considered for rendering no matter how much of it you can see.  This can cause considerable overhead for rendering as well as streaming levels and many other game systems that need to determine where an object is located.

So try to avoid combining things that are far apart or take up a lot of screen space.

Final Thoughts:

As a rule try to avoid separate materials on models, some examples of when a new material would be wanted:

  • You need very large textures 
    • head and body of characters are often separate
  • You need different rendering modes or lighting types on your meshes
    • Translucent vs Opaque, Phong vs An-isotropic
    • Like a truck with opaque body but separate window material so it can be translucent
  • You have small amounts of available memory and are using repeating texture maps instead of textures that match UV layouts
Some assets are considered hero pieces and thus will stand alone and not be used too often, these are often forgiven their misconduct and allowed whatever it takes to look amazing.

-

Thursday, April 26, 2012

Temporary vs Placeholder

So during early development you will often find yourself needing some quick and dirty assets for use in your game.  These may be the beginnings of a final asset or just a simple primitive you imported to appease the programming gods.  These assets typically fall into one of two categories: Placeholder and Temporary.

Placeholder assets are initial versions of permanent assets.

Temporary assets are imported and meant to be deleted before release.

Example 1:

A level designer needs to place a bunch of assets in a level but they aren't built yet!  You quickly throw together a couple of quick extruded primitives to sort of mimic what the houses and such may look like, then you get them into the engine and let him know.

He now places those objects throughout the level and later on you come back and update/replace those same meshes with the final products and the level is automatically updated with your new meshes.

The original meshes were Placeholders for the final assets; by getting him the assets quickly he could start doing his job and then later on you just imported the new assets onto/over the old placeholder ones, thus keeping the references intact.

Example 2:

A programmer needs some randomly sized/shaped meshes to test out some coding voodoo system you know nothing about.  Since these have no real purpose in the game, you just import some random meshes named something arbitrary like "Mesh1", "Mesh2", etc.  The programmer gets his system figured out and then no longer needs the random meshes you made.

This is an example of Temporary assets.  They filled a need quickly but were never planned to be a permanent asset.  Any role they filled was generic or not really planned out enough to have a clear goal.

Final thoughts:

Placeholder assets should be imported with the final asset names in properly setup packages/folders.  Treat them like they ARE the final asset.  Try to mimic the final asset as much as you can and go ahead and set up materials and placeholder textures, etc.

Temporary assets should follow a standard naming convention such as adding a prefix to them: "TEMP_Mesh1" or "DELETEME_Mesh2" to easily find them later for removal/dereferencing.  Sometimes it is hard for someone to know if a temporary asset is ready to be deleted so I often add a signature or initials to it "TEMP_BRYCE_Mesh1".  Try to avoid ever referencing temporary assets from any permanent assets.  This prevents a lot of fuss removing those references later on or your temporary asset becoming a poorly thought out permanent asset.

This idea is crucial for maintaining nice package/folder structures.  It really sucks when someone imports an asset called "TempThingie" into a package called "TempPackage" and it ends up being referenced throughout the game or having to go through every reference to that object and replace it with the new permanent asset you just imported.

Welcome

This is a small area for discussing game development topics that most artists don't know they need to know.  Though most of these topics won't apply to your every day life, they may give you insight into why game developers do things the way they do.

Most topics here are for general game development but some may be engine specific, usually dealing with Unreal Engine 3.