在这篇文章中,会分析和对比三种渲染算法:
- 前向渲染(Forward Rendering)
- 延迟着色(Deferred Shading)
- Forward+(基于Tile的前后渲染)
介绍
前向渲染
前向渲染是通过在场景中光栅化每个几何对象来工作的,在着色过程中,通过迭代每个灯光来决定该几何对象如何被照亮,这意味着每个几何对象都需要考虑场景中的所有灯光。当然,我们也可以通过舍弃被遮挡的或在相机的视椎体内不可见的几何对象来进行优化,我们也可以通过舍弃不在相机视椎体的内的灯光来进一步优化。如果灯光的范围是已知的,我们可以在进行场景几何体的渲染之执行光椎的剔除。对象剔除和光椎剔除只能为前向渲染提供有限的优化,并且灯光剔除通常在前向渲染中是不可行的。减少场景中影响场景对象的灯光数量更为常见,例如,有些图形引擎每个像素执行两到三个的光照,以及每个顶点执行三到四个的光照。在传统的由OpenGL和DirectX提供的固定渲染管线中,场景中激活的动态灯光数量被限制到8个,即使是现代的图形硬件,在可以感知的帧率问题发生之前,前向渲染管线中动态场景灯光也被限制到100个。
延迟着色 (Deferred shading)
另一方面,延迟着色通过将所有的(无光照)场景对象光栅化到一系列的2D纹理缓冲区,该纹理缓冲区存储了后续的光照pass中需要的几何信息,2D纹理缓冲区中存储的信息包括:
- 屏幕空间深度
- surface的法线
- diffuse颜色
- 高光(specular)颜色和高光因子(specular power)
图1
这些纹理构成了G-Buffer: Diffuse(左上),高光(右上),法线(左下)和深度(右下),高光因子存储在高光纹理(右上)的alpha通道。
这些2D纹理缓冲区的组合也称为几何缓存区或G-Buffer[1]。
如果后续执行光照需要也可以将其它信息存储到纹理缓冲区,但如果每个像素点32个bit,在1080P上至少需要8.29M的纹理内存。
G-Buffer被生成后,几何信息可以在光照pass中用来计算光照信息,在光照pass中每个光源都被当作一个几何对象被执行,每个与灯光所表示的几何体相交的像素都使用期望的光照方程进行着色。
相比于前向渲染,延迟渲染的优势是昂贵的光照计算只对每个光源及其覆盖的像素计算一次。使用现代硬件只渲染不透明物体时,延迟渲染技术可以在1080P分辨率下处理2500个动态场景灯光,而不会有帧率问题的发生。
延迟渲染的一个劣势是只有不透明物体可以被光栅化到G-Buffer,原因是多个半透明对象可以覆盖同一个屏幕像素,而G-Buffer中每个像素只可以存储一个值。在光照Pass中,深度值,表面法线,diffuse颜色和高光色被当前的屏幕像素所采样来进行光照,因为每个G-Buffer只能采样一个值,透明物体不能光照pass中被支持。为了绕过这个问题,透明几何体必须使用标准的前向渲染技术进行渲染,可以限制场景中透明物体的数量或动态光源的数量。只包含不透明物体的场景可以处理大约2000个动态光源而不会发生帧率问题。
延迟渲染的另一个劣势是只能在光照pass中模拟一个光照模型,这是因为在渲染灯光几何体时只能绑定一个像素着色器(pixel shader)。当使用ubershader(把所有的计算都放到一个shader)时,这通常不会是一个问题。然而,如果你的渲染管线在多个像素着色器中使用不同的光照模型,通过切换渲染管线来执行延迟渲染是会有问题的。
Forward+
Forward+[2][3],也称为基于Tile的前向渲染,是结合了前向渲染和基于tile灯光剔除来减少着色过程中灯光数量的一种渲染技术,Forward+主要包含两个阶段:
- 灯光剔除(Light culling)
- 前向渲染
图2
- 图2,Forword+光照,默认光照(左),光照热力图(右)。热力图中的颜色表示影响当前tile的灯光数量。黑色表示无灯光,蓝色表示包含1-10个灯光,绿色表示包含20-30个灯光。
Forward+渲染的第一个pass是使用一个在屏幕空间统一大小的格子将灯光划分到一个个的tile列表。
第二个pass是使用标准的前向渲染来对每个物体进行着色,与遍历场景的每个动态灯光不同,当前像素的屏幕空间位置用来查找在先前Pass计算的当前所在格子的灯光列表。相比于标准的前向渲染,灯光剔除可以带来明显的性能提升,因为它大大减少了像素正确光照所需要迭代的冗余灯光数量。不透明物体和透明物体都可以使用相似的行为进行处理,而不会有明显的性能损失,并且多材质和多光照模型是Forward+原生支持的。
因为Forward+是与标准前向渲染共同工作的,因此Forward+可以集成到最初使用前向渲染进行构建的图形引擎中。Forward+没有使用B—Buffer,也没有延迟渲染的限制,不透明物体和透明物体都可以使用Forward+进行渲染。使用现代图形硬件,可以在高清画质(1080P)下渲染包含5000-6000个动态灯光的场景。
定义
在本文中,为了方便理解,定义一些术语是很重要的,如果你对这个基本的术语很熟悉,可以直接跳过该部分。
Scene
Scene(场景)是指一个可被渲染的嵌套的层级对象。例如,所有可被渲染的静态对象会组合成一个场景,每个独立的可渲染对象称为Node(场景结点),每个场景结点指向一个可渲染对象(如mesh),整个场景可以被一个场景的顶级结点引用,称为root node(根结点)。因为根结点也是一个场景结点,因此场景可以嵌套地创建更复杂的包含动态或静态对象的场景树。
Pass
一个Pass是指一个操作,用来执行渲染技术的其中一步。例如,不透明(opaque)Pass是迭代场景中的所有对象,并只渲染场景中的不透明对象。透明(transparent)Pass是迭代场景中的所有对象,并只渲染场景中的透明对象。一个Pass也可以用来进行更加通常的操作,如拷贝GPU资源或调配一个计算着色器(compute shader)。
Technique
Technique是多个Pass的组合,多个Pass必须按一定的顺序进行执行来实现一个渲染算法。
Pipeline State
管线状态(Pipeline State)是指在对象被渲染之前渲染管线的配置,一个Pipeline State对象封装了以下的渲染状态:
- Shader: 顶点shader(vertex shder),细分shader(tessellation shader),几何shader(geometry shader)和像素shader(pixel shader。
- 光栅化状态(Rasterizer state): 多边形填充模式(fill mode),裁剪模式(culling model),scissor, viewport
- 融合状态(blend state)
- depth/stencil state
- render target
其中,dx12等不同的渲染API都会引入一些不同的管线状态。
前向渲染
前向渲染是一个通常只有两个pass的渲染技术:
- 不透明Pass
- 透明Pass
不透明Pass会渲染所有的不透明对象,理想情况下,场景应当被从前向后进行排序以减少overdraw。在不透明Pass中不会执行融合(blending)。
透明Pass会渲染所有的透明对象,理想情况下,为了能正确blend,场景应当从后向前进行排序(相对于相机),在该pass下,alpha blend需要被开启,使用得半透明材质能与已经渲染到render target的像素进行正确的blend。
在前向渲染中,所有的灯光与其它的着色指令一起在pixel shader中被执行。
延迟渲染
延迟渲染是一个包含三个主要Pass的渲染技术:
- 几何Pass
- 光照Pass
- 透明Pass
第一个Pass是与前向渲染的不透明Pass相似的几何Pass,只有不透明对象在该Pass中被渲染,不同的是几何Pass不执行任何的光照计算,但只输出几何和材质数据到前面介绍的G-Buffer中。
在光照Pass中,表示灯光的几何体(geometric volume)和G-Buffer中的材质信息被用来计算光栅化的像素光照。
最后一个Pass是透明Pass,该Pass与前向渲染的中透明Pass是完全相同的。因为延迟渲染不支持透明材质,因此透明物体需要在一个使用标准前向渲染的独立的Pass中被渲染。
Forward+
Forward+(也被称为基于tile的前向渲染)是包含三个主要pass的渲染技术:
- 灯光剔除Pass
- 不透明Pass
- 透明Pass
前面介绍中有提到,灯光剔除Pass需要将动态灯光分类到屏幕空间的tile中,一个灯光索引列表用来指示哪些灯光索引(从全局灯光列表)覆盖了屏幕tile。在该pass中,两个灯光索引列表会被生成:
- 不透明灯光索引列表
- 透明灯光索引列表
不透明灯光索引列表被用来渲染不明秀几何体,透明灯光索引列表用来渲染透明几何体。
不透明Pass和透明Pass与标准前向渲染是相同的,与遍历场景中所有的动态灯光不同,Foward+渲染只会遍历当前片元(像素)所在屏幕空间的tile的灯光。
A light refers to one of the following types of lights:
灯光
灯光是指下面几种灯光的一种:
- 点光源
- 聚光灯(Spot light)
- 方向光
本文中所描述的渲染技术都支持了这三种灯光类型,但没有支持区域光。点光源和聚光灯被模拟成从一个点向外发射,方向光被认为是从无限远处的一点发射光线,任何地方都具有相同的方向。点光源和聚光灯都有一个有限的范围,超过这个范围强度会下降到0,光强度的下降称为衰减(attenuation)。点光源被描述成一个球,聚光灯作为一个圆椎体,方向光是全屏幕的四方形(quad)。