How should you efficiently batch complex meshes?
<p>What is the best way to render complex meshes? I wrote different solutions below and wonder what is your opinion about them.</p>

<p>Let's take an example: how to render the 'Crytek-Sponza' mesh?</p>

<p>PS: I do not use Ubershader but only separate shaders</p>

<p>If you download the mesh on the following link: </p>

<pre><code>http://graphics.cs.williams.edu/data/meshes.xml
</code></pre>

<p>and load it in Blender you'll see that the whole mesh is composed by about 400 sub-meshes with their own materials/textures respectively.</p>

<p>A dummy renderer (version 1) will render each of the 400 sub-mesh separately! It means (to simplify the situation) 400 draw calls with for each of them a binding to a material/texture. Very bad for performance. Very slow!</p>

<pre><code>pseudo-code version_1:

foreach mesh in meshList //400 iterations :(!
 mesh-&gt;BindVBO();

  Material material = mesh-&gt;GetMaterial();
  Shader bsdf = ShaderManager::GetBSDFByMaterial(material);

  bsdf-&gt;Bind();
   bsdf-&gt;SetMaterial(material);
   bsdf-&gt;SetTexture(material-&gt;GetTexture()); //Bind texture

    mesh-&gt;Render();
</code></pre>

<p>Now, if we take care of the materials being loaded we can notice that the Sponza is composed in reality of ONLY (if I have a good memory :)) 25 different materials!</p>

<p>So a smarter solution (version 2) should be to gather all the vertex/index data in batches (25 in our example) and not store VBO/IBO into sub-meshes classes but into a new class called Batch.</p>

<pre><code>pseudo-code version_2:

foreach batch in batchList //25 iterations :)!
  batch-&gt;BindVBO();

  Material material = batch-&gt;GetMaterial();
  Shader bsdf = ShaderManager::GetBSDFByMaterial(material);

  bsdf-&gt;Bind();
   bsdf-&gt;SetMaterial(material);
   bsdf-&gt;SetTexture(material-&gt;GetTexture()); //Bind texture

    batch-&gt;Render();
</code></pre>

<p><em>In this case each VBO contains data that share exactly the same texture/material settings!</em></p>

<p>It's so much better! Now I think 25 VBO for render the sponza is too much! The problem is the number of Buffer bindings to render the sponza! I think a good solution should be to allocate a new VBO if the first one if 'full' (for example let's assume that the maximum size of a VBO (value defined in the VBO class as attribute) is 4MB or 8MB).</p>

<pre><code>pseudo-code version_3:

foreach vbo in vboList //for example 5 VBOs (depends on the maxVBOSize)

 vbo-&gt;Bind();

 BatchList batchList = vbo-&gt;GetBatchList();

 foreach batch in batchList

  Material material = batch-&gt;GetMaterial();
  Shader bsdf = ShaderManager::GetBSDFByMaterial(material);

  bsdf-&gt;Bind();
   bsdf-&gt;SetMaterial(material);
   bsdf-&gt;SetTexture(material-&gt;GetTexture()); //Bind texture

    batch-&gt;Render();
</code></pre>

<p><em>In this case each VBO does not contain necessary data that share exactly the same texture/material settings! It depends of the sub-mesh loading order!</em></p>

<p>So OK, there are less VBO/IBO bindings but not necessary less draw calls! (are you OK by this affirmation ?). But in a general manner I think this version 3 is better than the previous one! What do you think about this ?</p>

<p>Another optimization should be to store all the textures (or group of textures) of the sponza model in array(s) of textures! But if you download the sponza package you will see that all texture has different sizes! So I think they can't be bound together because of their format differences.</p>

<p>But if it's possible, the version 4 of the renderer should use only less texture bindings rather than 25 bindings for the whole mesh! Do you think it's possible ?</p>

<p>So, according to you, what is the best way to render the sponza mesh ? Have you another suggestion ?</p>