(效率低,适应性高)模型点超过65535自动分模型,一个mesh上有多个材质会自动分出来成为子集部分,父节点要有mesh则 fatherMesh = true;
(效率快、适应性低)模型点不能超过65535,超过会报错,且相同材质才会合并,若一个mesh上有多个材质会少一些材质(也就是丢失了一部分模型)
(适应性极低)模型点不能超过65535,超过会报错 ,材质相同也不会合并(一般外部不常调用,MergeMesh1、2函数更好)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace CombineMeshes
{
///
///注意:MergeMesh2、3只能针对于mesh上只有一个材质
///
public static class Combinemeshes
{
///
/// (效率低,适应性高)模型点超过65535自动分模型,一个mesh上有多个材质会分出来成为子集部分,父节点要有mesh则 fatherMesh = true;
///
public static GameObject MergeMesh1(GameObject parent, bool fatherMesh = true)
{
//获取原始坐标
Vector3 initialPos = parent.transform.position;
Quaternion initialRot = parent.transform.rotation;
//将模型坐标归零
parent.transform.position = Vector3.zero;
parent.transform.rotation = Quaternion.Euler(Vector3.zero);
List list = new List();
int verts = 0;
//存放要合并的父物体
Dictionary NewParent = new Dictionary();
//获取所有网格过滤器
MeshFilter[] meshFilters = parent.GetComponentsInChildren();
//通过游戏对象的总点数/65536,进行分组
for (int i = 0; i < meshFilters.Length; i++)
{
verts += meshFilters[i].mesh.vertexCount;
}
for (int i = 1; i <= (verts / 65536) + 1; i++)
{
GameObject wx = new GameObject("child" + i);
wx.transform.parent = parent.transform;
NewParent.Add(i, wx);
}
verts = 0;
int key = 1;
//给超过65535点的游戏对象进行分组
for (int i = 0; i < meshFilters.Length; i++)
{
verts += meshFilters[i].mesh.vertexCount;
if (verts >= 65535)
{
key++;
verts = 0;
verts += meshFilters[i].mesh.vertexCount;
}
//key= (verts / 65536) + 1;
if (NewParent.ContainsKey(key))
{
meshFilters[i].transform.parent = NewParent[key].transform;
}
//else
// Debug.Log("错误");
}
//处理多材质(一个mesh上有多个材质)
if (meshFilters[0].GetComponent().sharedMaterials.Length > 1)
{
list.Add(GameObject.Instantiate(meshFilters[0].gameObject));
}
//
foreach (var item in NewParent)
{
list.Add(MergeMesh3(item.Value, false));
}
//处理多材质
for (int i = 1; i < meshFilters.Length; i++)
{
if (meshFilters[0].GetComponent().sharedMaterials.Length > 1)
{
for (int j = 0; j < list[0].transform.childCount; j++)
{
GameObject.Destroy(list[0].transform.GetChild(j).gameObject);
}
GameObject.Destroy(meshFilters[0].gameObject);
}
if (meshFilters[i].GetComponent().sharedMaterials.Length > 1)
{
list.Add(GameObject.Instantiate(meshFilters[i].gameObject));
GameObject.Destroy(meshFilters[i].gameObject);
}
}
//
GameObject tar_Obj = null;
//是否父节点上有mesh
if (!fatherMesh)
{
tar_Obj = new GameObject();
tar_Obj.name = "clone_F";
for (int i = 0; i < list.Count; i++)
{
list[i].gameObject.transform.parent = tar_Obj.transform;
}
//还原坐标
tar_Obj.transform.position = initialPos;
tar_Obj.transform.rotation = initialRot;
}
//父节点上无mesh
else
{
for (int i = 1; i < list.Count; i++)
{
list[i].gameObject.transform.parent = list[0].gameObject.transform;
list[i].gameObject.name = "child" + i;
}
//还原坐标
list[0].gameObject.transform.position = initialPos;
list[0].gameObject.transform.rotation = initialRot;
}
GameObject.Destroy(parent);
return fatherMesh ? list[0] : tar_Obj;
}
///
///(效率快、适用性低)模型点不能超过65535,且相同材质会合并
///
public static GameObject MergeMesh2(GameObject parent, bool mergeAll = true)
{
//获取原始坐标
Vector3 initialPos = parent.transform.position;
Quaternion initialRot = parent.transform.rotation;
//将坐标归零
parent.transform.position = Vector3.zero;
parent.transform.rotation = Quaternion.Euler(Vector3.zero);
//获取所有网格过滤器
MeshFilter[] meshFilters = parent.GetComponentsInChildren();
//存放不同的材质球,相同的就存一个
Dictionary materials = new Dictionary();
//存放要合并的网格对象
Dictionary> combines = new Dictionary>();
for (int i = 0; i < meshFilters.Length; i++)
{
//构造一个网格合并结构体
CombineInstance combine = new CombineInstance();
//给结构体的mesh赋值
combine.mesh = meshFilters[i].sharedMesh;
combine.transform = meshFilters[i].transform.localToWorldMatrix;
MeshRenderer renderer = meshFilters[i].GetComponent();
if (renderer == null)
{
continue;
}
Material mat = renderer.sharedMaterial;
//将相同材质记录一次,再将拥有相同材质的mesh放到Dictionary中
if (!materials.ContainsKey(mat.name))
{
materials.Add(mat.name, mat);
}
if (combines.ContainsKey(mat.name))
{
combines[mat.name].Add(combine);
}
else
{
List coms = new List();
coms.Add(combine);
combines[mat.name] = coms;
}
}
GameObject combineObj = new GameObject(parent.name);
foreach (KeyValuePair mater in materials)
{
GameObject obj = new GameObject(mater.Key);
obj.transform.parent = combineObj.transform;
MeshFilter combineMeshFilter = obj.AddComponent();
combineMeshFilter.mesh = new Mesh();
//将引用相同材质球的网格合并
combineMeshFilter.sharedMesh.CombineMeshes(combines[mater.Key].ToArray(), true, true);
//Debug.LogError("网格定点数" + combineMeshFilter.sharedMesh.vertices);
MeshRenderer rend = obj.AddComponent();
//指定材质球
rend.sharedMaterial = mater.Value;
//需要设置请自行打开
//rend.shadowCastingMode = ShadowCastingMode.Off;
//rend.receiveShadows = true;
}
GameObject tar_Obj = null;
if (mergeAll)
{
tar_Obj = MergeMesh3(combineObj);
}
//还原坐标
tar_Obj.transform.position = initialPos;
tar_Obj.transform.rotation = initialRot;
GameObject.Destroy(parent);
return tar_Obj;
}
///
/// 模型点不能超过65535,材质相同也不会合并(一般外部不常调用,MergeMesh1、2函数更好)
///
public static GameObject MergeMesh3(GameObject parent, bool mergeSubMeshes = false)
{
MeshRenderer[] meshRenderers = parent.GetComponentsInChildren();
Material[] materials = new Material[meshRenderers.Length];
for (int i = 0; i < meshRenderers.Length; i++)
{
materials[i] = meshRenderers[i].sharedMaterial;
}
MeshFilter[] meshFilters = parent.GetComponentsInChildren();
CombineInstance[] combineInstances = new CombineInstance[meshFilters.Length];
for (int i = 0; i < meshFilters.Length; i++)
{
combineInstances[i].mesh = meshFilters[i].sharedMesh;
combineInstances[i].transform = meshFilters[i].transform.localToWorldMatrix;
}
GameObject mesh_obj = new GameObject(parent.name);
MeshFilter meshFilter = mesh_obj.AddComponent();
meshFilter.mesh.CombineMeshes(combineInstances, mergeSubMeshes);
MeshRenderer meshRenderer = mesh_obj.AddComponent();
meshRenderer.sharedMaterials = materials;
GameObject.Destroy(parent);
return mesh_obj;
}
}
}
using System.Collections.Generic;
using UnityEngine;
using CombineMeshes;
public class UsingMergeMesh : MonoBehaviour
{
[Header("示例1:AllMergeMesh")]
public GameObject MergeMeshGameObject;
[Header("示例2:PartMergeMesh请给父节点放入4个模型(若没有4个游戏对象,程序会报错)")]
public GameObject MergeMeshGameObject2;//
void Update()
{
//按下Enter键才会执行
if (Input.GetKeyDown(KeyCode.Return))
{
AllMergeMesh(MergeMeshGameObject);
}
//按下A键才会执行
if (Input.GetKeyDown(KeyCode.A))
{
PartMergeMesh(MergeMeshGameObject2);
}
}
///
/// 模型的整体合并网格
///
/// 父节点
///
GameObject AllMergeMesh(GameObject source_Obj)
{
Vector3 initialPos = source_Obj.transform.position;
Quaternion initialRot = source_Obj.transform.rotation;
GameObject clone_Obj = Instantiate(source_Obj);
GameObject cloneParents = new GameObject();
cloneParents.transform.position = initialPos;
cloneParents.transform.rotation = initialRot;
clone_Obj.transform.parent = cloneParents.transform;
#region<根据实际要求自行更改>
///
///自动分总点数超过65535点的模型,超过65535的点会有子集关系,且相同材质会合并
///
GameObject tar_Obj = Combinemeshes.MergeMesh1(cloneParents, true);//父节点有mesh
//tar_Obj = Combinemeshes.MergeMesh1(clone_F,false);//父节点无mesh
///
///模型总点数不能超过65535,且相同材质会合并,超过会报错:合并游戏对象的总点数超过65535
///
//tar_Obj = Combinemeshes.MergeMesh2(clone_F);
///
///模型总点数不能超过65535,材质相同也不会合并(一般不调用,MergeMesh2函数更好)
///
//tar_Obj = Combinemeshes.MergeMesh3(clone_F);
#endregion
tar_Obj.name = "AllMergeMesh";
return tar_Obj;
}
///
/// 模型的子集关系合并(这里做个示例,请给父节点放入4个模型)
///
/// 父节点
///
GameObject PartMergeMesh(GameObject source_Obj)
{
//获取父节点中的子物体
List source_ObjChild = new List();
for (int i = 0; i < source_Obj.transform.childCount; i++)
{
source_ObjChild.Add(source_Obj.transform.GetChild(i).gameObject);
}
GameObject tar_Obj = new GameObject(source_Obj.name);
GameObject gameObjects;//将gameObj实例化的对象,放入gameObjects子集中
List gameObj = new List();//实例化对象
//合并一
gameObjects = new GameObject(source_Obj.name);
gameObjects.transform.position = source_ObjChild[0].transform.localPosition;
gameObj.Add(Instantiate(source_ObjChild[0]));
gameObj.Add(Instantiate(source_ObjChild[1]));
for (int i = 0; i < gameObj.Count; i++)
{
gameObj[i].transform.parent = gameObjects.transform;
}
//这里我用的是MergeMesh1,可自行根据实际更改MergeMesh2、MergeMesh3
gameObjects = Combinemeshes.MergeMesh1(gameObjects);
gameObj.Clear();
gameObjects.transform.parent = tar_Obj.transform;
//合并二
gameObjects = new GameObject("joint");
gameObjects.transform.position = source_ObjChild[2].transform.localPosition;
gameObj.Add(Instantiate(source_ObjChild[2]));
gameObj.Add(Instantiate(source_ObjChild[3]));
for (int i = 0; i < gameObj.Count; i++)
{
gameObj[i].transform.parent = gameObjects.transform;
}
//这里我用的是MergeMesh1,可自行根据实际更改MergeMesh2、MergeMesh3
gameObjects = Combinemeshes.MergeMesh1(gameObjects);
gameObj.Clear();
gameObjects.transform.parent = tar_Obj.transform;
Vector3 initialPos = source_Obj.transform.position;
Quaternion initialRot = source_Obj.transform.rotation;
tar_Obj.transform.position = initialPos;
tar_Obj.transform.rotation = initialRot;
//设置父子关系
for (int i = 0; i < tar_Obj.transform.childCount; i++)
{
gameObj.Add(tar_Obj.transform.GetChild(i).gameObject);
}
for (int i = 1; i < gameObj.Count; i++)
{
gameObj[i].transform.parent = gameObj[i - 1].transform;
}
#region<根据需要请自行更改>
///
///父节点有mesh
///
gameObj[0].transform.parent = tar_Obj.transform.parent;
gameObj[0].name = "PartMergeMesh";
Destroy(tar_Obj);
return gameObj[0];
///
///父节点无mesh
///
//return tar_Obj;
#endregion
}
}
参考文章:
Unity 合并Mesh 将多个小的物体合并成一个大物体,同批次渲染_万兴丶的博客-CSDN博客_unity合并物体