- Home /
Combine meshes result in a larger file size on export (GLTF)
Hi guys, I have a script to combine meshes which share the same material. The obvious goal is to reduce the draw calls count and it works perfectly (from 500 draw calls to about 70).
I need to export the scene in GLTF compressed format (.glb) to use it on web, I am using this open source project by KhronosGroup.
I've noticed that after the combine operation, my exported file has a larger file size: from 2 MB (not combined) to about 5.8 MB (combined). I don't understand the reason , since materials and textures should be the same. Does anyone know why is this happening?
How "large" are those meshes? $$anonymous$$eep in $$anonymous$$d that Unity by default uses a 16 bit index buffer which limits a single mesh to 65k vertices. However for quite some time now Unity supports 32 bit index buffers. Of course they require twice the space.
I've never used the glTF format. However it seems that usually vertex and index data is stored binary. So it's reasonable that if you combine meshes that the index buffer format might need to change and results in a twice as large index buffer. However since the index buffer usually is only a tiny fraction of the total size this shouldn't have such a large impact.
From what i've seen the "glb" format is a very simple "archive" / concatenation of the involved files with a small 8 byte header (4 byte integer for the file size and a 4 byte type string). So since the major contributing files (usually textures) shouldn't change, the size shouldn't grow that heavily.
I have a script to combine meshes
This is probably the main cause of the issue. $$anonymous$$aybe this script destroys the shared references and somehow each combined mesh now has it's own set of textures. We can't really tell without more information on how you do that "combining".
Answer by _lud_ · Apr 11, 2019 at 01:04 PM
Hi @Bunny83 , thanks for the answer. The script to combine meshes is almost the same as the one provided by Bunzaga on this thread:
using UnityEngine;
using System.Collections;
public class MeshCombiner : MonoBehaviour
{
public void Awake()
{
ArrayList materials = new ArrayList();
ArrayList combineInstanceArrays = new ArrayList();
MeshFilter[] meshFilters = gameObject.GetComponentsInChildren<MeshFilter>();
foreach (MeshFilter meshFilter in meshFilters)
{
MeshRenderer meshRenderer = meshFilter.GetComponent<MeshRenderer>();
if (!meshRenderer ||
!meshFilter.sharedMesh ||
meshRenderer.sharedMaterials.Length != meshFilter.sharedMesh.subMeshCount)
{
continue;
}
for (int s = 0; s < meshFilter.sharedMesh.subMeshCount; s++)
{
int materialArrayIndex = Contains(materials, meshRenderer.sharedMaterials[s].name);
if (materialArrayIndex == -1)
{
materials.Add(meshRenderer.sharedMaterials[s]);
materialArrayIndex = materials.Count - 1;
}
combineInstanceArrays.Add(new ArrayList());
CombineInstance combineInstance = new CombineInstance();
combineInstance.transform = meshRenderer.transform.localToWorldMatrix;
combineInstance.subMeshIndex = s;
combineInstance.mesh = meshFilter.sharedMesh;
(combineInstanceArrays[materialArrayIndex] as ArrayList).Add(combineInstance);
}
}
// Get / Create mesh filter & renderer
MeshFilter meshFilterCombine = gameObject.GetComponent<MeshFilter>();
if (meshFilterCombine == null)
{
meshFilterCombine = gameObject.AddComponent<MeshFilter>();
}
MeshRenderer meshRendererCombine = gameObject.GetComponent<MeshRenderer>();
if (meshRendererCombine == null)
{
meshRendererCombine = gameObject.AddComponent<MeshRenderer>();
}
// Combine by material index into per-material meshes
// also, Create CombineInstance array for next step
Mesh[] meshes = new Mesh[materials.Count];
CombineInstance[] combineInstances = new CombineInstance[materials.Count];
for (int m = 0; m < materials.Count; m++)
{
CombineInstance[] combineInstanceArray = (combineInstanceArrays[m] as ArrayList).ToArray(typeof(CombineInstance)) as CombineInstance[];
meshes[m] = new Mesh();
meshes[m].CombineMeshes(combineInstanceArray, true, true);
combineInstances[m] = new CombineInstance();
combineInstances[m].mesh = meshes[m];
combineInstances[m].subMeshIndex = 0;
}
// Combine into one
meshFilterCombine.sharedMesh = new Mesh();
meshFilterCombine.sharedMesh.CombineMeshes(combineInstances, false, false);
// Destroy other meshes
foreach (Mesh oldMesh in meshes)
{
oldMesh.Clear();
DestroyImmediate(oldMesh);
}
// Assign materials
Material[] materialsArray = materials.ToArray(typeof(Material)) as Material[];
meshRendererCombine.materials = materialsArray;
foreach (MeshFilter meshFilter in meshFilters)
{
DestroyImmediate(meshFilter.gameObject);
}
}
private int Contains(ArrayList searchList, string searchName)
{
for (int i = 0; i < searchList.Count; i++)
{
if (((Material)searchList[i]).name == searchName)
{
return i;
}
}
return -1;
}
}
I've also tried this payed solution from the Asset Store for combine meshes, with the same result on the export.
Your answer
Follow this Question
Related Questions
CombineMeshes Error on Run-time Meshes 2 Answers
skinned mesh renderer, combine meshes can't see the result, what am I doing wrong/ missing? 0 Answers
How to combine multiple new meshes without instantiating? 1 Answer
How to merge generated meshes 0 Answers
CombineMeshes() Not Working Properly? 0 Answers