[Unity学习教程] Unity合并mesh,【CombineMeshes】将多个物体合并成一个物体或层级关系的物

[复制链接]
查看2685 | 回复3 | 2023-8-23 12:13:24 | 显示全部楼层 |阅读模式 来自 中国北京
 Unity3D将多个物体合并一个物体或层级关系的物体

一、三种合并工具

1.MergeMesh1:

(服从低,顺应性高)模子点超过65535主动分模子,一个mesh上有多个材质会主动分出来成为子集部分,父节点要有mesh则 fatherMesh = true;
2.MergeMesh2:

(服从快、顺应性低)模子点不能超过65535,超过会报错,且雷同材质才会集并,若一个mesh上有多个材质会少一些材质(也就是丢失了一部分模子)
3.MergeMesh3:

(顺应性极低)模子点不能超过65535,超过会报错 ,材质雷同也不会集并(一般外部不常调用,MergeMesh1、2函数更好)
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace CombineMeshes
  5. {
  6.     ///<summary>
  7.     ///注意:MergeMesh2、3只能针对于mesh上只有一个材质
  8.     /// </summary>
  9.     public static class Combinemeshes
  10.     {
  11.         /// <summary>
  12.         /// (效率低,适应性高)模型点超过65535自动分模型,一个mesh上有多个材质会分出来成为子集部分,父节点要有mesh则 fatherMesh = true;
  13.         /// </summary>
  14.         public static GameObject MergeMesh1(GameObject parent, bool fatherMesh = true)
  15.         {
  16.             //获取原始坐标
  17.             Vector3 initialPos = parent.transform.position;
  18.             Quaternion initialRot = parent.transform.rotation;
  19.             //将模型坐标归零
  20.             parent.transform.position = Vector3.zero;
  21.             parent.transform.rotation = Quaternion.Euler(Vector3.zero);
  22.             List<GameObject> list = new List<GameObject>();
  23.             int verts = 0;
  24.             //存放要合并的父物体  
  25.             Dictionary<int, GameObject> NewParent = new Dictionary<int, GameObject>();
  26.             //获取所有网格过滤器
  27.             MeshFilter[] meshFilters = parent.GetComponentsInChildren<MeshFilter>();
  28.             //通过游戏对象的总点数/65536,进行分组
  29.             for (int i = 0; i < meshFilters.Length; i++)
  30.             {
  31.                 verts += meshFilters[i].mesh.vertexCount;
  32.             }
  33.             for (int i = 1; i <= (verts / 65536) + 1; i++)
  34.             {
  35.                 GameObject wx = new GameObject("child" + i);
  36.                 wx.transform.parent = parent.transform;
  37.                 NewParent.Add(i, wx);
  38.             }
  39.             verts = 0;
  40.             int key = 1;
  41.             //给超过65535点的游戏对象进行分组
  42.             for (int i = 0; i < meshFilters.Length; i++)
  43.             {
  44.                 verts += meshFilters[i].mesh.vertexCount;
  45.                 if (verts >= 65535)
  46.                 {
  47.                     key++;
  48.                     verts = 0;
  49.                     verts += meshFilters[i].mesh.vertexCount;
  50.                 }
  51.                 //key= (verts / 65536) + 1;
  52.                 if (NewParent.ContainsKey(key))
  53.                 {
  54.                     meshFilters[i].transform.parent = NewParent[key].transform;
  55.                 }
  56.                 //else
  57.                 //    Debug.Log("错误");
  58.             }
  59.             //处理多材质(一个mesh上有多个材质)
  60.             if (meshFilters[0].GetComponent<MeshRenderer>().sharedMaterials.Length > 1)
  61.             {
  62.                 list.Add(GameObject.Instantiate(meshFilters[0].gameObject));
  63.             }
  64.             //
  65.             foreach (var item in NewParent)
  66.             {
  67.                 list.Add(MergeMesh3(item.Value, false));
  68.             }
  69.             //处理多材质
  70.             for (int i = 1; i < meshFilters.Length; i++)
  71.             {
  72.                 if (meshFilters[0].GetComponent<MeshRenderer>().sharedMaterials.Length > 1)
  73.                 {
  74.                     for (int j = 0; j < list[0].transform.childCount; j++)
  75.                     {
  76.                         GameObject.Destroy(list[0].transform.GetChild(j).gameObject);
  77.                     }
  78.                     GameObject.Destroy(meshFilters[0].gameObject);
  79.                 }
  80.                 if (meshFilters[i].GetComponent<MeshRenderer>().sharedMaterials.Length > 1)
  81.                 {
  82.                     list.Add(GameObject.Instantiate(meshFilters[i].gameObject));
  83.                     GameObject.Destroy(meshFilters[i].gameObject);
  84.                 }
  85.             }
  86.             //
  87.             GameObject tar_Obj = null;
  88.             //是否父节点上有mesh
  89.             if (!fatherMesh)
  90.             {
  91.                 tar_Obj = new GameObject();
  92.                 tar_Obj.name = "clone_F";
  93.                 for (int i = 0; i < list.Count; i++)
  94.                 {
  95.                     list[i].gameObject.transform.parent = tar_Obj.transform;
  96.                 }
  97.                 //还原坐标
  98.                 tar_Obj.transform.position = initialPos;
  99.                 tar_Obj.transform.rotation = initialRot;
  100.             }
  101.             //父节点上无mesh
  102.             else
  103.             {
  104.                 for (int i = 1; i < list.Count; i++)
  105.                 {
  106.                     list[i].gameObject.transform.parent = list[0].gameObject.transform;
  107.                     list[i].gameObject.name = "child" + i;
  108.                 }
  109.                 //还原坐标
  110.                 list[0].gameObject.transform.position = initialPos;
  111.                 list[0].gameObject.transform.rotation = initialRot;
  112.             }
  113.             GameObject.Destroy(parent);
  114.             return fatherMesh ? list[0] : tar_Obj;
  115.         }
  116.         /// <summary>
  117.         ///(效率快、适用性低)模型点不能超过65535,且相同材质会合并
  118.         /// </summary>
  119.         public static GameObject MergeMesh2(GameObject parent, bool mergeAll = true)
  120.         {
  121.             //获取原始坐标
  122.             Vector3 initialPos = parent.transform.position;
  123.             Quaternion initialRot = parent.transform.rotation;
  124.             //将坐标归零
  125.             parent.transform.position = Vector3.zero;
  126.             parent.transform.rotation = Quaternion.Euler(Vector3.zero);
  127.             //获取所有网格过滤器
  128.             MeshFilter[] meshFilters = parent.GetComponentsInChildren<MeshFilter>();
  129.             //存放不同的材质球,相同的就存一个
  130.             Dictionary<string, Material> materials = new Dictionary<string, Material>();
  131.             //存放要合并的网格对象
  132.             Dictionary<string, List<CombineInstance>> combines = new Dictionary<string, List<CombineInstance>>();
  133.             for (int i = 0; i < meshFilters.Length; i++)
  134.             {
  135.                 //构造一个网格合并结构体
  136.                 CombineInstance combine = new CombineInstance();
  137.                 //给结构体的mesh赋值
  138.                 combine.mesh = meshFilters[i].sharedMesh;
  139.                 combine.transform = meshFilters[i].transform.localToWorldMatrix;
  140.                 MeshRenderer renderer = meshFilters[i].GetComponent<MeshRenderer>();
  141.                 if (renderer == null)
  142.                 {
  143.                     continue;
  144.                 }
  145.                 Material mat = renderer.sharedMaterial;
  146.                 //将相同材质记录一次,再将拥有相同材质的mesh放到Dictionary中
  147.                 if (!materials.ContainsKey(mat.name))
  148.                 {
  149.                     materials.Add(mat.name, mat);
  150.                 }
  151.                 if (combines.ContainsKey(mat.name))
  152.                 {
  153.                     combines[mat.name].Add(combine);
  154.                 }
  155.                 else
  156.                 {
  157.                     List<CombineInstance> coms = new List<CombineInstance>();
  158.                     coms.Add(combine);
  159.                     combines[mat.name] = coms;
  160.                 }
  161.             }
  162.             GameObject combineObj = new GameObject(parent.name);
  163.             foreach (KeyValuePair<string, Material> mater in materials)
  164.             {
  165.                 GameObject obj = new GameObject(mater.Key);
  166.                 obj.transform.parent = combineObj.transform;
  167.                 MeshFilter combineMeshFilter = obj.AddComponent<MeshFilter>();
  168.                 combineMeshFilter.mesh = new Mesh();
  169.                 //将引用相同材质球的网格合并
  170.                 combineMeshFilter.sharedMesh.CombineMeshes(combines[mater.Key].ToArray(), true, true);
  171.                 //Debug.LogError("网格定点数" + combineMeshFilter.sharedMesh.vertices);
  172.                 MeshRenderer rend = obj.AddComponent<MeshRenderer>();
  173.                 //指定材质球
  174.                 rend.sharedMaterial = mater.Value;
  175.                 //需要设置请自行打开
  176.                 //rend.shadowCastingMode = ShadowCastingMode.Off;
  177.                 //rend.receiveShadows = true;
  178.             }
  179.             GameObject tar_Obj = null;
  180.             if (mergeAll)
  181.             {
  182.                 tar_Obj = MergeMesh3(combineObj);
  183.             }
  184.             //还原坐标
  185.             tar_Obj.transform.position = initialPos;
  186.             tar_Obj.transform.rotation = initialRot;
  187.             GameObject.Destroy(parent);
  188.             return tar_Obj;
  189.         }
  190.         /// <summary>
  191.         /// 模型点不能超过65535,材质相同也不会合并(一般外部不常调用,MergeMesh1、2函数更好)
  192.         /// </summary>
  193.         public static GameObject MergeMesh3(GameObject parent, bool mergeSubMeshes = false)
  194.         {
  195.             MeshRenderer[] meshRenderers = parent.GetComponentsInChildren<MeshRenderer>();
  196.             Material[] materials = new Material[meshRenderers.Length];
  197.             for (int i = 0; i < meshRenderers.Length; i++)
  198.             {
  199.                 materials[i] = meshRenderers[i].sharedMaterial;
  200.             }
  201.             MeshFilter[] meshFilters = parent.GetComponentsInChildren<MeshFilter>();
  202.             CombineInstance[] combineInstances = new CombineInstance[meshFilters.Length];
  203.             for (int i = 0; i < meshFilters.Length; i++)
  204.             {
  205.                 combineInstances[i].mesh = meshFilters[i].sharedMesh;
  206.                 combineInstances[i].transform = meshFilters[i].transform.localToWorldMatrix;
  207.             }
  208.             GameObject mesh_obj = new GameObject(parent.name);
  209.             MeshFilter meshFilter = mesh_obj.AddComponent<MeshFilter>();
  210.             meshFilter.mesh.CombineMeshes(combineInstances, mergeSubMeshes);
  211.             MeshRenderer meshRenderer = mesh_obj.AddComponent<MeshRenderer>();
  212.             meshRenderer.sharedMaterials = materials;
  213.             GameObject.Destroy(parent);
  214.             return mesh_obj;
  215.         }
  216.     }
  217. }
