1、简介
     在计算机图形学的词典里,Shading表示“对受光物体的渲染”,这个渲染过程包括下面几步[1]:

1) 计算几何多边形(也就是Mesh)。
     2) 决定表面材质特性,例如法线、双向反射分布函数(bidirectional reflectance distribution function, BRDF)等等。
     3) 计算入射光照。
     4) 计算光照对表面的影响,并最终显示。

     一般渲染引擎,渲染场景中的物体的时候,是将这四步一次执行完的。延迟渲染则将前两步和后两步分开到渲染管道相互独立的两个部分来执行。
2、背景知识

     对比前向渲染(聚光灯的最简单的前向渲染见DirectX 9.0c的sample"Shadow Map"),前向渲染有多种问题[1]:

1) 计算每个几何体受那些光影响耗费了CPU的时间,更坏的是,这是个O(n*m)的操作。
     2) Shader经常需要超过一次以上的Pass来渲染光照,渲染n个灯光,对于复杂的Shader,可能需要O(n)次运算。
     3) 增加新的光照模型和新的光源类型,可能需要改变所有Effect的源文件。
     4) Shader很快就将达到或者超出SM2的指令限制。

     在MMO里,我们对游戏环境很少会有过于苛求的要求。我们无法控制同屏可见的玩家数量、无法控制同屏会有多少特效和光源。由于传统前向渲染缺乏对环境的控制,且对于光源的复杂度难于估量,因此我们选择了延迟渲染。这可以让我们的画面更接近于当今顶尖的游戏引擎,并且让光照所耗费的资源独立于场景的几何复杂度。
     延迟渲染提供了下面的好处:
     1) 光照所耗费的资源独立于场景复杂度,这样就不用再费尽心机去想着处理那些光源影响几何体了。
     2) 不必要再为几何体的受光提供附加的Pass了,这样就节省了Draw Call和状态切换的数量。
     3) 在增加新的光源类型和光照模型时,材质的Shader不需要做出任何改变。
     4) 材质Shader不产生光照,这样就节省了计算额外的几何体的指令数。
     延迟渲染需要显卡提供MRT的支持,且利用了不断增加的存储器的带宽——这也就意味着我们可能得对玩家所使用的硬件提出更高的要求。因此我们既实现了前向渲染,也实现了延迟渲染。我们优化了前向渲染管道,并在此基础上完成了延迟渲染管道。
3、基本原理
     目前我们看到最终画面都是2D的,只能看到有限的像素数,理论上我们只要处理(指光照,阴影处理)最终我们可以看到的点的效果就够了,多余的处理是浪费的。而正常的前向渲染(Forward Shading)流程是把空间的点进行各种剪裁后,进行处理,所处理量远远大于我们最终看到的。所以延迟渲染出现了。它先将摄像机空间的点光栅化转化成屏幕坐标后再进行处理。这样就能减少处理的次数,从而提高效率[5]。
     既然把处理流程放在了后面,那么处理所需要的参数也必须带到后面的流程。这里使用MRT(multi target render)就很重要,RT占用的显存越大,对显卡的的带宽要求也就越高,DX10支持8个MRT(DX11的MRT数量我没查到,在DX11的新特征中,也没有提到增加MRT,所以可能也是8个)。后面的处理至少需要空间位置信息,可以通过Depth(至少16位)获得,其他可以将法线信息(normal),高光信息(specular),AO系数,diffuse,自发光(emissive),材质编号等信息放入MRT中。
     延迟渲染管线可分为四个阶段(和第一节说的4个阶段有一些不同,只是某些功能进行不一样的划分而已,大致还是一样的):Geometry,Lighting, Composition, Post-processing[4],Post-processing阶段与传统的forward shading没有太大差别,这里不提,只说明一下前三个阶段。

