模型数据作渲染优化时遇到的问题
2014-03-22 00:12
369 查看
前提:美术很随意得使用贴图、材质,大量的材质虽然名称不同,但是实际上材质属性是相同的。
于是,在导出时,在依次处理材质时,应该将新的材质属性与已经收集到的材质进行对比,如果是相同的,则使用已存在的材质。
同时,虽然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都会被绘制出来,反而会影响到渲染效率。
优化无止境,同学需努力。
于是,在导出时,在依次处理材质时,应该将新的材质属性与已经收集到的材质进行对比,如果是相同的,则使用已存在的材质。
同时,虽然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都会被绘制出来,反而会影响到渲染效率。
优化无止境,同学需努力。
相关文章推荐
- 微信小程序遇到修改数据后页面不渲染的问题解决
- 关于Unity渲染优化,你可能遇到这些问题
- 使用ADO.net 实体数据模型遇到的问题
- Vue.js v-bind遇到的数据渲染问题
- 关于Unity渲染优化,你可能遇到这些问题
- linq更新部分数据时遇到的问题及解决办法
- 机器学习-数据挖掘遇到问题-考虑处理的方向
- ListView优化机制及滑动时数据时出现的数据错乱重复问题
- Chrome 渲染优化 - 层模型 当中缺少的图片
- VS2005+ACCESS2003开发中遇到的“标准表达式中数据类型不匹配”问题解决方法
- 关于EXP-00056: 遇到 ORACLE 错误 1455 ORA-01455: 转换列溢出整数数据类型 EXP-00000: 导出终止失败 的问题解决方法整理
- cocos2dx的RenderTarget渲染遇到模板缓冲(Stencil)出问题的解决方案
- Echarts 异步数据加载遇到的问题
- 2D纹理与3D模型共存时的渲染问题
- 请教大家一个问题:.net3.5的实体数据模型如何插入和编辑数据
- faster rcnn训练自己地数据时遇到地问题
- 解决spark中遇到的数据倾斜问题
- 带着5G数据的网站升级(1)--计数我遇到的问题
- EntiryFramework中事务操作(三)事务回滚数据模型和数据库不对应问题
- 遇到的问题-----------perl脚本用handlersocket把数据插入mysql执行时报错lock_tables