复制代码
 
二、调用合并工具 

  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using CombineMeshes;
  4. public class UsingMergeMesh : MonoBehaviour
  5. {
  6.     [Header("示例1:AllMergeMesh")]
  7.     public GameObject MergeMeshGameObject;
  8.     [Header("示例2:PartMergeMesh请给父节点放入4个模型(若没有4个游戏对象,程序会报错)")]
  9.     public GameObject MergeMeshGameObject2;//
  10.     void Update()
  11.     {
  12.         //按下Enter键才会执行
  13.         if (Input.GetKeyDown(KeyCode.Return))
  14.         {
  15.             AllMergeMesh(MergeMeshGameObject);
  16.         }
  17.         //按下A键才会执行
  18.         if (Input.GetKeyDown(KeyCode.A))
  19.         {
  20.             PartMergeMesh(MergeMeshGameObject2);
  21.         }
  22.     }
  23.     /// <summary>
  24.     /// 模型的整体合并网格
  25.     /// </summary>
  26.     /// <param name="source_Obj">父节点</param>
  27.     /// <returns></returns>
  28.     GameObject AllMergeMesh(GameObject source_Obj)
  29.     {
  30.         Vector3 initialPos = source_Obj.transform.position;
  31.         Quaternion initialRot = source_Obj.transform.rotation;
  32.         GameObject clone_Obj = Instantiate(source_Obj);
  33.         GameObject cloneParents = new GameObject();
  34.         cloneParents.transform.position = initialPos;
  35.         cloneParents.transform.rotation = initialRot;
  36.         clone_Obj.transform.parent = cloneParents.transform;
  37.         #region<根据实际要求自行更改>
  38.         ///<summary>
  39.         ///自动分总点数超过65535点的模型,超过65535的点会有子集关系,且相同材质会合并
  40.         ///</summary>
  41.         GameObject tar_Obj = Combinemeshes.MergeMesh1(cloneParents, true);//父节点有mesh
  42.         //tar_Obj = Combinemeshes.MergeMesh1(clone_F,false);//父节点无mesh
  43.         ///<summary>
  44.         ///模型总点数不能超过65535,且相同材质会合并,超过会报错:合并游戏对象的总点数超过65535
  45.         ///</summary>
  46.         //tar_Obj = Combinemeshes.MergeMesh2(clone_F);
  47.         ///<summary>
  48.         ///模型总点数不能超过65535,材质相同也不会合并(一般不调用,MergeMesh2函数更好)
  49.         ///</summary>
  50.         //tar_Obj = Combinemeshes.MergeMesh3(clone_F);
  51.         #endregion
  52.         tar_Obj.name = "AllMergeMesh";
  53.         return tar_Obj;
  54.     }
  55.     /// <summary>
  56.     /// 模型的子集关系合并(这里做个示例,请给父节点放入4个模型)
  57.     /// </summary>
  58.     /// <param name="source_Obj">父节点</param>
  59.     /// <returns></returns>
  60.     GameObject PartMergeMesh(GameObject source_Obj)
  61.     {
  62.         //获取父节点中的子物体
  63.         List<GameObject> source_ObjChild = new List<GameObject>();
  64.         for (int i = 0; i < source_Obj.transform.childCount; i++)
  65.         {
  66.             source_ObjChild.Add(source_Obj.transform.GetChild(i).gameObject);
  67.         }
  68.         GameObject tar_Obj = new GameObject(source_Obj.name);
  69.         GameObject gameObjects;//将gameObj实例化的对象,放入gameObjects子集中
  70.         List<GameObject> gameObj = new List<GameObject>();//实例化对象
  71.         //合并一
  72.         gameObjects = new GameObject(source_Obj.name);
  73.         gameObjects.transform.position = source_ObjChild[0].transform.localPosition;
  74.         gameObj.Add(Instantiate(source_ObjChild[0]));
  75.         gameObj.Add(Instantiate(source_ObjChild[1]));
  76.         for (int i = 0; i < gameObj.Count; i++)
  77.         {
  78.             gameObj[i].transform.parent = gameObjects.transform;
  79.         }
  80.         //这里我用的是MergeMesh1,可自行根据实际更改MergeMesh2、MergeMesh3
  81.         gameObjects = Combinemeshes.MergeMesh1(gameObjects);
  82.         gameObj.Clear();
  83.         gameObjects.transform.parent = tar_Obj.transform;
  84.         //合并二
  85.         gameObjects = new GameObject("joint");
  86.         gameObjects.transform.position = source_ObjChild[2].transform.localPosition;
  87.         gameObj.Add(Instantiate(source_ObjChild[2]));
  88.         gameObj.Add(Instantiate(source_ObjChild[3]));
  89.         for (int i = 0; i < gameObj.Count; i++)
  90.         {
  91.             gameObj[i].transform.parent = gameObjects.transform;
  92.         }
  93.         //这里我用的是MergeMesh1,可自行根据实际更改MergeMesh2、MergeMesh3
  94.         gameObjects = Combinemeshes.MergeMesh1(gameObjects);
  95.         gameObj.Clear();
  96.         gameObjects.transform.parent = tar_Obj.transform;
  97.         Vector3 initialPos = source_Obj.transform.position;
  98.         Quaternion initialRot = source_Obj.transform.rotation;
  99.         tar_Obj.transform.position = initialPos;
  100.         tar_Obj.transform.rotation = initialRot;
  101.         //设置父子关系
  102.         for (int i = 0; i < tar_Obj.transform.childCount; i++)
  103.         {
  104.             gameObj.Add(tar_Obj.transform.GetChild(i).gameObject);
  105.         }
  106.         for (int i = 1; i < gameObj.Count; i++)
  107.         {
  108.             gameObj[i].transform.parent = gameObj[i - 1].transform;
  109.         }
  110.         #region<根据需要请自行更改>
  111.         ///<summary>
  112.         ///父节点有mesh
  113.         /// </summary>
  114.         gameObj[0].transform.parent = tar_Obj.transform.parent;
  115.         gameObj[0].name = "PartMergeMesh";
  116.         Destroy(tar_Obj);
  117.         return gameObj[0];
  118.         ///<summary>
  119.         ///父节点无mesh
  120.         /// </summary>
  121.         //return tar_Obj;
  122.         #endregion
  123.     }
  124. }