1) Geometry阶段:将本帧所有的几何信息光栅化到G-buffer。包括位置,法线,贴图等。
     2) Lighting阶段:以G-buffer作为输入(位置,法线)进行逐像素的光照计算,将diffuse lighting和specular lighting 结果分别保存在两张RT上作为lighting buffer。
     3) Composition阶段:将G-buffer中的贴图buffer和lighting buffer融合,得到渲染结果。

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

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

  4.2、光照计算及相关优化
     使用延迟渲染技术最大的好处就是可以渲染光照极为复杂的场景。这里场景中的光照可以分为两类。影响整个场景的scenelight。如directionallight。渲染一个screenquad,逐像素光照计算,没什么好说的;另一类是只影响一部分区域的locallight,如点光源、聚光灯、和特效等等。这些locallight只影响到屏幕上的某些像素,当然不需要逐像素的进行光照计算。最简单的方法是绘制这些光源的包围体(点光源的包围体是球,聚光灯的包围体是圆锥),包围体的大小要大于等于光源的衰减范围。这些包围体经过变换投影到屏幕上的对应区域,随后在pixelshader中计算光照[3]。

优化:
     1.光源包围体的视锥剔除,遮挡剔除。
     2.光源包围体投影后很小时剔除;若干个靠的比较近的小光源合并成一个较大的光源
     3.光源包围体的backfaceculling
     4.屏幕空间中没有被光源照到的,或者被更近的物体遮挡住的像素不需要光照计算,因此可以逐像素的深度剔除。有两种方法:a.使用正确的stencillightvolume。类似shadowvolume的方案,将渲染lightvolume的正反两面,得到正确的stencilmask,然后光照计算时使用stencilbuffer。这种方法可以得到正确的结果,但是需要渲染每盏灯时频繁改变renderstate,可能会带来一定性能上的损失。b.使用ztest,可以得到“一定程度上正确”的结果。

  4.3、阴影计算
     光照计算的同时计算阴影。使用传统的shadowmap,预先生成一张阴影图(相关)。考虑在编辑场景的时候指定那些重要的光源才会产生阴影。在计算shadowmap时要针对光源的bindingvolume进行剔除[3]。

方向光和聚光灯可以使用基本的Shadow Map投影(正交投影,透视投影),点光源会复杂一些,需要使用Cube Shadow Map,由于较老的硬件不支持在不同纹理之间插值,使得不同纹理之间会有接缝(见[6] P171),在DX10中才支持Cube Map纹理之间的插值。

5、优缺点分析

     延迟渲染主要的好处包括[1,6]:
     1) 光照的开销与场景复杂度无关。
     2) Shader可以访问深度和其他像素信息。
     3) 每个象素对每个光源仅运行一次。也就是说,那些被遮挡的像素是不会被光照计算到的。
     4) 材质和光照的Shader完全分开。
     延迟渲染还需要克服的主要障碍包括:

1) 较高的显存带宽占用

   2) G-buffer消耗较多的填充率,这个问题在游戏机上比较严重
     3) 无硬件反锯齿的支持

     4) 对Alpha Blend支持较差
     解决方案:
     1) 我们发现当前驻留的显卡已经可以在稍低的分辨率下解决贷款问题了,而在当今最高端的机器上,可以在开启全部特性的前提下,适应更高的分辨率。在DX10 即便显卡上,ATI和NVIDIA都增强了MRT的性能。DX10和SM4都提供了GPU支持的整数处理,以及从深度缓冲中读取数据。所有这些都可以减少显存带宽。当提供了新的硬件和特性时,性能自然就会提升。
     2) 在合适的Filter作用下,精确的边缘检测可以减少几何体边缘的锯齿。虽然这些方法并不像硬件全场景反锯齿那样精确,但是仍然可以以假乱真。
     3) 对不透明物体采用延迟渲染,透明物体采用正向渲染,可以解决Alpha Blend的问题(Unity3D采用这种解决方案)。
 

PS:对某个具体项目的说明,包括其中的一些优化见资料[1],GPU GEMS2和3中都有这个引擎延迟渲染的文章,值得一看。

 
参考文献:
[6]Akenine-Möller T, Haines E, Hoffman N. Real-time rendering 3 [M]. 

