unity 3d 之合并网格和贴图(combine mesh and texture)

https://www.cnblogs.com/eangulee/p/3877824.html

 

unity 3d 之合并网格和贴图(combine mesh and texture)

 

  本人是个小白,但是有个做技术的理想。

  关于合并网格和贴图这个问题困扰了我好久,问群友,逛论坛,翻帖子,或者说是我的愚笨吧,不过经过努力还是我解决了,测试通过,一个8drawcall的模型,合并后降到2drawcall,当然现在移动设备的性能都比较高了,不必过多纠结于drawcall,如果没这需要请路过吧。。。

  好的,废话不多说,我把代码贴出来。

复制代码
  1 using UnityEngine;
  2 using System.Collections;
  3 using System.Collections.Generic;
  4 using System.IO;
  5 
  6 public class CombineMesher : MonoBehaviour
  7 {
  8     // Use this for initialization
  9     void Start()
 10     {
 11         Combine(transform);
 12     }
 13 
 14     // Update is called once per frame
 15     void Update()
 16     {
 17 
 18     }
 19 
 20 
 21     public Transform Combine(Transform root)
 22     {
 23         float startTime = Time.realtimeSinceStartup;
 24 
 25         // The SkinnedMeshRenderers that will make up a character will be
 26         // combined into one SkinnedMeshRenderers using one material.
 27         // This will speed up rendering the resulting character.
 28         // note:each SkinnedMeshRenderer must share a same material
 29         List<CombineInstance> combineInstances = new List<CombineInstance>();
 30         List<Material> materials = new List<Material>();
 31         Material material = null;
 32         List<Transform> bones = new List<Transform>();
 33         Transform[] transforms = root.GetComponentsInChildren<Transform>();
 34         List<Texture2D> textures = new List<Texture2D>();
 35         int width = 0;
 36         int height = 0;
 37 
 38         int uvCount = 0;
 39 
 40         List<Vector2[]> uvList = new List<Vector2[]>();
 41 
 42         foreach (SkinnedMeshRenderer smr in root.GetComponentsInChildren<SkinnedMeshRenderer>())
 43         {
 44             if (material == null)
 45                 material = Instantiate(smr.sharedMaterial) as Material;
 46             for (int sub = 0; sub < smr.sharedMesh.subMeshCount; sub++)
 47             {
 48                 CombineInstance ci = new CombineInstance();
 49                 ci.mesh = smr.sharedMesh;
 50                 ci.subMeshIndex = sub;
 51                 combineInstances.Add(ci);
 52             }
 53 
 54             uvList.Add(smr.sharedMesh.uv);
 55             uvCount += smr.sharedMesh.uv.Length;
 56 
 57             if (smr.material.mainTexture != null)
 58             {
 59                 textures.Add(smr.renderer.material.mainTexture as Texture2D);
 60                 width += smr.renderer.material.mainTexture.width;
 61                 height += smr.renderer.material.mainTexture.height;
 62             }
 63 
 64             // we need to recollect references to the bones we are using
 65             foreach (Transform bone in smr.bones)
 66             {
 67                 foreach (Transform transform in transforms)
 68                 {
 69                     if (transform.name != bone.name) continue;
 70                     bones.Add(transform);
 71                     break;
 72                 }
 73             }
 74             Object.Destroy(smr.gameObject);
 75         }
 76 
 77         // Obtain and configure the SkinnedMeshRenderer attached to
 78         // the character base.
 79         SkinnedMeshRenderer r = root.gameObject.GetComponent<SkinnedMeshRenderer>();
 80         if (!r)
 81             r = root.gameObject.AddComponent<SkinnedMeshRenderer>();
 82         
 83         r.sharedMesh = new Mesh();
 84 
 85         //only set mergeSubMeshes true will combine meshs into single submesh
 86         r.sharedMesh.CombineMeshes(combineInstances.ToArray(), true, false);
 87         r.bones = bones.ToArray();
 88         r.material = material;
 89 
 90         Texture2D skinnedMeshAtlas = new Texture2D(1024, 512);
 91         Rect[] packingResult = skinnedMeshAtlas.PackTextures(textures.ToArray(), 0);
 92         Vector2[] atlasUVs = new Vector2[uvCount];
 93 
 94         //as combine textures into single texture,so need recalculate uvs
 95 
 96         int j = 0;        
 97         for (int i = 0; i < uvList.Count; i++)
 98         {
 99             foreach (Vector2 uv in uvList[i])
100             {
101                 atlasUVs[j].x = Mathf.Lerp(packingResult[i].xMin, packingResult[i].xMax, uv.x);
102                 atlasUVs[j].y = Mathf.Lerp(packingResult[i].yMin, packingResult[i].yMax, uv.y);
103                 j++;
104             }
105         }
106         
107         r.material.mainTexture = skinnedMeshAtlas;
108         r.sharedMesh.uv = atlasUVs;
109 
110         Debug.Log("combine meshes takes : " + (Time.realtimeSinceStartup - startTime) * 1000 + " ms");
111         return root;
112     }
113 }
复制代码

