技术美术百人计划 | 《3.4 渲染路径》笔记

1. 渲染路径

在Unity 里,渲染路径 (RenderingPath) 决定了光照是如何应用到 Unity Shader 中的, 我们需要为每个Pass指定它使用的渲染路径。

Pass 
{
    Tags{ "LightMode" = "ForwardBase" }
    ...
}

Unity 支持多种类型的渲染路径。前向渲染路径(Forward Rendering Path)、延迟渲染路径 (Deferred Rendering Path) 和顶点照明渲染路径 (Vertex Lit Rendering Path)。在 Unity 5.0 版本以后,顶点照明渲染路径已经被抛弃。

前向渲染(左)与延迟渲染(右)对比

1.1. 前向渲染路径

前向渲染路径是传统的渲染方式,也是我们最常用的一种渲染路径。

1.1.1. 原理

思路:每进行一次完整的前向渲染,我们需要渲染该对象的渲染图元,并计算两个缓冲区的信息:一个是颜色缓冲区,一个是深度缓冲区。我们利用深度缓冲来决定一个片元是否可见,如果可见就更新颜色缓冲区中的颜色值。


如图所示,渲染流程为:待渲染几何体 → 顶点着色器 → 片元着色器 → 渲染目标

在渲染每一帧的时,每一个顶点/片元都要执行一次片元着色器代码,这时需要将所有的光照信息传到片元着色器中。虽然大部分情况下的光照都趋向于小型化,而且照亮区域也不大,但即便是离这个像素所对应的世界空间的位置很远的光源,光照计算还是会把所有的光源考虑进去的。简单来说就是不管光源的影响大不大,计算的时候都会把所有光源计算进去,这样就会造成一个很大的浪费。

对于每一个像素,都需要执行一次Pass计算。假设,场景中有N个物体,每个物体受M个光源的影响,那么要渲染整个场景一共需要N*M个Pass。可以看出,如果有大量逐像素光照, 那么需要执行的Pass数目也会很大。因此,渲染引擎通常会限制每个物体的逐像素光照的数目。

1.1.2. Unity 中的前向渲染

1.1.2.1. 处理光照方式及其选择规则

在 Unity 中,前向渲染路径有3 种处理光照(即照亮物体)的方式:

  • 逐顶点处理
  • 逐像素处理
  • 球谐函数 (Spherical Harmonics, SH) 处理

而决定一个光源使用哪种处理模式取决于它的类型和渲染模式。

  • 光源类型指的是该光源是平行光还是其他类型的光源
  • 而光源的渲染模式指的 是该光源是否是重要的 (Important)。

其中,一定数目的光源会按逐像素,最多4个光源按逐顶点(可更改,如下图),剩下的光源可以按SH。

Unity使用的判断规则如下。

  • 最亮的平行光---逐像素
  • Not Important---逐顶点或者SH
  • Important---逐像素处理。
  • 最后,如果逐像素光源数批<Quality Setting中的逐像素光源数批(Pixel Light Count) ,会有更多的光源以逐像素的方式进行渲染
1.1.2.2. 两种Pass

前向渲染有两种Pass: Base Pass和AdditionalPass

1.1.3. 内置的光照变量和函数

总结:前向渲染的每一个物体对每个光照都计算一次,为了节约性能Unity会使用不同处理光照的方式。

1.2. 顶点照明渲染路径

顶点照明渲染路径是对硬件配罚要求最少、运算性能最高,但同时也是得到的效果最差的一种类型,它不支持那些逐像素才能得到的效果,只是使用了逐顶点的方式来计算光照。

1.3. 延迟渲染路径

1.3.1. 原理

流程为:待渲染几何体 → 顶点着色器 → MRT 多渲染目标→ 光照计算 → 渲染目标

延迟渲染主要包含了两个Pass。

  • 在第一个Pass 中,我们不进行任何光照计算,而是仅仅计算哪些片元是可见的,这主要是通过深度缓冲技术来实现,当发现一个片元是可见的,我们就把它的相关信息存储到G缓冲区G-Buffer(G 缓冲区存储了我们所关心的表面的其他信息,例如该表面的法线、位置、用于光 照计算的材质属性等)中。 这个Pass 仅会执行一次。
  • 然后,在第二个Pass 中,我们利用G缓冲区的各个片元信息,进行真正的光照计算 。 默认的G缓冲区包含了以下几个渲染纹理(RenderTexture, RT)。
    • 漫反射颜色
    • 高光反射颜色
    • 法线
    • 自发光+lightmap+反射探针(reflection probes)
    • 深度缓冲和模板缓冲