Deferred Shading(延迟渲染)的更多相关文章

  1. Deferred Shading,延迟渲染(提高渲染效率,减少多余光照计算)【转】

    Deferred Shading,看过<Gems2> 的应该都了解了.最近很火的星际2就是使用了Deferred Shading. 原帖位置:   http://blog.csdn.net ...

  2. Deferred Shading延迟渲染

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

  3. Deferred Shading 延迟着色(翻译)

    原文地址:https://en.wikipedia.org/wiki/Deferred_shading 在3D计算机图形学领域,deferred shading 是一种屏幕空间着色技术.它被称为Def ...

  4. opengl deferred shading

    原文地址:http://www.verydemo.com/demo_c284_i6147.html 一.Deferred shading技术简介 Deferred shading是这样一种技术:将光照 ...

  5. Unity5 的新旧延迟渲染Deferred Lighting Rendering Path

    unity5 的render path ,比4的区别就是使用的新的deferred rendering,之前的4的deferred rendering(其实是light prepass)也被保留了下来 ...

  6. Deferred shading rendering path翻译

    Overview 概述 When using deferred shading, there is no limit on the number of lights that can affect a ...

  7. Unity的Deferred Shading

    什么是Deferred Shading Unity自身除了支持前向渲染之外,还支持延迟渲染.Unity的rendering path可以通过Edit/Project Settings中的Graphic ...

  8. DirectX11 With Windows SDK--36 延迟渲染基础

    前言 随着图形硬件变得越来越通用和可编程化,采用实时3D图形渲染的应用程序已经开始探索传统渲染管线的替代方案,以避免其缺点.其中一项最流行的技术就是所谓的延迟渲染.这项技术主要是为了支持大量的动态灯光 ...

  9. DirectX11 With Windows SDK--37 延迟渲染:光源剔除

    前言 在上一章,我们主要介绍了如何使用延迟渲染,以及如何对G-Buffer进行一系列优化.而在这一章里,我们将从光源入手,讨论如何对大量的动态光源进行剔除,从而获得显著的性能提升. 在此之前假定读者已 ...

随机推荐

  1. 4k 对齐,你准备好了吗?

    什么是 4k 对齐? 其实与 “ 4K对齐 ” 相关联的是一个叫做 “ 高级格式化 ” 的分区技术.“ 高级格式化 ” 是国际硬盘设备与材料协会为新型数据结构格式所采用的名称.这是主要鉴于目前的硬盘容 ...

  2. 查锁表及kill

    当一个表一直被锁住而无法进行操作的时候,可以用如下方法 select l.session_id sid, s.serial#, l.locked_mode 锁模式, l.oracle_username ...

  3. 【已解决】BeautifulSoup已经获得了Unicode的Soup但是print出来却是乱码

    [问题] 某人遇到的问题: 关于BeautifulSoup抓取表格及SAE数据库导入的问题(跪求大神帮忙) 简单说就是: 用如下代码: ? 1 2 3 4 5 6 7 import re,urllib ...

  4. 浅谈call和apply的联系&区别&应用匹配

    call和apply的联系和区别在之前查过资料了解了一番,昨天晚上睡不着觉忽然想到了这个问题,发现对于他们的联系和区别理解的还是很模糊.看来还是欠缺整理,知识没有连贯起来.反思一二,详情如下: 1作用 ...

  5. iPad accessory communication through UART

    We manufacture a new accessory for iPad/iPhone which should transfer commands to the iPad. We like t ...

  6. android 获取前台进程

    String getTopActivity() { ActivityManager manager = (ActivityManager)getSystemService(ACTIVITY_SERVI ...

  7. echo & print

    在实际使用中, print 和 echo 两者的功能几乎是完全一样.可以这么说,凡是有一个可以使用的地方,另一个也可以使用.但是,两者之间也还是一个非常重要的区别:在 echo 函数中,可以同时输出多 ...

  8. Ubuntu、Sql Server卸载心得

    这几天真是搞得亏大了! 首先是卸载Ubuntu,直接在Windows下格式化那个盘了,这就出岔子了……然后越来越糟糕,最后弄得一个系统都没有了……然后重装系统…… 然后装VS和Sql Server,因 ...

  9. 6.JAVA_SE复习(集合)

    集合 结构图: 总结: 1.集合中的元素都是对象(注意不是基本数据类型),基本数据类型要放入集合需要装箱. 2.set与list的主要区别在于set中不允许重复,而list(序列)中可以有重复对象. ...

  10. VS2010 常见错误总结

    错误一:“此时无足够的可用内存,无法满足操作的预期要求,可能是由于虚拟地址空间碎片造成的,请稍后重试” 安装VS2010补丁:http://xiazai.jb51.net/201007/tools/V ...