前提:美术很随意得使用贴图、材质,大量的材质虽然名称不同,但是实际上材质属性是相同的。
于是,在导出时,在依次处理材质时,应该将新的材质属性与已经收集到的材质进行对比,如果是相同的,则使用已存在的材质。
同时,虽然mesh中的submesh其实是根据MatID来作划分,但是一般情况下,mesh中的submesh的vertex decl通常是完全相同的。
那么其实可以将所有相同的vertex decl的submesh合并在同一个geometry(VB)中,submesh使用不同的index buffer来绘制,减少绘制时的VB切换。
于是,就有了shared geometry的共用,如果submesh的vertex decl与之不同(例如ABC是diffuseMap,DE是diffuseMap + specularMap,FGH是diffuseMap + specularMap + normalMap),则自己使用独立的geometry来绘制。
另外,还要对于mesh中所有的submesh所使用的material进行排序,以减少不必要的state切换。
而且还有一个好处是,material的数量、mesh的大小都会减少,意味着减少了磁盘IO和文件解析所需要的时间。
接下来,就是本文的重点出现了。
问题总有2个:
1. 想象中优化后的场景目录的文件数量和大小,都应该会相应减少。但实际中发现,的确大多数模型数据都减少了十几K到几十K不等,但是少数模型的mesh尺寸变大了。
这个现象很奇怪,为了分析原因,我使用了工具对两者进行了二进制对比。
有意思的是,变大的文件,例如之前的十六进制数据为: AB CD EF GH,变大的数据变成AB CD 00 00 EF GH 00 00。
经验告诉我,肯定是某些原先使用16bits描述的数值,现在变成32bits了。
相信朋友们已经猜到了原因,即合并submesh之前,每一个geometry大小都是65535以内,于是16bits IB就够了
合并之后,vertex数量超过了65535,于是我的导出插件自动切换为32bits IB来描述了
通过搜索资料,了解到10年前的GPU对于32bits IB的处理,除了带宽上略有影响之外,并不会有额外的性能惩罚
而随之优化带来的batch减少以及VB等state切换所带来的FPS提升,我的结论是这样的优化是值得的
进一步的优化思考是,我目前是使用的triangle list保存的IB,即一个face使用3个index;如果改为triangle trip,那么IB是很有可能控制在65535之内的
2. 美术不一定会将同一个物体的多个子物体合并(Attach),例如手机:显示屏幕、外壳、电池、天线,是分开为多个mesh存在,然后合成一个group。
这样子并不会影响实际使用中的操作,因为毕竟scene中还是有一个叫“手机”的node。
但是理论上,我们还是希望这几个物体合并在一起,甚至想到说,既然上述的material和geometry的优化,那为什么不把整个场景都在导出时自动merge到一起呢?
然后我想当然得写了一个maxscript,在导出之前会自动将场景中所有的mesh合并在一起。
但是实际情况是,虽然感觉上应该会更流畅,单个scene在观察时也会有些许提升,但是当画面是由多个scene分块构成时,camera frustum的cull就废掉了。
哪怕只有scene A的一棵小草被看到,整个scene都会被绘制出来,反而会影响到渲染效率。
优化无止境,同学需努力。