Unity Shader学习记录(14) —— Unity的光照渲染路径,(前向,顶点,延迟)

本文介绍了Unity中的渲染路径,包括前向渲染和延迟渲染。前向渲染处理逐顶点、逐像素和球谐函数光照,根据光源重要性和数量进行优化。延迟渲染则通过G缓冲技术,先存储表面信息,后进行光照计算,适合光源数量多的场景,但不支持某些高级特性如抗锯齿和半透明物体处理。
摘要由CSDN通过智能技术生成

1 渲染路径介绍

在前面的学习中,我们的场景中都仅有一个光源且光源类型是平行光(如果你的场景不是这样的话,可能会得到错误的结果)。但在实际的游戏开发过程中,我们往往需要处理数目更多、类型更复杂的光源。更重要的是,我们想要得到阴影。在本章我们就会学习如何在 Unity 中实现上面的功能。

在学习这些之前,我们有必要知道 Unity 到底是如何处理这些光源的。也就是说,当我们在场景里放置了各种类型的光源后,Unity 的底层染引擎是如何让我们在 Shader 中访问到它们的因此9.1节首先介绍了Unity 的染路径。

在Unity里,**渲染路径(Rendering Path)**决定了光照是如何应用到Unity Shader 中的。因此如果要和光源打交道,我们需要为每个 Pass 指定它使用的染路径,只有这样才能让 Unity 知道“哦,原来这个程序员想要这种渲染路径,那么好的,我把光源和处理后的光照信息都放在这些数据里,你可以访问啦!”也就是说,我们只有为 Shader 正确地选择和设置了需要的染路径,该Shader的光照计算才能被正确执行。

Unity支持多种类型的渲染路径。在Unity 5 版本之前主要有3种前向染路径(ForwardRendering Path)、延迟渲染路径(Deferred Rendering Path)和顶点照明染路径(Vertex LitRenderingPath)。但在Unity 5.0版本以后,Unity 做了很多更改,主要有两个变化:首先,顶点照明渲染路已经被Unity抛弃(但目前仍然可以对之前使用了顶点照明渲染路径的 Unity Shader兼容):其次,新的延迟渲染路径代替了原来的延迟渲染路径(同样,目前也提供了对较旧版本的兼容)。

Camera里面的设置
Unity的渲染路径
在这里插入图片描述

2 前向渲染路径

每进行一次完整的前向渲染,我们需要渲染该对象的渲染图元,并计算两个缓冲区的信息:一个是颜色缓冲区,一个是深度缓冲区。我们利用深度缓冲来决定一个片元是否可见,如果可见就更新颜色缓冲区中的颜色值。我们可以用下面的伪代码来描述前向渲染路径的大致过程:
在这里插入图片描述
对于每个逐像素光源,我们都需要进行上面一次完整的渲染流程。如果-个物体在多个逐像素光源的影响区域内,那么该物体就需要执行多个Pass,每个Pass计算一个逐像素光源的光照结果,然后在帧缓冲中把这些光照结果混合起来得到最终的颜色值。假设,场景中有N个物体,每个物体受M个光源的影响,那么要渲染整个场景一共需要 N*M个Pss。可以看出,如果有大量逐像素光照,那么需要执行的 Pass 数目也会很大。因此,渲染引擎通常会限制每个物体的逐像素光照的数目

3.Unity 中的前向渲染

在 Unity 中,前向渲染路径有 3 种处理光照(即照亮物体)的方式:逐顶点处理逐像素处理球谐函数(SphericalHarmonics,SH)处理。而决定一个光源使用哪种处理模式取决于它的类型和渲染模式。光源类型指的是该光源是平行光还是其他类型的光源,而光源的渲染模式指的是该光源是否是重要的(Important)。如果我们把一个光照的模式设置为Important,意味着我们告诉Unity,“嘿老兄,这个光源很重要,我希望你可以认真对待它,把它当成一个逐像素光源。

在前向渲染中,当我们渲染一个物体时,Unity会根据场景中各个光源的设置以及这些光源对物体的影响程度(例如,距离该物体的远近、光源强度等)对这些光源进行一个重要度排序。其中,一定数目的光源会按逐像素的方式处理,然后最多有4个光源按逐顶点的方式处理,剩下的光源可以按SH方式处理。Unity 使用的判断规则如下。
场景中最亮的平行光总是按逐像素处理的渲染模式被设置成NotImportant的光源会按逐顶
图9.3设置光源的类型和渲染模式点或者SH处理。渲染模式被设置成Important的光源,会按逐像素处理如果根据以上规则得到的逐像素光源数量小于Quality Setting中的逐像素光源数量(PixelLight Count),会有更多的光源以逐像素的方式进行渲染。那么,在哪里进行光照计算呢?当然是在 Pass 里。前面提到过,前向染有两种 Pass: BasePassAdditionalPass。通常来说,这两种Pass进行的标签和染设置以及常规光照计算如图9.4所示。

在这里插入图片描述
首先,可以发现在渲染设置中,我们除了设置了 Pass 的标签外,还使用了#pragma multicompile_fwdbase 这样的编译指令。虽然#pragma multi_compile fwdbase 和#pragmamulti_compile fwdadd在官方文档中还没有给出相关说明但实验表明只有分别为 BassPass和Additional Pass 使用这两个编译指令,我们才可以在相关的Pass中得到一些正确的光照变量,例如光照衰减值等。

Base Pass旁边的注释给出了 Base Pass中支持的一些光照特性。例如在 Base Pass中,我们可以访问光照纹理(lightmap)。

Base Pass 中渲染的平行光默认是支持阴影的(如果开启了光源的阴影功能)而AdditionalPass 中渲染的光源在默认情况下是没有阴影效果的,即便我们在它的 Light 组件中设置了有阴影的Shadow Type。但我们可以在 Additional Pass中使用 #pragma multi compilefwdadd fullshadows代替#pragmamulti compile fwdadd 编译指令,为点光源和聚光灯开启阴影效果,但这需要Unity在内部使用更多的Shader 变种。环境光和自发光也是在 Base Pass 中计算的。这是因为,对于一个物体来说,环境光和自发光我们只希望计算一次即可,而如果我们在Additional Pass 中计算这两种光照,就会造成叠加多次环境光和自发光,这不是我们想要的。

在Additional Pass的渲染设置中,我们还开启和设置了混合模式。这是因为,我们希望每个AdditionalPass可以与上一次的光照结果在缓存中进行叠加,从而得到最终的有多个光照的渲染效果。如果我们没有开启和设置混合模式,那么Additional Pass 的染结果会覆盖掉之前的渲染结果,看起来就好像该物体只受该光源的影响。通常情况下,我们选择的混合模式是 BlendOne One。

对于前向渲染来说,一个Unity Shader 通常会定义一个Base Pass(Base Pass也可以定义多次,例如需要双面渲染等情况)以及一个Additional Pass。一个 Base Pass 仅会执行次(定义了多个Base Pass 的情况除外),而一个Additional Pass 会根据影响该物体的其他逐像素光源的数目被多次调用,即每个逐像素光源会执行一次AdditionalPass。

图9.4给出的光照计算是通常情况下我们在每种 Pass 中进行的计算。实际上,渲染路径的设置用于告诉Unity该Pass在前向染路径中的位置,然后底层的染引警会进行相关计算并填充些内置变量(如 LightColor0 等),如何使用这些内置变量进行计算完全取决于开发者的选择例如,我们完全可以利用 Unity 提供的内置变量在 Base Pass 中只进行逐顶点光照;同样,我们也完全可以在AdditionalPass 中按逐顶点的方式进行光照计算,不进行任何逐像素光照计算。

在这里插入图片描述

前向渲染可以使用的内置光照函数

在这里插入图片描述

顶点照明渲染路径

顶点照明渲染路径是对硬件配置要求最少、运算性能最高,但同时也是得到的效果最差的一种类型,它不支持那些逐像素才能得到的效果,例如阴影、法线映射、高精度的高光反射等。实际上,它仅仅是前向渲染路径的一个子集,也就是说,所有可以在顶点照明渲染路径中实现的功能都可以在前向渲染路径中完成。就如它的名字一样,顶点照明渲染路径只是使用了逐顶点的方式来计算光照,并没有什么神奇的地方。实际上,我们在上面的前向渲染路径中也可以计算一些逐顶点的光源。但如果选择使用顶点照明渲染路径,那么 Unity 会只填充那些逐顶点相关的光源变量,意味着我们不可以使用一些逐像素光照变量。
可以看出,一些变量我们同样可以在前向渲染路径中使用,例如unity LightColor。但这些变量数组的维度和数值在不同渲染路径中的值是不同的。
在这里插入图片描述

延迟渲染路径

前向渲染的问题是:当场景中包含大量实时光源时,前向渲染的性能会急速下降。例如,如果我们在场景的某一块区域放置了多个光源,这些光源影响的区域互相重叠,那么为了得到最终的光照效果,我们就需要为该区域内的每个物体执行多个Pass 来计算不同光源对该物体的光照结果,然后在颜色缓存中把这些结果混合起来得到最终的光照。然而,每执行一个 Pass 我们都需要重新渲染一遍物体,但很多计算实际上是重复的。延迟渲染是一种更古老的渲染方法,但由于上述前向渲染可能造成的瓶颈问题,近几年又流行起来。除了前向渲染中使用的颜色缓冲和深度缓冲外,延迟渲染还会利用额外的缓冲区,这些缓冲区也被统称为G缓冲(G-buffer),其中G是英文Geometry 的缩写。G缓冲区存储了我们所关心的表面(通常指的是离摄像机最近的表面)的其他信息,例如该表面的法线、位置、用于光照计算的材质属性等。

原理:延迟渲染主要包含了两个Pass。在第一个Pass 中,我们不进行任何光照计算,而是仅仅计算哪些片元是可见的,这主要是通过深度缓冲技术来实现,当发现一个片元是可见的,我们就把它的相关信息存储到G缓冲区中。然后,在第二个 Pass 中,我们利用G缓冲区的各个片元信息例如表面法线、视角方向、漫反射系数等,进行真正的光照计算。

可以看出,延迟渲染使用的 Pass 数目通常就是两个,这跟场景中包含的光源数目是没有关系的。换句话说,延迟渲染的效率不依赖于场景的复杂度,而是和我们使用的屏幕空间的大小有关。这是因为,我们需要的信息都存储在缓冲区中,而这些缓冲区可以理解成是一张张 2D 图像,我们的计算实际上就是在这些图像空间中进行的。

对于延迟渲染路径来说,它最适合在场景中光源数目很多、如果使用前向渲染会造成性能瓶颈的情况下使用。而且,延迟渲染路径中的每个光源都可以按逐像素的方式处理。但是,延迟渲染也有一些缺点。

对于延迟渲染路径来说,它最适合在场景中光源数目很多、如果使用前向渲染会造成性能瓶颈的情况下使用。而且,延迟渲染路径中的每个光源都可以按逐像素的方式处理。但是,延迟渲染也有一些缺点。
1 不支持真正的抗锯齿(anti-aliasing)功能。
2 不能处理半透明物体。
3 对显卡有一定要求。如果要使用延迟渲染的话,显卡必须支持MRT(Multiple RenderTargets)、Shader Mode3.0及以上、深度染纹理以及双面的模板缓冲

Unity中延迟渲染:
当使用延迟渲染时,Unity 要求我们提供两个Pass。

(1)第一个Pass用于渲染G缓冲在这个Pass 中,我们会把物体的漫反射颜色、高光反射颜色、平滑度、法线、自发光和深度等信息渲染到屏幕空间的G 缓冲区中。对于每个物体来说,这个Pass 仅会执行一次。

(2)第二个Pass用于计算真正的光照模型。这个Pass会使用上一个Pass中染的数据来计算最终的光照颜色,再存储到帧缓冲中。
默认的G缓冲区(注意,不同Unity 版本的染纹理存储内容会有所不同)包含了以下几个渲染纹理(Render Texture,RT)。

RT0:格式是ARGB32,RGB通道用于存储漫反射颜色,A通道没有被使用。
RT1:格式是ARGB32,RGB 通道用于存储高光反射颜色,A通道用于存储高光反射的指数部分。
RT2:格式是ARGB2101010,RGB通道用于存储法线,A通道没有被使用。
RT3:格式是ARGB32(非HDR)或ARGBHalf(HDR)用于存储自发光+lightmap+反射探针(reflection probes)。

深度缓冲和模板缓冲。
当在第二个Pass中计算光照时,默认情况下仅可以使用Unity内置的Standard 光照模型。如果我们想要使用其他的光照模型,就需要替换掉原有的 Intermal-DeferredShadingshader 文件。更详细的信息可以访问官方文档(http://docsunity3d.com/Manual/RenderTech-DeferredShading.html)。

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值