• 三维场景的渲染优化


    (一) 有效的性能评测
                             
    对于任何一个3D应用程序来说,追求场景画面真实感是一个无止尽的目标,其结果就是让我们的场景越来越复杂,模型更加精细,这必然给图形硬件带来极大的负荷以致于无法达到实时绘制帧率。因此,渲染优化是必不可少的。在渲染优化之前,我们需要对应用程序性能进行系统的评测,找出瓶颈,对症下药。对于3D应用程序来说,影响性能的十分多,同时不同的硬件配置条件下,瓶径也会有所不同。因此,对应用程序进行有效的性能评测,不仅需要对整个渲染管线原理有深入地了解,此外借助一些评测工具能让我们的工作事倍功半。

    我们知道渲染流水线的速度是由最慢的阶段决定首先,因此对一个3D应用程序进行评测,首先要分析影响渲染性能的瓶颈是在CPU端还是GPU端,由此来绝对我们优化的对象。由于目前的图形加速硬件都具有强大的,这个瓶径往往出现在CPU端,我们可以通过一些工具获得这个信息,如Nvidia的NVPerfHUD。在评测选项中,我们可以查看CPU和GPU繁忙度这项,当CPU繁忙度是100%时,GPU还不是时,我们知道性能的瓶颈在CPU端,我们必须CPU端的操作,同时尽量的“喂饱”GPU,把一些费事的计算移值到GPU上,例如硬件骨骼蒙皮。当GPU端是瓶颈时,说明GPU超荷负载,有可能是因为有过多的渲染填充,也就是多边形数量太多(当前强大的GPU使得这种情况并不多见。

    CPU上的瓶颈产生有两个方面,一是因为复杂AI计算或低效的代码,二是由于不好的渲染批处理或资源管理。对于第一种情况,我们可以利用VTurn这类的工具,把应用程序中所有函数调用时间从大到小的排列出来,我们就很容易知道问题所在。对第二种情况来说,同样利用NVPerfHUD,我们可以查看每帧的DP数目,看看批的数量是否过多(有一个具体的换算公式),查看纹理内存的数目,是否消耗了过多的显存。利用这些工具,我们基本上能够定位应用程序的瓶颈。在应用程序内部,编写一个内嵌的profiler功能,能更加便利的进行评测,此外利用Lua这样的脚本程序,让我们运行时调试,也能提高评测的效率。

    (二) 静态场景优化
       

    静态场景包括了地形、植被、建筑物等一般不改变位置的实体集合,对它的优化是场景优化中最重主要的内容。本文就静态场景优化的常见问题进行了探讨。

    1 批的优化

    批是场景优化中的最重要的概念之一,它指的是一次渲染调用(DP),批的尺寸是这次渲染调用所能渲染的多边形数量。每个批的调用都会消耗一定的CPU时间,对于显卡来说,一个批里的多边形数量远达不到最大绘制数量。因此尽可能将更多的多边形放在一个批里渲染,以此来减少批的数目,最终降低CPU时间,是批的优化基本原则。然而事情往往不尽如人意,有些情况下原有的批会被打破,造成额外的开销,如纹理的改变或不同的矩阵状态。针对这些问题,我们可以采用一些方法来尽量避免它,已达到批尺寸的最大化。

    (1)合并多个小纹理为一张大纹理     

    在某个场景中,地面上有十多种不同的植被,它们除了纹理不同外,渲染状态都是一样。我们就可以把它们的纹理打包成一个大纹理,再为每个植被模型指定UV,这样我们就可以用一个渲染调用来渲染所有的物体,批的数量就从十多个降为一个。这种方法比较适合对纹理精度要求不高,面数不会太多的物体。

    (2)利用顶点shader 来统一不同矩阵的情况   

    即使场景中的所有物体材质都一样,如果它们的矩阵状态不同(特别是场景图管理的引擎),也会打碎原有的批。利用顶点shader技术可以避免这种情况,因为可以把要乘的变换矩阵通过常量寄存器传到shader程序中,这样统一了物体的矩阵状态,可以放在一个批里渲染。

    2 渲染状态管理

    渲染状态是用来控制渲染器的渲染行为,在D3D中是setRenderState,通过改变渲染状态,我们可以设置纹理状态、深度写入等等。改变渲染状态对显卡来说,是个比较耗时的工作,因为显卡执行API必须严格按照渲染路径,当渲染状态变化时,显卡就必须执行浮点运算来改变渲染路径,因此给CPU和GPU带来时间消耗(CPU必须等待),渲染状态变化越大,所要进行的浮点运算越多。因此将渲染状态进行有效的管理,尽可能 减少其变化,对渲染性能影响巨大。(新六代的显卡Geforce8系列中将一些常见的状态参数集存储在显卡核心中,当渲染状态状态发生变化,可以直接读取保存的参数集,以消除不必要的开销)。绝大部分的3D引擎都会按照渲染状态对PASS进行分组渲染。

    3 LOD

    LOD这个已经被人讨论烂掉的技术我就不多废话了,简单谈谈一些实际应用。地形的LOD我就不多说了,方法太多了,不过感觉目前情况下最实用的还是连锁分片的方法。对于模型LOD,自动减面的算法,如VDPM(渐近网格子)并不少见,但是效果都很一般。常规的做法还是让美工做低模进行替换,对于复杂场景来说,模型LOD的效果还是比较明显的。材质LOD就需要一些技巧,例如可以将雾后的物体,包括地形等统一成一种材质,采用雾的颜色,这样就统一了渲染状态,至于是否要打包成一个DP就要看具体情况了(这个统一的材质最好把光照影响关掉,这也是比较费时的)。至于角色模型的LOD和普通模型LOD相类似,低模减少了顶点数,自然减少了蒙皮计算量。个人认为骨骼LOD不是特别的必要,看具体的情况。

    4 场景管理的优化

    场景管理的优化包括场景分割,可见性剔除等,有很多的参考文章,这里就不多说了,谈些个人的心得。现在的室外场景一般采用quadtree或octree,当我们在性能评测时发现遍历树的过程比较慢时,有可能有两个原因。一是树的深度设置的不合理,我们可以很容易寻找到一个最佳的深度。另一个原因可能是我们为太多数量 众多,但体积很小的物体分配了结点,造成结点数量的冗余。解决方法是把这些小物体划分到他们所在的大的结点中。

    可见性剔除是最常见优化方法,我们常用的是视锥裁减,这也是非常有效的。视锥裁减也是许多优化方法,这里就不详说了。遮挡裁减也是经常被用到的方法,常见的有地平线裁减。但是在有些情况下,遮挡裁减的效果并不明显,如当CPU使用率已经是100%时,CPU端是瓶颈,这时进行遮挡裁减计算消耗CPU时间,效果就不明显。但是有些情况下利用一些预生成信息的方法,降低遮挡裁减计算的复杂度,提高遮挡裁减计算的效率,对场景性能会一定的改善。
  • 相关阅读:
    Windows下安装并设置Redis
    OpenGL纹理上下颠倒翻转的三种解决办法
    如何计算android设备的屏幕物理尺寸
    VS2010中使用QtOpenGL出现 unresolved external symbol __imp__glClear@4 referenced in function之类的错误
    VC运行库版本不同导致链接.LIB静态库时发生重复定义问题的一个案例分析和总结
    7月份文章回顾
    NSIS脚本根据操作系统版本动态决定默认安装目录
    WinDriver的一些
    〔池化纲领〕也及链表
    多道程序设计〕协程构造
  • 原文地址:https://www.cnblogs.com/lizhengjin/p/2471608.html
Copyright © 2020-2023  润新知