How do you combine meshes with submeshes?
I have two meshes, and each mesh has two submeshes. What I want, after combining them, is one mesh, and two submeshes.
How do you combine meshes with submeshes?
I have two meshes, and each mesh has two submeshes. What I want, after combining them, is one mesh, and two submeshes.
just found this question using google, and i found a simpler answer while trying to figure this out:
you can use the .subMeshIndex property on your CombineInstance-s, so for each submesh you want to combine you need to add a CombineInstance with the correct subMeshIndex.
this is how i did it:
(the script is placed on a parent GO, with an empty mesh filter, and a mesh renderer. the script combines child meshes on awake, while keeping the mesh in the same position as the originals were. the resulting mesh uses only 1 material)
void Awake ()
{
// save the parent GO-s pos+rot
Vector3 position = transform.position;
Quaternion rotation = transform.rotation;
// move to the origin for combining
transform.position = Vector3.zero;
transform.rotation = Quaternion.identity;
MeshFilter[] filters = GetComponentsInChildren<MeshFilter> ();
List<CombineInstance> combine = new List<CombineInstance> ();
for (int i = 0; i < filters.Length; i++)
{
// skip the empty parent GO
if (filters*.sharedMesh == null)*
continue;
// combine submeshes
for (int j = 0; j < filters*.sharedMesh.subMeshCount; j++)*
{
CombineInstance ci = new CombineInstance ();
ci.mesh = filters*.sharedMesh;*
ci.subMeshIndex = j;
ci.transform = filters*.transform.localToWorldMatrix;*
combine.Add (ci);
}
// disable child mesh GO-s
filters*.gameObject.SetActive (false);*
}
MeshFilter filter = GetComponent ();
filter.mesh = new Mesh ();
filter.mesh.CombineMeshes (combine.ToArray (), true, true);
// restore the parent GO-s pos+rot
transform.position = position;
transform.rotation = rotation;
}
you can combine meshes with with combinechildren script in standard assets. if you import standard assets you can find it in component menu in mesh sub menu. you can combine a mesh with it's children with this script. you can easily modify the code to do what you want because the main part of this script is the function that combines two meshes.
I commented on the previous answer, but I just tested my theory and it seems to work. To recap: I create a NEW mesh for each sub-mesh in an original mesh. I then combine these (sub-mesh) meshes. So for 4 objects that use identical 2-sub-mesh meshes, instead of getting a single combined mesh with 8 sub-meshes, I get 2 combined meshes, with 1 "sub-mesh" each. This brings my draw calls down from 17 to 6, in my test case.
Briefly, I performed 4 steps to combine objects that use meshes with multiple sub-meshes:
Sorry if the wording is poor. Hope this helps.
Update: There appears to be a bug with the MeshCreationHelper script that I linked to above. I don't believe it's properly constructing the new triangle list. I edited the wiki discussion for that page, so you can view my suggested change via the discussion:
http://www.unifycommunity.com/wiki/index.php?title=Talk:MeshCreationHelper
The answer by @raziel_anarki almost does the trick. The only one little step left to go. Actually we need to combine all corresponding submeshes by index into separate combined meshes, and then combine them all as submeshes within the resulting mesh. Like this:
// Combines all root's children's meshes into the root's mesh.
public Mesh CombineMeshesWithSubmeshes(GameObject root)
{
// save the parent GO-s pos+rot
Vector3 position = root.transform.position;
Quaternion rotation = root.transform.rotation;
// move to the origin for combining
root.transform.position = Vector3.zero;
root.transform.rotation = Quaternion.identity;
MeshFilter rootMf;
root.TryGetComponent<MeshFilter>(out rootMf);
MeshFilter[] meshFilters = root.GetComponentsInChildren<MeshFilter>(); // root included
List<CombineInstance> combineFinal = new List<CombineInstance>();
Mesh mesh = null;
// first find the maximal number of submeshes in each mesh
int maxSubMeshes = 0;
foreach (MeshFilter mf in meshFilters)
{
if (mf.sharedMesh) {
maxSubMeshes = Mathf.Max(maxSubMeshes, mf.sharedMesh.subMeshCount);
}
}
// create separate lists for each submesh index found
List<CombineInstance>[] combines = new List<CombineInstance>[maxSubMeshes];
for (int j = 0; j < maxSubMeshes; j++)
{
combines[j] = new List<CombineInstance>();
}
for (int i=0; i < meshFilters.Length; i++)
{
if (!meshFilters*.sharedMesh) continue;*
// iterate submeshes, and put them into the corresponding combine lists
for (int j = 0; j < meshFilters*.sharedMesh.subMeshCount; j++)*
{
CombineInstance ci = new CombineInstance
{
mesh = meshFilters*.sharedMesh,*
subMeshIndex = j,
transform = meshFilters*.transform.localToWorldMatrix*
};
combines[j].Add(ci);
}
// disable GO (considering root included)
if (meshFilters != rootMf) meshFilters*.gameObject.SetActive(false);*
}
// first combine all the meshes of the ‘sub’ combines lists into combineFinal list
foreach (List subCombine in combines)
{
mesh = new Mesh();
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
mesh.CombineMeshes(subCombine.ToArray(), true, true);
//store combined mesh for further combining
CombineInstance ci = new CombineInstance { mesh = mesh };
combineFinal.Add(ci);
}
// and finally combine all joined submeshes into large single mesh
mesh = new Mesh();
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
mesh.name = “Combined-Subs” + maxSubMeshes.ToString();
// now each mesh becomes a submesh in given order
mesh.CombineMeshes(combineFinal.ToArray(), false, false);
// restore the parent GO-s pos+rot
root.transform.position = position;
root.transform.rotation = rotation;
// assign the mesh to the root’s filter if any
if (rootMf) rootMf.sharedMesh = mesh;
return mesh;
}
One more suggestion for anyone coming here in the future if the other suggestions don’t suit you. You can do this very easily with the “Easy Mesh Combiner MT” plugin available in the Asset Store. Here is the link: Easy Mesh Combiner MT - Scene Mesh Merge, Atlasing Support & More | Game Toolkits | Unity Asset Store