复制代码
三、利用方法

 1.创建如下测试示例模子,拖入框中

 
 2.创建好的模子如下

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


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

来源:https://blog.csdn.net/weixin_48388330/article/details/127588694
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

FrankJScott | 2025-5-20 11:43:20 | 显示全部楼层 来自 英国

Great AI Stock Predictions Analysis Tips

To the person talking about open ai on the stock market, ai stock investing, stock market study, free stock predictor, using ai for day trading, stock app that tells you when to buy and sell, best online stock analysis tools, best app for analysing stocks, stock picking tools, stock analyzer tool,  I highly recommend this read this post here about AI stock trading analysis advice or ai forecast stock, stock trading help, stock analysis websites free, best free app for stock analysis, best application for stock analysis, best sites for stock, chat gpt stocks to buy, ai stock news today, stocks in trading, stock market stock investment, not to mention this directory about AI stock investing analysis link bearing in mind best stock trading tools, stock tools for analysis, best app for analysing stocks, ai trading software cost, best ai investments, investing with ai, best tools to analyze stocks, best place to analyze stocks, openai stock buy, stock chart predictor, alongside all this more tips here on AI stock trading platform url which is also great. Also, have a look at this top rated AI stock predictions platform tips which is worth considering with investing in open ai, best stocks in ai, best app for stock market prediction, ai stock futures, ai bot stock trading, stock price analysis tools, best software for stock market analysis, free stock forecast tool, stock market prediction software, ai companies on stock market, as well as this updated AI stock investing platform details bearing in mind stock trading and investing, best technical analysis website, chat gpt stock trading, stock app that tells you when to buy and sell, ai for stock market prediction,  do you agree on and don't forget stock market tools software, free stock market advice, stock trading advice, trade stocks with ai, bot stock trading,  for good measure. Check more @ Cool Pyeongtaek Business Massage Website c6043b3
回复