转载于:https://www.cnblogs.com/nafio/p/9221650.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity中,可以使用以下代码将多个Mesh合并成一个,并导出为.obj格式的模型文件,同时包含其使用的材质和贴图: ```csharp // 获取需要合并的所有Mesh MeshFilter[] meshFilters = gameObject.GetComponentsInChildren<MeshFilter>(); // 创建新的Mesh 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; } Mesh newMesh = new Mesh(); newMesh.CombineMeshes(combineInstances); // 创建新的Material Renderer renderer = gameObject.GetComponent<Renderer>(); Material material = renderer.sharedMaterial; // 导出为.obj格式的模型文件 string path = "Assets/NewModel.obj"; ObjExporter.MeshToFile(newMesh, material, path); // 刷新AssetDatabase AssetDatabase.Refresh(); ``` 在上述代码中,首先获取需要合并的所有Mesh,并将其转换为CombineInstance数组。然后创建新的Mesh,使用CombineMeshes方法将CombineInstance数组合并成一个Mesh。接着获取需要导出的Material,并将其保存为一个新的Material。最后使用ObjExporter类中的MeshToFile方法将新的Mesh及其使用的Material和贴图导出为.obj格式的模型文件,并调用AssetDatabase.Refresh方法刷新AssetDatabase。 以下是修改后的ObjExporter类,支持将Mesh及其使用的Material和贴图导出为.obj格式的模型文件: ```csharp using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; public static class ObjExporter { public static void MeshToFile(Mesh mesh, Material material, string path) { StreamWriter sw = new StreamWriter(path); sw.WriteLine("# Unity Mesh"); sw.WriteLine("mtllib " + Path.GetFileNameWithoutExtension(path) + ".mtl"); sw.WriteLine("g default"); for (int i = 0; i < mesh.vertices.Length; i++) { Vector3 v = mesh.vertices[i]; sw.WriteLine(string.Format("v {0} {1} {2}", -v.x, v.y, v.z)); } for (int i = 0; i < mesh.normals.Length; i++) { Vector3 n = mesh.normals[i]; sw.WriteLine(string.Format("vn {0} {1} {2}", -n.x, n.y, n.z)); } for (int i = 0; i < mesh.uv.Length; i++) { Vector2 uv = mesh.uv[i]; sw.WriteLine(string.Format("vt {0} {1}", uv.x, uv.y)); } for (int i = 0; i < mesh.subMeshCount; i++) { int[] triangles = mesh.GetTriangles(i); for (int j = 0; j < triangles.Length; j += 3) { int i1 = triangles[j] + 1; int i2 = triangles[j + 1] + 1; int i3 = triangles[j + 2] + 1; sw.WriteLine(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}", i1, i2, i3)); } } sw.Close(); // 导出Material和贴图 string mtlPath = Path.GetDirectoryName(path) + "/" + Path.GetFileNameWithoutExtension(path) + ".mtl"; StreamWriter mtlSw = new StreamWriter(mtlPath); mtlSw.WriteLine("# Unity Material"); mtlSw.WriteLine("newmtl default"); mtlSw.WriteLine(string.Format("map_Kd {0}", Path.GetFileName(material.mainTexture.name))); mtlSw.Close(); string texPath = Path.GetDirectoryName(path) + "/" + material.mainTexture.name; File.Copy(AssetDatabase.GetAssetPath(material.mainTexture), texPath, true); } } ``` 在上述代码中,MeshToFile方法接受一个Mesh、一个Material和一个文件路径作为参数,将Mesh及其使用的Material和贴图导出为.obj格式的模型文件并保存到指定文件路径下。在导出过程中,先将Material和贴图保存到.mtl和对应的文件中,再将Mesh的顶点、法线、UV等信息以及使用的Material的引用保存到.obj文件中。 需要注意的是,上述代码中的StreamWriter类和Path类需要使用System.IO命名空间,因此需要在代码中添加以下语句: ```csharp using System.IO; ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值