Skip to content

Instantly share code, notes, and snippets.

@reveriejake
Last active April 6, 2023 11:17
Show Gist options
  • Save reveriejake/a80f131979017b23594d37ddc0671a04 to your computer and use it in GitHub Desktop.
Save reveriejake/a80f131979017b23594d37ddc0671a04 to your computer and use it in GitHub Desktop.
More advanced mesh combiner that takes in a parent gameobject and combines all child meshes regardless of material count or triangle count. Outputs a lit of generated gameobjects that contain the combined meshe(s). Could probably use some optimizations ;). Modified and improved from https://www.youtube.com/watch?v=6APzUgckV7U&ab_channel=CraigPerko
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
namespace PicoGames
{
public class MeshCombiner
{
const int MAX_VERT_COUNT = 65535;
public static GameObject[] Combine(GameObject obj)
{
List<GameObject> renderGOs = new List<GameObject>();
Queue<MeshFilter> filterQueue = new Queue<MeshFilter>(obj.GetComponentsInChildren<MeshFilter>());
while (filterQueue.Count > 0)
{
// Create New Render GO;
GameObject renderGO = new GameObject("RGO");
renderGO.transform.SetParent(obj.transform);
renderGO.transform.position = Vector3.zero;
renderGO.hideFlags = HideFlags.DontSave;
var mr = renderGO.AddComponent<MeshRenderer>();
var mf = renderGO.AddComponent<MeshFilter>();
mf.mesh = GetMaxFilters(ref filterQueue, out var materials, false);
mr.sharedMaterials = materials.ToArray();
renderGOs.Add(renderGO);
}
return renderGOs.ToArray();
}
private static int GetVertexCount(Mesh mesh)
{
int vertCount = 0;
for (int i = 0; i < mesh.subMeshCount; i++)
{
vertCount += mesh.GetSubMesh(i).vertexCount;
}
return vertCount;
}
private static Mesh GetMaxFilters(ref Queue<MeshFilter> filterQueue, out List<Material> materials, bool setInactive)
{
List<MeshFilter> filterList = new List<MeshFilter>();
List<MeshRenderer> rendererList = new List<MeshRenderer>();
int vertexCount = 0;
while (filterQueue.Count > 0)
{
vertexCount += GetVertexCount(filterQueue.Peek().sharedMesh);
if (vertexCount > MAX_VERT_COUNT)
break;
var filter = filterQueue.Dequeue();
filterList.Add(filter);
filter.gameObject.SetActive(!setInactive);
var renderer = filter.GetComponent<MeshRenderer>();
if (renderer != null)
{
rendererList.Add(renderer);
}
}
materials = new List<Material>();
foreach (var renderer in rendererList)
{
Material[] localMats = renderer.sharedMaterials;
foreach (var localMat in localMats)
{
if (!materials.Contains(localMat))
materials.Add(localMat);
}
}
List<Mesh> subMeshes = new List<Mesh>();
foreach (Material material in materials)
{
List<CombineInstance> combiners = new List<CombineInstance>();
foreach (var filter in filterList)
{
MeshRenderer renderer = filter.GetComponent<MeshRenderer>();
if (renderer == null)
continue;
Material[] localMaterials = renderer.sharedMaterials;
for (int i = 0; i < localMaterials.Length; i++)
{
if (localMaterials[i] != material)
continue;
CombineInstance ci = new CombineInstance();
ci.mesh = filter.sharedMesh;
ci.subMeshIndex = i;
ci.transform = filter.transform.localToWorldMatrix;
combiners.Add(ci);
}
}
Mesh mesh = new Mesh();
mesh.CombineMeshes(combiners.ToArray(), true);
subMeshes.Add(mesh);
}
List<CombineInstance> finalCombiners = new List<CombineInstance>();
foreach (var mesh in subMeshes)
{
CombineInstance ci = new CombineInstance();
ci.mesh = mesh;
ci.subMeshIndex = 0;
ci.transform = Matrix4x4.identity;
finalCombiners.Add(ci);
}
Mesh finalMesh = new Mesh();
finalMesh.CombineMeshes(finalCombiners.ToArray(), false);
return finalMesh;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment