版本:Unity5.3.3
Unity自带了合并Mesh的功能,最简单的做法就是在Root节点勾选static选项,它的原理就是运行时合并。但是最近我在开发的时候就遇到了问题,因为我们场景非常庞大,Mesh的顶点不能超65535所以Unity会自动把合并的mesh分成了很多分mesh,总之顶点都小于65535。
在IOS上测试都是正常的,可是在有些Android机器是场景就出问题了。就是渲染不正确,所以得到的结论就是不能完全依赖Unity的合并Mesh功能。再说Mesh合并的太大一样会带来性能的影响。所以我就在想能不能有策略性的合并Mesh.答案肯定是可行的,比如我根据gameObject的位置找出50米之内的MeshRender然后进行合并。如果是运行时合并,为了避免大量查找所带来的性能消耗,可以在Editor下提前把需要合并的mesh序列化在场景里。 在场景加载的Awake里进行合并。
我在说说另一种生成文件的方式。今天我想说的就是把有些mesh提前合并成.asset文件,直接写在unity工程里。网上我找到了一些别的文章,但都是要生成一个全新的大mesh,然后把之前的小mesh全都隐藏了。我感觉没有unity原有的方式好,因为假如原有的gameObject上挂了一些脚本, 这样一隐藏脚本也就失去了某些意义。。而且还不能单独的显示/隐藏某一个特定的mesh。
如下图所示,美术把所有的mesh都放在了Root节点下面。每一个MeshFilter都应该是美术自己创建的FBX里的。
我现在想做的就是,把某些MeshFilter合并,生成一个新的Mesh,并且要直接修改在原有的MeshFilter上的mesh。如下图所示,最终的结果。
为了避免重名我会根据当前场景的路径在平级目录下生成一个文件夹,把生成的mesh文件放进去。并且替换原有meshFilter上的mesh文件。
下面是我的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
using UnityEngine; using System.Collections; using UnityEditor; using UnityEditor.SceneManagement; using System.IO; public class CreateMesh { [MenuItem("Tools/create")] static void Start1 () { GameObject root = GameObject.Find("Root"); if(root) { MeshRenderer [] meshRenderers = root.GetComponentsInChildren<MeshRenderer>(); GameObject [] gos = new GameObject[meshRenderers.Length]; for(int i = 0; i< meshRenderers.Length;i++) { gos[i] =meshRenderers[i].gameObject; } string scenePath = EditorSceneManager.GetSceneAt(0).path; string meshScenePath = scenePath.Replace(".unity","_mesh"); string fullPath = Path.Combine(Directory.GetCurrentDirectory(),meshScenePath); if(Directory.Exists(fullPath)) Directory.Delete(fullPath,true); Directory.CreateDirectory(fullPath); string assetPath = FileUtil.GetProjectRelativePath(fullPath); StaticBatchingUtility.Combine(gos,root); for(int i =0; i< gos.Length; i++) { Mesh mesh = gos[i].GetComponent<MeshFilter>().sharedMesh; string meshPath = AssetDatabase.GetAssetPath(mesh); if(string.IsNullOrEmpty(meshPath)) { string path = Path.Combine(assetPath,Random.Range(int.MinValue,int.MaxValue) +".asset"); AssetDatabase.CreateAsset(mesh,path); } } } AssetDatabase.Refresh(); EditorSceneManager.MarkAllScenesDirty(); } } |
StaticBatchingUtility.Combine 这方法有两个重载
1.参数root节点。这样使用起来就有点限制了, 因为美术就得提前放需要合并的mesh放在一个规定的节点下。假如我想把一个节点合并成多个 mesh就不行了。
2.参数是 数组 和一个顶层节点。 这个用起来就方便多了。我可以把我需要合并的gameObject放在一个数组里,然后给他们指定一个节点就行了。(指定在地图的顶层节点上就行了)
最后欢迎大家一起讨论。 目前我还是在 运行时合并 和 提前合并 中拿捏不定!!
- 本文固定链接: https://www.xuanyusong.com/archives/4180
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
lightmap问题如何解决?
lightmap问题能不能解决呢
大神 我使用static void start()为什么脚本就不起作用了? 不设为静态方法就能运行脚本 但是合并失败?
Couldn’t create asset file!UnityEditor.AssetDatabase:CreateAsset(Object, String)老师这是为什么?
我也遇到这个问题了,你解决了吗?
合并模型后,lightmap就显示不正常了,有没有解决的思路?
老师 问下为啥勾选为static的的网格打包之后,再加载,这些static的网格不会自动合并呢
你说的打包是什么打包 ? 安装包 ? 还是 uniypackage 还是 assetbundle
assetbundle包,我之前场景里面勾选static的建筑,打到assetsbundle里面,然后从里面再加载出来,static属性并补起作用。。。
static属性是记录在scene上的。 所以打成ab在加载就不起作用了。但是你可以用 StaticBatchingUtility.Combine 动态合并
谢谢
另外请教老师一个问题,如果把很多小模型预先合成了一个大模型,如果多个场景使用这些小模型,那么我们的资源体积不就变大了么,那么如果这样,让美术来合并不是更好么。。
SimpleLod 非常好用,已购买并试用于项目,雨松想做测试可以找我要这个插件
我用过这个插件, 不太好后来放弃了。。
新版本还可以,只不过前期对美术的要求会变高
謝謝,這是我需要的知道的代碼Mesh mesh = gos .GetComponent().sharedMesh;string meshPath = AssetDatabase.GetAssetPath(mesh);
因为要重复利用资源,所以用StaticBatchingUtility.Combine合并,并且会移动。我的做法是ab包读取一份到内存后,生成出来的第一个GameObject go1合并了,然后用合并好的go1 instance出新的GameObject(因为要同时渲染3个相同的东西,如果合并3次的话,网格占内存太大了)。这样出现了一个问题,就是合并出来的物体,有部分模型,在不同的摄像机距离、角度下显示异常(就是不显示了)。编译器正常、安卓真机会出现这种情况。着色器换了默认的、把合并体细化为小的。都没有效果。
lightmap也会有问题。。 我的做法是只有静态 物体才会合并批次。。
lightmap我是动态贴上去的,每生成一个,都会对新的模型贴一遍。实时生成StaticBatchingUtility.Combine的时候卡顿严重,我有4个大模型(里面有30-40个模型)。合批后,每个都是2m的网格,每个合批3次就是4*2*3=24M内存,如果能用合批后的模型去创建,内存就是4*2*1=8M。真机测试是可以实现的。就是不知道为什么用合批后的模型去创建,大模型里面的部分模型(大概5、6个的样子,而且的固定的那几个模型,模型设置也和其他的一样)会闪烁。
这样合并之后,视野内的面数应该会增加吧。之前我们的美术把很多物件都合并到一起了,但是导致视野内的面数很高(500K左右),dc数倒是不多(100左右)。请问,面数对性能的影响大不大啊,合并物件的程度是不是也有个平衡,不是合并的越多越好?
我现在是导出场景的时候 合并50米之内的。。
多谢momo回答!!!
还有个问题,能帮看一下么。就是unity合并mesh有什么条件么,为什么我的场景物件在运行游戏之后,不能成功合并呢(static已经勾选了)?
有问题的,合并之后,那个mesh不能正常显示的
我最近已经被搞疯了,合并贴图,计算uv,动态合并蒙皮,需要合并的东西好多啊
把Mesh合并的目的是什么?
减少drawcall