Ardor3D & Android: Optimization (Part I)
The keywords I’ll be using are:
- Mesh Combination
- Texture Atlas
So, as you should know by know, Caravel is a board game centered around hexagonal tiles.
These tiles, in general, can be divided in a couple of groups: Wool, Wood, Stone, Ore, Grain, Desert, and not altered or moved once placed.
Mesh Combination
Meshes with duplicate attributes (same texture && type of primitive), can be combined into a single Mesh. This technique is used primarily because modern graphic hardware is optimized to handle a large sets of vertices much more efficiently than multiple small sets.
On Android however, the thing we want to eliminate is the amount of Draw calls to openGL ES. You can have 30.000 vertices in a scene, running at a smooth 30fps on Nexus One, if you optimize for draw calls.
However, if those vertices are all divided among individual (tile) models, framerate quickly drops down to 6-12.
Mesh Combination benefits the most from static meshes; meshes in which the individual meshes it is composed of, do not change.
It is possible to change the individual meshes, but this forces us to keep track of where the corresponding vertices are in the combined mesh. For reference, see Besieged for a implementation of this technique.
First off, let’s start by combining all models we have which have a same texture.
This can be easily done by using the MeshCombiner class in Ardor3D.
<pre name=”code” class=”java”>
…
// First create a Node you want to compile.
Node combine= new Node();
int meshes=100;
For(int x=0; x<meshes;x++){
Box b = new Box();
b.setTranslation(x,0,0);
compile.attachChild(b);
}
// The actual combination:
Node combined= MeshCombiner.combine(compile);
…
</pre>
Eh, voila: all your models are now grouped together in a single mesh.
In essence, what this method does, is group Mesh Data of multiple meshes together in a single Mesh Data.
The downside is that the technique does not optimize, and you could be left with a lot of unnecessary vertices which are occluded by other vertices if the models where setup this way.
Texture Atlas
So now we have a group of combined meshes, consisting of the tile types mentioned earlier.
The only thing that sets these models apart from each other is their texture.
If not for that, we could combine them again in an even larger model.
This is where the Texture Atlas comes in handy:
By creating a larger texture consisting of the individual smaller textures of the models, and adjusting the U/V* coordinates on each model, we can compile the tile nodes into a single model.
(*: U/V coordinates indicate where a part of a Texture should be placed on a model)
The simplest approach would be to adjust the MeshCombiner class to distribute the U/V coordinates in direction, width, and create a method that stacks all the individual textures in a single direction into a larger Texture.
Note: as the most occurring maximum texture size of Android is 2048×2048, this technique will need to be adjusted to distribute the textures in all directions instead of just one.
As usual, all relevant code can be found on: http://github.com/methius/Caravel
Part II of this series will primarily center around the speed differences in primitives: Triange List vs Triangle Strip vs Triangle Fan.