延迟渲染(Deferred Rendering)的前生今世(一)

本文由@浅墨_毛星云 出品,转载请注明出处。
文章链接:https://blog.csdn.net/poem_qianmo/article/details/77142101

在计算机图形学中,延迟渲染( Deferred Rendering) ,即延迟着色(Deferred Shading),是将着色计算延迟到深度测试之后进行处理的一种渲染方法。延迟着色技术的最大的优势就是将光源的数目和场景中物体的数目在复杂度层面上完全分开,能够在渲染拥有成百上千光源的场景的同时依然保持很高的帧率,给我们渲染拥有大量光源的场景提供了很多可能性。

图1 使用Deferred Rendering方法渲染的多光源场景

这篇文章,就主要和大家一起聊一聊Deferred Shading和它的“前生今世”,以及文末简单提一提第八章“区域和环境光照 Area and Environmental Lighting”中的Environment Mapping(环境映射)相关的内容。

简而言之,通过阅读这篇文章,你将对以下要点有所了解:

  • 延迟着色/延迟渲染的概念 Deferred Shading / Deferred Rendering
  • 几何缓冲区 G-buffer
  • 延迟渲染的渲染过程
  • 延迟渲染 vs 正向渲染 Deferred Rendering vs Forward Rendering
  • 延迟渲染的优缺点
  • 延迟光照 Light Pre-Pass / Deferred Lighting
  • 分块延迟渲染Tile-Based Deferred Rendering
  • 延迟渲染 vs 延迟光照 Deferred Rendering vs DeferredLighting
  • 实时渲染中常见的Rendering Path总结
  • 环境映射Environment Mapping

一、延迟渲染 Deferred Rendering

延迟渲染( Deferred Rendering),即延迟着色(Deferred Shading),顾名思义,是将着色计算延后进行处理的一种渲染方法,在2004年的GDC上被正式提出http://www.tenacioussoftware.com/gdc_2004_deferred_shading.ppt

我们知道,正向渲染(Forward Rendering),或称正向着色(Forward Shading),是渲染物体的一种非常直接的方式,在场景中我们根据所有光源照亮一个物体,之后再渲染下一个物体,以此类推。

传统的正向渲染思路是,先进行着色,再进行深度测试。其的主要缺点就是光照计算跟场景复杂度和光源个数有很大关系。假设有n个物体,m个光源,且每个每个物体受所有光源的影响,那么复杂度就是O(m*n)。

正向渲染简单直接,也很容易实现,但是同时它对程序性能的影响也很大,因为对每一个需要渲染的物体,程序都要对每个光源下每一个需要渲染的片段进行迭代,如果旧的片段完全被一些新的片段覆盖,最终无需显示出来,那么其着色计算花费的时间就完全浪费掉了。

而延迟渲染的提出,就是为了解决上述问题而诞生了(尤其是在场景中存在大量光源的情况下)。

延迟着色给我们优化拥有大量光源的场景提供了很多可能性,因为它能够在渲染拥有成百上千光源的场景的同时还能够保持能让人接受的帧率。下面这张图展示了一个基于延迟着色渲染出的场景,这个场景中包含了1000个点光源,对于目前的硬件设备而言,用传统的正向渲染来实现几乎是不可能的。

图2 基于Deferred Rendering 渲染的含1000个点光源的场景 [J. Andersson, SIGGRAPH 2009 Beyond Programmable shading course talk] @ Frostbite 2引擎

可以将延迟渲染( Deferred Rendering)理解为先将所有物体都先绘制到屏幕空间的缓冲(即G-buffer,Geometric Buffer,几何缓冲区)中,再逐光源对该缓冲进行着色的过程,从而避免了因计算被深度测试丢弃的⽚元的着色而产⽣的不必要的开销。也就是说延迟渲染基本思想是,先执行深度测试,再进行着色计算,将本来在物空 间(三维空间)进行光照计算放到了像空间(二维空间)进行处理。

对应于正向渲染O(m*n)的 复杂度,经典的延迟渲染复杂度为O(n+m)。

图3 Unreal Engine 3中实现的Deferred Shading  @GDC 2011

