Unity 2018.3.5f1
项目中经常存在很多Material只是贴图不一样的情况,不同的Material是需要单独一个DrawCall来提交数据渲染这个对象的,比如下面场景中五个Cube对象,每个Cube对象使用了一个单独的Material,其中各自的Material只有贴图不一样。因为每个Cube使用了独立的Material,渲染花费了五个DrawCall:
如果我们把这些贴图合并到一张大的贴图中去(参考Unity贴图合并工具),然后让那些仅仅是贴图不一样的Material都使用这个合并后的大贴图。针对每个模型修改自己的UV,让Mesh的UV匹配到合并后的大贴图。这样这些模型就可以使用相同的Material了,Unity对使用相同的Material渲染的Mesh会进行动态合批(dynamic batching)。这样游戏运行时这五个Cube只需要一个DrawCall消耗了。进一步思考,dynamic batching可以在运行时刻开辟一块内存把这些分散的Mesh合并到一个新的Mesh中去,我们干脆直接在资源层面将这些Mesh合并,这样还节省运行时刻的内存。这办法可行,下面介绍下一个简单的Mesh合并工具的实现过程。
需要合并Mesh我们需要先了解其数据结构,一个Mesh文件基本组成部分:
- 顶点(vertex):表示位置的坐标
- 面(triangles):顶点连接起来形成的面
- UV :贴图的坐标
- 颜色(color):模型的附带颜色
- 法线(normal):每个面的垂直线
两个独立的Mesh文件,我们只需要把它们这些信息合并就可以得到一个新的Mesh。这个新的Mesh包含了两者的信息。第一步获取这些信息:
1 |
|
或者了所有的Mesh信息之后,正如文章开头所说,这些Mesh使的Material仅仅是贴图不一样的Material。这里事先利用Unity 贴图合并工具把这些需要合并的Mesh的所用到的渲染其的Material的贴图合并到一张大贴图中去。
现在需要的是渲染合并之后的Mesh用到的一个Material,这个Material的的贴图用的是合并之后的大贴图,Material的其他属性和未合并的Mesh所用的Material的属性是相同的,创建一个这样的Material供之后生成合并的Mesh使用:
1 |
|
然后合并Mesh生成一个新的Mesh即可:
1 |
|
上面代码第60行有个处理需要注意下,就是合并之后的Mesh使用合并之后的Atlas之后,Mesh对应的UV需要重新计算下。比如说一张256x256的贴图TexA合并到了一张1024x1024的图集中,那么使用TexA的Mesh需要修改下UV。如下图所示:
最后,合并之后的Mesh的效果:
现在渲染这五个Cube只需要一个DrawCall即可。