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. SQLite的查询

    using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...

  2. 初识CSS3之媒体查询(2015年05月31日)

    一.什么是媒体查询 媒体查询是面向不同设备提供不同样式的一种实现方式,它可以为每种类型的用户提供最佳的体验,也是响应式设计的实现方式. 现今每天都有更多的手机和平板电脑问市.消费者能够拥有可想象到的各 ...

  3. kafka集群安装与配置

    一.集群安装 1. Kafka下载: 可以从kafka官方网站(http://kafka.apache.org)上找到下载地址,再wgetwget http://mirrors.cnnic.cn/ap ...

  4. sql server 2008 查询语句的红色波浪线

    在 Microsoft sql server management studio 里点击“编辑”——“IntelliSense”——“刷新本地缓存” 就会发现红色波浪线没了(前提是你的代码没错)

  5. JAVA生成EXCEL图表

    跟据客户的要求,需要开发一套包括图形的报表,还需要导出WORD 图表需要这样: 这样: 这样: 还有这样: 接下来是实现思路: 以往用的最多的就是JFreechart,手上也有实现各种图形的资源,但是 ...

  6. OC1_协议语句

    // // Programmer.h // OC1_协议语句 // // Created by zhangxueming on 15/6/24. // Copyright (c) 2015年 zhan ...

  7. jquery实现2级联动

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. spring中得到servletContext对象方法

    1.spring得到servletContext,这个和session没有什么关系,上下文可以说是一个session容器,一个上下文可以有多个会话session 在web.xml中有以下配置后.加入s ...

  9. windows 配置免安装 node

    1.下载 node.exe; 2.下载npm并解压;(NPM是一个Node包管理和分发工具) 3.创建单独文件夹 nodejs,将1.2步中的两个文件和一个文件夹放进该新建文件夹; 4.配置环境变量中 ...

  10. Navicat for mysql linux 破解方法

    安装方法   进入下载页面:http://www.navicat.com.cn/download/navicat-for-mysql ,选择Linux版本进行下载,下载后解压安装包,运行 start_ ...