Jimmikaelkael在2016年12月24日发推文(https://twitter.com/jimmikaelkael/status/812631802242273280),分享了一组在Unity3D中基于deferred shading渲染的SpeedTree场景,非常逼真:

图4 SpeedTree deferred shading with translucency @Unity3D引擎 by jimmikaelkael


图5 SpeedTree deferred shading with translucency @Unity3D引擎 by jimmikaelkael


图6 SpeedTree deferred shading with translucency @Unity3D引擎 by jimmikaelkael


图7 SpeedTree deferred shading with translucency @Unity3D引擎  by jimmikaelkael

延迟着色中一个非常重要的概念就是G-Buffer,下面先聊一下G-Buffer。

二、几何缓冲区 G-buffer

G-Buffer,全称Geometric Buffer ,译作几何缓冲区,它主要用于存储每个像素对应的位置(Position),法线(Normal),漫反射颜色(Diffuse Color)以及其他有用材质参数。根据这些信息,就可以在像空间(二维空间)中对每个像素进行光照处理。

图8 一个典型的G-buffer layout。Source: W. Engel, “Light-Prepass Renderer Mark III” @SIGGRAPH 2009Talks

下面是一帧中G-buffer中存储的内容:

图9 G-buffer存储的信息

三、延迟渲染的过程分析
 
可以将延迟渲染理解为两个Pass的过程:

1、几何处理阶段(Geometry Pass)。这个阶段中,我们获取对象的各种几何信息,并将第二步所需的各种数据储存(也就是渲染)到多个G-buffer中;

2、光照处理阶段(Lighting Pass)。在这个pass中,我们只需渲染出一个屏幕大小的二维矩形,使用第一步在G-buffer中存储的数据对此矩阵的每一个片段计算场景的光照;光照计算的过程还是和正向渲染以前一样,只是现在我们需要从对应的G-buffer而不是顶点着色器(和一些uniform变量)那里获取输入变量了。

下面这幅图片很好地展示了延迟着色的整个过程:

图10 延迟着色的过程

延迟渲染方法一个很大的好处就是能保证在G-buffer中的片段和在屏幕上呈现的像素所包含的片段信息是一样的,因为深度测试已经最终将这里的片段信息作为最顶层的片段。这样保证了对于在光照处理阶段中处理的每一个像素都只处理一次,所以我们能够省下很多无用的渲染调用。除此之外,延迟渲染还允许我们做更多的优化,从而渲染更多的光源。

在几何处理阶段中填充G-buffer非常高效,因为我们直接储存位置,颜色,法线等对象信息到帧缓冲中,这个过程几乎不消耗处理时间。

而在此基础上使用多渲染目标(Multiple Render Targets, MRT)技术,我们可以在一个Pass之内完成所有渲染工作。

总结一下,典型的Deferred Rendering 的渲染流程有两步:

1. 几何处理阶段:渲染所有的几何/颜色数据到G-buffer

2. 光照处理阶段:使用G-buffer计算场景的光照。

四、延迟渲染的伪代码

为了便于理解,这里贴出一些各种描述版本的延迟渲染算法的伪代码:

1、通用版本的延迟着色算法伪代码:

For each object:
	Render to multiple targets
For each light:
	Apply light as a 2D postprocess

2、一个通用版本的deferred shading过程描述:

“Standard”deferred shading is a 2-stage process:
(1) draw (opaque) geometry storing its attributes (i.e. position as depth,normals, albedo color, specular color and other material properties) in anumber of full screen buffers (typically 3 or 4)
(2) for each light source, draw its volume and accumulate lit surfacecolor into final render target

3、两个Pass的延迟着色算法伪代码:

Two-pass deferred shading algorithm
Pass 1: geometry pass
- Write visible geometry information to G-buffer
Pass 2: shading pass
For each G-buffer sample, compute shading
- Read G-buffer data for current sample
- Accumulate contribution of all lights
- Output final surface color

4、多光源的延迟渲染的伪代码:

Many-light deferred shading algorithm
For each light:
-Generate/bind shadow/environment maps
-Compute light’s contribution for each G-buffer sample:
For each G-buffer sample
-Load G-buffer data
-Evaluate light contribution (may be zero)
-Accumulate contribution into frame-buffer

可以将这里的多光源计算过程理解为,对每个光源创建一个屏幕空间包围矩形,然后用光照shader渲染这个矩形。

未完待续......

来源:CSDN,作者:浅墨_毛星云
原文:https://blog.csdn.net/poem_qianmo/article/details/77142101
版权声明:本文为博主原创文章,转载请附上博文链接!

最新文章