延迟渲染跟场景中包含的光源数目是没有关系的,而是和屏幕空间的大小有关。这是因为,我们需要的信息都存储在缓冲区中,而这些缓冲区可以理解成是一张张 2D 图像。它最适合在场景中光源数目很多、如果使用前向渲染会造成性能瓶颈的情况下使用。

可以自定义延迟渲染路径来满足项目的需求:

总结:延迟渲染就是分两次渲染,第一次计算哪些片元可见并将信息存到G-Buffer,第二次进行光照计算。适合多光源场景。

2. 案例

对于这样一个场景,包含两个点光源,一个Direction Light,和两个物体。

性能对比

Frame Debugger中渲染过程对比:

前向渲染

延迟渲染

3. 比较

3.1. 特性对比

1、后处理方式不同(如何需要深度信息进行后处理的话)

  • 前向渲染需要单独渲染出一张深度图
  • 延迟渲染直接用G-buffer中的深度信息计算即可

2、shader计算不同

  • 延迟渲染,因为是最后统一计算光照的,所以只能算一个光照模型,如果需要其他光照模型,只能切换pass

3、抗锯齿方式不同

3.2. 优缺点对比

前向渲染的优缺点

优点

  • 1.支持半透明渲染
  • 2.支持使用多个光照pass
  • 3.支持自定义光照计算方式
    • (延迟渲染是渲染到Gbuffer,再一起计算光照,所以不支持每一个物体用单独的光照方式计算)

缺点

  • 1.光源数量对计算复杂度影响巨大
  • 2.访问深度等数据需要额外计算(需要再渲染一张深度图)

延迟渲染的优缺点

优点

  • 1.大量光照场景的情况下,优势明显
  • 2.只渲染可见像素,节省计算量
  • 3.对后处理支持良好(例如深度信息:直接拿G-buffer中的就行)
  • 4.用更少的shader(所有的物体光照模型都一样,很多东西不用再定义了)

缺点

  • 1.对MSAA(Multisample anti aliasing,多重采样抗锯齿)支持不友好
  • 2.透明物体渲染存在问题(深度问题,只渲染离物体最近的物体,渲染透明度时会出现问题)
  • 3.占用大量的显存带宽
    • 涉及一个clear的操作,如果不清理的话,后边可以继续获取到
    • 每一帧都需要几张RT在显存中传输、清理等,会更耗带宽
  • 4.只能使用同一个光照pass

4. 补充

Unity的渲染路径设置:

4.1. 移动端优化

见补充

4.2. 其他渲染路径

游戏引擎中的光照算法 - 知乎 (zhihu.com)

4.2.1. 延迟光照(Light Pre-Pass / Deferred Lighting)

减少G-buffer占用的过多开销,支持多种光照模型。和延迟渲染的区别:用更少的buffer信息,着色计算的时候用的是forward,所以第三步开始都是前向渲染(可以对不同的物体进行不同的光照模型)。

这个算法跟Deferred Shading差不多,Cryengine3早期版本中使用过该技术,目前基本上没有引擎再使用这个方法。

4.2.2. 分块正向渲染(Forward plus/ Tiled Forward Rendering

减少带宽,支持多光源,强制需要一个preZ

  • 通过分块索引的方式,以及深度和法线信息来到需要进行光照计算的片元进行光照计算。
  • 需要法线和深度的后处理需要单独渲染一个rt出来
  • 强制使用了一个preZ(如果没涉及过这个概念的话,可以理解为进行了一个深度预计算)

4.2.3. 群组渲染(Clustered Rendering)

带宽相对减少,多光源下效率提升。分为forward和deferred两种。

4.3. MSAA

计算机图形学四:抗锯齿SSAA及MSAA算法和遮挡剔除Z-Buffer算法_抗锯齿算法-CSDN博客

4.3.1. 走样

在介绍MSAA原理之前,首先了解走样(Aliasing),走样指的是因为对函数(信号)的采样频率不足,或者说信号的变化速率远大于采样的频率,使得出现不连续的现象称为走样。 走样分为三种:

  • 几何体走样(几何物体的边缘有锯齿),几何走样由于对几何边缘采样不足导致。因此需要采用抗锯齿技术。
  • 着色走样,由于对着色器中着色公式(渲染方程)采样不足导致。例如高光闪烁。
  • 时间走样,主要是对高速运动的物体采样不足导致。比如游戏中播放的动画发生跳变等。

4.3.2. 超采样反走样SSAA

超采样技术就是以一个更大的分辨率来渲染场景,然后再把相邻像素值做一个过滤(比如平均等)得到最终的图像(Resolve)。因为这个技术提高了采样率,所以它对于解决上面几何走样和着色走样都是有效果的。如下图所示,首先经对每个像素取n个子采样点,然后针对每个子像素点进行着色计算。最后根据每个子像素的值来合成最终的图像。如下图将每个像素点细分成了4个采样点进行抗锯齿处理(可以用更多采样点,越多效果越好,性能耗费越大)。

4.3.3. MSAA

MSAA是对SSAA的一个改进。MSAA是一种抗锯齿技术,即多重采样抗锯齿(MultiSampling Anti-Aliasing,简称MSAA),这是一种在OpenGL中的特殊的超级采样抗锯齿(SSAA),MSAA主要是对 Z-Buffer 和 Stencil Buffer(模板缓冲)进行SSAA处理,其原理是通过提取像素界面周围的颜色信息,通过混合颜色信息来消除高对比界面所产生的锯齿。只对多边形的边缘进行抗锯齿处理。

缺点:资源耗费,画质上有些不如一般的SSAA。

MSAA依然同样会分采样点,但是只会去计算究竟有几个采样点会被三角形覆盖,计算颜色的时候只会利用像素中心坐标计算一次颜色(即所有的信息都会被插值到像素中心然后取计算颜色),如下图:

但是Direct X9完全不支持MSAA。

延迟渲染管线不支持MSAA。

MSAA在延迟渲染中存在的问题:延迟渲染依赖于每个片元存储的数据,这是通过纹理RT来完成的。这与多重采样抗锯齿不兼容,因为抗锯齿技术依赖于子像素数据。

4.4. PreZ(Z-Prepass)

在几何阶段(顶点着色器)后光栅化阶段(片元着色器)前再添加一次深度测试,将不通过测试的片元舍弃掉,不参加后续的计算,这一步操作被称为EarlyZ(详见3.1深度测试与模板测试):

应用阶段(CPU)->几何阶段(顶点着色器)->early-z(提前深度测试)->光栅化阶段(片元着色器)->各种测试(深度测试,透明度测试,模板测试等)->颜色缓冲区(buffer)

但是要注意,下面几种情况会使得EarlyZ失效:

  • 开启AlphaTest或clip/discard等舍弃片元的操作
    • 正常来说开启Alpha Test后,A的黑色部分片元被舍弃,能够看到后面B C两个不透明物体;但是开启EarlyZ后,首先记录下了A的深度信息,到了AlphaTest理应舍弃A物体黑色部分,渲染B C,然而因为B C无法通过深度测试被舍弃而出现错误渲染结果。
  • 修改深度值,同理。
  • 开启Alpha blend,一般会关闭深度写入(ZWriteOff),这就导致EarlyZ无法写入深度信息。

为了解决上述的问题,我们可以用Z-PrePass。我们使用两个Pass:

  • PrePass:第一个Pass,仅开启深度写入,不输出任何颜色信息,先渲染不透明物体(Opaque),再渲染透明物体(也可以称为Transparent Mask),渲染透明物体的时候做Clip。
  • BasePass:第二个Pass,关闭深度写入,并且将深度比较函数设置为Equal,正常渲染输出颜色信息,先渲染不透明物体再渲染透明物体,但是这时不开启Clip。

但是这样显然多了一个pass的消耗,会出现两倍的drawcall。而如果PixelShader非常复杂的话,这么也是值得的,所以还是要看具体的项目才能确定技术方案。

简单来说EarlyZ是底层硬件写好无法修改且在某些情况下会失效,而Z-PrePass则是在EarlyZ失效情况下的一种手动替代方案,目的都是为了减少overdraw节省性能所做的操作。

5. 作业

移动端如何优化延迟渲染管线?

移动端采用了TBDR架构,优化的建议有:

如果何时不再需要 RenderTexture 的当前内容,清除当前缓冲区可以提高性能。

RenderTexture.DiscardContents()

GL.Clear()

在每帧渲染之前尽量clear

不要在一帧里面频繁的切换framebuffer

压缩贴图格式

尽量打开mipmap

随机纹理寻址相对于相邻纹理寻址有显著开销(?)

纹理寻址模式 - UWP applications | Microsoft Learn

Filer Mode减少Trilinear/Anisotropic使用,使用Bilinear/point

  1. 减少使用LUT(look up texture)(滤镜)

用户 LUT - Unity 手册

合并贴图通道,减少Shader中贴图采样次数

unity编辑器拓展十一——将两张RGB图合并成一张_unity 合并图片-CSDN博客

【Untiy】在Unity中拼合贴图到通道工具_哔哩哔哩_bilibili

控制Framebuffer大小

避免gpu上的copy-on-write,不要在同一帧内多次改变提交给gpu的资源,这会迅速把framedata撑大到装不下的状态。

其他见《Unity Shader入门精要》第十六章-Unity中的渲染优化技术

  • 20
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值