前言
unity引擎中渲染代价的指标是场景中网格(Mesh)的数量,对显卡来说渲染一个100面的物体和渲染一个1500面的物体几乎是等价的,于是当多个物体的材质(Shader)相同时,可以把他们的网格合并起来,然后共用一个材料(Material)来降低渲染的成本,达成优化游戏体验的效果。
这里我们把对材料的共用模糊化了,其实这也是一个复杂的过程,后文中会详细描述其原理和算法。
什么样的物体可以合并?
场景中有那么多物体,在进行合并之前,我们需要先确定哪些物体是可以合并在一起的?
1.shader相同的物体才可以合并
观察物体的属性面板,我们发现物体可能有不同的材料,这些材料会有不同的shader。shader是也是使用编程语言编写的由gpu处理的,不同的shader渲染出的效果是不一样的。因为我们合并起来的物体的网格是一个合并的网格,使用的是合并的材料,每个材料只能有一个shader属性,这也就限制了我们要合并的物体的材料的shader必须要相同。
2.要合并的物体需要处于一定范围内
多个物体合并了之后,成为一个物体,若这个物体的mesh分布在场景中的各个地方,无疑是对资源的一个浪费。极端地来说,若我们将一万个物体合并成了一个,摄像机所看到了这一万个之中的一个,其他九千九百九十九个虽然对玩家不可见,但因为是同一个物体,所以也渲染了出来,这样的资源浪费是无必要的。
于是我们在合并之前会将场景划分为多个正方体,每个正方体内的物体才能互相合并在一起,以此避免合并出来物体的mesh分散的情况。
3.物体的光照贴图需要相同(lightmapindex属性相同)
一个很General的算法
变量的数据结构及意义
在此处先将mesh合并整个过程的大体算法描述出来,细节部分在后篇展开解释。
当然在描述算法前,先说明算法中用到的变量的数据结构及其意义:
List<MeshFilter> AllMeshFiltersInScene : 场景中所有meshfilter的链表
List<MeshRender> AllMeshRenderersInScene : 场景中所有meshrenderer的链表
List<GameObject> AllGameobjectsInScene : 场景中所有Gameobject的链表
Dictionary<Shader, Dictionary<Texture2d, List<int>> ShaderToTextures : 场景中所有的Shader到其贴图的映射(在合并之前,所有贴图都是贴在材料之上的,这些材料有自己的Shader,就视为这个贴图的Shader。只有Shader相同的贴图才能打包到一个图集中,他们的mesh才能合并在一起)
List<List<Gameobjcet>> CubesOfGameobjects : 场景中的正方体数组,里面存着这个正方体里的物体
Dictionary<Gameobject, int> GameObjectToIndex : 建立物体到其索引的映射
算法
1.FindAllMeshesInScene : 找到场景中所有MeshFilter组件,存在AllMeshFiltersInScene,据其还可以获得带这个组件的物体存在AllGameobjectsInScene 以及这个物体的其他有用组件如MeshRenderer存在AllMeshRenderersInScene
2.PackAllTexturesInScene && DividingTextures: 将场景内所有的贴图打包成若干个图集(图集,即是贴图的集合;如前所述,Mesh合并之后多个物体成为一个物体,这个物体使用的是一个合并的Mesh,合并的材料,这个合并的材料当然就有一个合并的贴图集合,即为图集)
3.DoCombine : 遍历场景内的每个正方体,对其内的物体进行合并条件判断后,分组进行合并