I had a great meeting with the Charlotte Area Game Development Group last Monday night. The Group is sponsored by Meridian Technologies, and is hosted by the Charlotte Microsoft Office. I met the team leader, Matt Duffield, who is doing a fantastic job running and organizing the Group. The key presenter that evening was Dan Russell Pinson, the creator of Monster Physics and the upcoming game Tower Math! Dan’s work can be found on his website.
The focus for Tuesday’s meeting was on Optimizing Mobile 3D Games in Unity and exploring some of the tools, tips and tricks for deploying to the various platforms. Dan had a pretty cool rule that I wanted to share on 2 key statistics for mobile performance: number of draw calls and number of drawn triangles.
At most, you should have 50 draw calls and 20,000 drawn triangles
That initially sounds like a lot until you start popping open the terrain editor, downloading assets from the store and placing them into your scene. To prove his point, Dan built a sample piece of terrain which consisted of over 100,000 triangles and more than 200 draw calls. This presented a unique challenge, since he ended up investing 4 times the maximum draw calls and 5 times the maximum triangles in the terrain alone. Luckily, Dan found some cool tools in the Unity Asset Store:
- T4M – Transforms your terrain into a model
- Cruncher – Reduces Polygon count of models via a slider, can also be used for Level of Detail (LOD)
- Mesh Baker – Great for creating assets that can be statically batched
First he used T4M on the sample terrain*, then, he used Cruncher to reduce the polygon count to something that presented a good balance between appearance and performance. These two easy steps reduced Dan’s initial statistics to 7,000 triangles and 6 draw calls – a 20X performance gain! This performance can further be increased by setting the terrain model to static and to bake lighting (so mountain shadows are baked into the scene), further reducing both statistics.
*(and then had to adjust the texture tiling, as T4M appears to have a bug that messes that up, luckily is fixed in under 30 second
Always check your downloaded assets – they usually come at the highest resolutions possible
Once we finally had our terrain, the next step was to add some scenery. Dan selected some assets he had downloaded for free from the asset store, which were made specifically for games on mobile phones. He inserted an Aztec-type temple, a French villa, and a giant tombstone into the landscape. As you might imagine, the addition of these structures sent our statistics through the roof again. Dan introduced a step by step process with these assets that should be used on all models brought into a mobile game:
- Check the size of the textures. The size of the textures was set to 2048, which is just silly big for a mobile game. Dan was able to drop this to 128 without any appreciable loss of quality on the temple. He did the same for the French villa and the tombstone, which were reduced to 256 and 64 respectively.
- Crunch the models. We just did the temple as the process was the same for all 3, but we were able to drop the number of triangles from 15,000 down to 6,000 without any appreciable deterioration. If you need to reduce further, you could put the model in blender to pick specific areas to reduce the number of triangles, such as square segments that should be at most 2 triangles.
- Remove “receive shadows”. These particular models were not in an area of the scene were receiving shadows is important. Now I know what you may think, but what about mountain shadows from scenery, will it receive those? And the answer is YES! IFF both models are set to static.
- Set to static. This will allow for a possible batching match of models.
- Mesh Baker. Dan took all 3 models and combined them with Mesh Baker, this allowed all three models to share the same material, and be baked into a single batch-able model.
- Light Mapping. Dan then used the built in light mapping tools to bake the scene.
For this scene in Dan’s game we were using a terrain piece which had been previously optimized at 5 draw calls and 4,400 triangles. After the addition of the Aztec temple, the French house, and the tombstone, we were able to have our scene at only 7 draw calls and 13,000 triangles an impressive statistic for both the terrain and detailed scenery.
What about moving components, like enemies?
Dan was presented with a unique problem here as his game shows the entire scene the entire time, and therefore can show large quantities of enemies simultaneously. While this may sound more like an asset than a problem, the truth is that it is computationally difficult for a game to display a high number of moving characters at once. Since the premise of Dan’s game is based on having many enemies, this was an issue which needed to be solved. The key to optimizing the performance of game characters is dynamic batching (click here for more info). Components to be batched must meet the following criteria in order for dynamic batching to work for them:
- Share same material
- < 900 vertices
- No multi-pass shaders
- No shadows
Looking at Dan’s game, the major problem appears to be the sheer number of different materials required: There are 10 different enemies with roughly 10 stages of damage they can receive, which equates to nearly 100 different possible materials.
After pondering this for a while, Dan realized that a model is just a bunch of triangles with UV mappings for textures.
It was not long before Dan remembered a technique called Texture Atlasing – a popular method which you can read more about here. Dan created what was essentially a single texture material split into a 10×10 grid. Each cell on the grid represented the individual materials for each enemy. Dan then added code to his enemy scripts which altered the way that the texture is applied to each enemy. That is to say, if an enemy receives enough damage, that particular model’s UV mappings will be changed to the new offset for the next material in the damage chain. Therefore, instead of applying brand new material as you might normally do, Dan discovered a way for enemies to be batched together in a single draw call!
Last but not least, your game code may need to support multiple devices with various capabilities. A great tool for this is the Unity Quality Settings Panel. This panel allows you to define several quality levels for your game.
From this panel you can configure your graphics levels. For example, if you have two levels, “Fantastic” and “Fastest”, you might set shadows to OFF and set the max LOD level to 1 in “Fastest”, while having soft shadows ON and the max LOD level set to 5 in “Fantastic”.
In summary, here is a review of the topics we have gone over:
- Batching. By ensuring that sets of objects in your game can be batched together, you can reduce the number of draw calls significantly. There are two types of batching: static and dynamic.
- Shadows are expensive. Whenever you can mark a character or object as “not receiving/giving shadows”, do so.
- Texture Atlasing is awesome. Use one material for everything. Just reset your UV mappings on the fly using precise offsets.
- Cruncher is $$$, but cool. This tool is somewhat expensive, but now you can reduce poly count quickly, set LOD levels, and access via script in game.
- Reduce your texture sizes to something mobile-friendly.
- Static models perform well.
- Mesh Baker allows entirely different models to become one. Remember that this turns into a single model and though you may only see a single model, all of them will be drawn. Basically, Mesh Baker allows you to combine different materials and models into one set.
- T4M. A great tool to transform your terrain into a model. This increases performance on its own, and also opens the opportunity for further optimization.
- Bake your lighting!!! Baking lighting into the textures allows for received shadows between static objects and increases your performance! (This only works on static models.)
- Use the Quality Settings Panel. 60 fps on a Nokia 1520 might only be 10 fps on a Nokia 820.
- Level of Detail is crucial. If your 500,000 triangle dragon is so far away in the scene that is it is essentially a dot, you might as well have it be 10 triangles until it is up close tearing your head off at its 500,000 triangle glory.
Well I hope this was a good and informative post.