使用道具 举报

FrankJScott | 2025-5-27 09:28:12 | 显示全部楼层 来自 英国

Updated DVLTOTO Info

For the person inquiring about game pg soft terbaik, judi slot adalah, provider slot online terbaik, akun judi slot terpercaya, rekomendasi situs judi online, link game slot online terbaik, agen judi, link togel dan slot terpercaya, game online yang, judi slot online,  I highly suggest this new DVLTOTO advice or slot pragmatic play, indonesia slot online, spadegaming slot online, permainan online terbaru, permainan spadegaming, pg soft login, judi bola, yang bisa main game, aplikasi togel online terpercaya, login casino, not forgetting sites such as this top rated DVLTOTO link together with microgaming slot, permainan slot pragmatic yang mudah menang, slot situs baru, situs bandar online, link judi togel terpercaya, game slot online, link slot terpercaya di indonesia, judi toto, slot login, situs judi casino, on top of this new DVL TOTO tips which is also great. Also, have a look at this find on DVL TOTO info not to mention permainan pg soft, website judi slot terpercaya, slot link alternatif, main casino online, situs judi terbesar dan terpercaya, rupiah slot link alternatif, situs game slot, situs slot terbesar, game judi online slot, bandar togel online terbesar dan terpercaya, bearing in mind this updated DVLTOTO blog together with situs resmi judi online, game togel terpercaya, agen bandar togel terpercaya, bandar togel slot online, togel slot login,  use this link about which is worth considering with pg slot online, bandar slot online terbesar, online terpercaya, game judi slot online uang asli, situs slot terbesar di indonesia,  for good measure. Check more @ High Rated Tajir4D Link Alternatif Tips 1d047ad
回复

