• Deferred Shading


      传统的渲染过程通常为:1)绘制Mesh;2)指定材质;3)处理光照效果;4)输出。传统的过程Mesh越多,光照处理越费时,多光源时就更慢了。

          延迟渲染的步骤:1)Pass0先不做光照处理,将Mesh的Position信息和Normal信息绘制到纹理(RenderTargets,D3D支持多向输出);2)Pass1仅绘制屏幕大小的一个四边形,利用之前得到的Position纹理和Normal纹理对有效地区域选择性地进行光照处理,再输出最后的图像。

         分析:由于延迟渲染将光照的处理量由空间转换到了平面,减少了光照等效果的计算量,提高了绘制速度,对多光源的绘制优势更为明显。

     

    渲染流程

    延迟渲染管线可分为四个阶段:geometry, lighting, composition, post-processing

    Post-processing阶段与传统的forward shading没有太大差别,这里不提,只说明一下前三个阶段。

    Geometry阶段:将本帧所有的几何信息光栅化到G-buffer。包括位置,法线,贴图等。

    Lighting阶段:以G-buffer作为输入(位置,法线)进行逐像素的光照计算,将diffuse lightingspecular

    Lighting 结果分别保存在两张RT上作为lighting buffer

    Composition阶段:将G-buffer中的贴图bufferlighting buffer融合,得到渲染结果。

    整体渲染过程并不复杂,但在实际的过程中还是有许多问题需要考虑的,下面一一列举。

    G-buffer

    Geometry阶段将几何信息渲染到multi render target上(MRT),当前最多支持4MRT。并且驱动要求4MRT必须相同的bit宽度。RT对显存占用过大会增加带宽,降低cache命中。而简单格式的RT又会影响画质。因此决定使用32bitRT(如A8R8G8B8R16G16F)或64bit宽度的RT(如A16R16G16B16F)。需要在画质和性能间做出折衷。(开发时尽可能可以方便的配置)。[1]中有一些性能比较。

    MRT中必须的信息:position(depth), normal, diffuse(texture)

    可能需要的信息:specular, power, emissive, ao, material id

    这些信息需要在这4RT上用合理格式,合理的组织。这里还可以就存储空间和shader的复杂性做折衷。如只保存depth,然后在光照时计算position[12]。以及用球面坐标保存法线[13]。以目前的资料得出的结论是应该尽可能地pack数据,减少内存占用,多出来的若干条shader指令不会明显影响性能。

     

    光照计算

    使用延迟渲染技术最大的好处就是可以渲染光照极为复杂的场景。这里场景中的光照可以分为两类。

    影响整个场景的scene light。如directional light。渲染一个screen quad,逐像素光照计算,没什么好说的。

    另一类是只影响一部分区域的local light。如点光源,聚光灯,以及特效等等。这些local light只影响到屏幕上的某些像素,当然不需要逐像素的进行光照计算。最简单的方法是绘制这些光源的包围体(点光源的包围体是球,聚光灯的包围体是圆锥),包围体的大小要大于等于光源的衰减范围。这些包围体经过变换投影到屏幕上的对应区域,随后在pixel shader中计算光照。

    优化:

    1.       光源包围体的视锥剔除,遮挡剔除。

    2.       光源包围体投影后很小时剔除;若干个靠的比较近的小光源合并成一个较大的光源[11]

    3.       光源包围体的backface culling

    4.       屏幕空间中没有被光源照到的,或者被更近的物体遮挡住的像素不需要光照计算,因此可以逐像素的深度剔除。

    a.       使用正确的stencil light volume。类似shadow volume的方案,将渲染light volume的正反两面,得到正确的stencil mask,然后光照计算时使用stencil buffer。这种方法可以得到正确的结果,但是需要渲染每盏灯时频繁改变render state,可能会带来一定性能上的损失。

    使用z test,可以得到“一定程度上正确”的结果。

     

    阴影

    光照计算的同时计算阴影。使用传统的shadow map,预先生成一张阴影图。考虑在编辑场景的时候指定那些重要的光源才会产生阴影。在计算shadow map时要针对光源的binding volume进行剔除。

    方向光和聚光灯可以使用基本的shadow map投影(正交投影,透视投影)。点光源会复杂一些,需要使用cubic shadow map。(考虑unwrapping method[14]

    半透明

    由于在延迟渲染的过程中只计算离屏幕距离最近的那个像素的光照,因此无法处理半透明物体的光照。

    方案1

    延迟渲染的过程中只处理不透明的物体,将所有半透明的物体放在渲染过程的最后,使用传统的forward shading渲染。

    方案2

    Geometry阶段将半透明的物体和背景逐像素的交织起来,将透明度放在一个单独的通道中。按一般的方法计算光照。随后在composition阶段再根据透明度将透明物体和背景逐像素的混合起来。

    优点:

    光照一致性。半透明的物体也参加延迟渲染,可以接受多光源的光照。

    简单并且健壮。不需要单独区分不透明物体和半透明物体,不需要单独的半透明渲染管道。

    速度快。只增加了710ps指令,两张贴图,只有约2%的性能损失。

    缺点:

    模糊。在半透明的物体上会有一点模糊,原因是在交织的过程中会有一定信息损失。

    边缘锯齿。反交织的过程中半透明物体的边缘会产生一些锯齿。

    只能有一层半透明。

    多种材质

    在延迟光照的过程中支持多种材质需要如下方案:

    G-buffer阶段输出材质的IDG-buffer的一个通道中,随后在lighting阶段和composition阶段根据材质ID使用不同的光照函数计算光照。这种方案在sm 3.0中使用动态分支的前提下可以很好的工作。

    反锯齿

    Dx9 API不支持反锯齿的MRTDx10支持。

    一种方案是使用超采样,先渲染到大的RT上,再downsample到正常的大小,得到没有锯齿的结果。延迟渲染的效率跟分辨率有很大关系,因此这种方法会极大的降低性能,基本不可取。

    另一种方案是使用“intelligent blur”,只模糊物体边缘的像素

    根据相邻像素的深度和法线提取物体边界,然后对提取出的边界进行模糊。模糊时要避免不正确的泄露。如后面物体的颜色泄露到前面的物体上[11] 总体而言实现会较为复杂。

    另一种方案pre-lighting [8][9][17]

    一种pre-z rendering deferred rendering的结合。G-buffer阶段只保存depthnormal,然后计算光照信息到lighting buffer,格式如下

    LightColor.r * N.L * Att
    LightColor.g * N.L * Att
    LightColor.b * N.L * Att
    R.V^n * N.L * Att

    最后使用传统的forward shading再将整个场景渲染一遍,期间查询lighting buffer

    与普通的deferred shading相比:

    优点:

    占用带宽小,第一遍渲染只输出normaldepth是自动获得的。

    可以用在较老的硬件平台上,不需要MRT支持。

    对现有forward shading管道改动较小,比较容易实现。

    缺点:

    整个场景需要渲染两遍,相当于在pre-zforward shading中间加了一个lighting stage

  • 相关阅读:
    easy ui 表单ajax和from两种提交数据方法
    easy ui 下拉级联效果 ,下拉框绑定数据select控件
    easy ui 下拉框绑定数据select控件
    easy ui 异步上传文件,跨域
    easy ui 菜单和按钮(Menu and Button)
    HTTP 错误 404.3
    EXTJS4.2 后台管理菜单栏
    HTML 背景图片自适应
    easy ui 表单元素input控件后面加说明(红色)
    EXTJS 4.2 添加滚动条
  • 原文地址:https://www.cnblogs.com/RenderLife/p/2730654.html
Copyright © 2020-2023  润新知