Unity合并mesh,【CombineMeshes】将多个物体合并成一个物体或层级关系的物体

您所在的位置:网站首页 zb怎么把模型合成一个整体 Unity合并mesh,【CombineMeshes】将多个物体合并成一个物体或层级关系的物体

Unity合并mesh,【CombineMeshes】将多个物体合并成一个物体或层级关系的物体

2024-02-23 16:08| 来源: 网络整理| 查看: 265

 Unity3D将多个物体合并一个物体或层级关系的物体 一、三种合并工具 1.MergeMesh1:

(效率低,适应性高)模型点超过65535自动分模型,一个mesh上有多个材质会自动分出来成为子集部分,父节点要有mesh则 fatherMesh = true;

2.MergeMesh2:

(效率快、适应性低)模型点不能超过65535,超过会报错,且相同材质才会合并,若一个mesh上有多个材质会少一些材质(也就是丢失了一部分模型)

3.MergeMesh3:

(适应性极低)模型点不能超过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 = 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 } } 三、使用方法  1.创建如下测试示例模型,拖入框中

 

 2.创建好的模型如下  3.点击Enter和A键就会得到如下合并后的模型,合并后模型与原模型位置是重合的,为了方便大家看清合并的模型,我将它们移了出来。

 

 参考文章:

Unity 合并Mesh 将多个小的物体合并成一个大物体,同批次渲染_万兴丶的博客-CSDN博客_unity合并物体



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3