使用道具 举报

FrankJScott | 2025-5-28 01:04:27 | 显示全部楼层 来自 英国

High Rated House Cleaning Service Blog

For the man asking about carpet setting, lots of rugs in one room, carpet for carpet floor, carpet into rug, turn carpet into rug, types of rugs, best quality wall to wall carpet, hand stitched rugs, interior design rugs living room, wall to wall carpet stores near me,  I highly recommend this clicking here for house cleaning service details or house carpet ideas, patterned carpet, room size rugs, carpet rights, floor carpet for shop, a living room rug, types of rugs designs, carpet us, area area rugs, rug over a carpet, not forgetting sites such as this his explanation on house cleaning service advice on top of beautiful rugs, types of carpet designs, rug design styles, carpet with leaf pattern, hall carpet design, custom area rugs near me, handcrafted carpets, carpet space rug, rugs and flooring, custom house rugs, together with this awesome house cleaning service blog which is also great. Also, have a look at this go to the website for house cleaning service site which is worth considering with custom rug company, cool carpets for living room, differences between carpet and rug, making a custom rug, tufted floor rug, packing carpet, making a rug by hand, carpet flammability standards, the rug company logo, wall design carpet, not to mention this a fantastic read on house cleaning service site as well as appropriate rug size for living room, interior design carpet ideas, area rug with leaf pattern, rugs for living room floor, best rugs to go over carpet,  straight from the source for as well as house of carpets and floors, best places for cheap rugs, living room rugs, carpet with a rug, carpet rugs,  for good measure. Check more @ Updated TAJIR4D Info 7ad46_9
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则