【Unity Shader入门精要 第9章】更复杂的光照(一)

1. 渲染路径

渲染路径是针对光照的设置,指的是以什么方式来进行光照计算,不同渲染路径主要影响的内容包括:

  • 渲染的过程,比如不同渲染路径分别需要哪些Pass,每个Pass的作用是什么,以及是否会生成中间数据(G-Buffer)等
  • Shader中可以使用的内置光照变量(如我们之前常用的_LightColor0等),Unity会根据配置的渲染路径给对应的光照变量进行赋值,因此渲染路径跟光照变量需要搭配使用,否则就会产生错误的渲染结果
  • 对于多光源的处理,其实也是渲染过程中的一部分

在这里插入图片描述
如上图所示,可以在摄像机的 Rendering Path 属性下选择当前摄像机的渲染路径,虽然选项看起来很多,但是现在我们只需要关心两个:

  • Forward:前向渲染路径
  • Deferred:延迟渲染路径

除此之外,我们在 Shader 中实际实现光照计算时,会用到 _LightColor0 这些内置光照变量,要保证计算结果的正确,就需要在 Shader 执行时这些光照变量已经被正确赋值。因此,还需要在 Shader 中指明当前 Pass 用于哪种渲染路径,这样 Unity 才知道要给哪些变量赋值以及赋什么值。

【Unity Shader入门精要 第3章】Unity Shader基础中曾经提到过,Pass 中也可以设置 Tags 标签,其中最常用的 Pass 级标签 “LightMode” 的主要作用就是负责通知引擎当前 Pass 对应的是哪种渲染路径,以及在当前渲染路径中所处的身份。

LightMode 标签支持的设置选项如下(顶点照明路径和老的延迟渲染路径选项这里省略了):

标签描述
Always无论使用哪种渲染路径,该Pass都会被渲染,但不会计算任何光照
ForwardBase前向渲染路径时,该Pass会被渲染,且该Pass身份为前向渲染路径的Base Pass
ForwardAdd前向渲染路径时,该Pass会被渲染,且该Pass身份为前向渲染路径的Additional Pass
Deferred延迟渲染路径时,该Pass会被渲染
ShadowCaster一个特殊功能类型的Pass,会将物体的深度信息写入到阴影映射纹理,用于对阴影的渲染,另外,在指定了摄像机需要生成深度纹理时,也会利用该类型的Pass进行深度纹理的生成

2. 前向渲染路径

2.1 光源处理类型

在前向渲染中,会对光源进行重要性排序,并按照排序对照射到当前物体上的光源分成三类,依次为:逐像素光源、逐顶点光源、SH(球谐)光源。

重要性排序的依据主要为光源对当前物体的影响,比如距离、强度等。另外,在光源 Inspector 面板的 Render Mode 选项中也可以指定当前光源的重要性(如下图)。
在这里插入图片描述

分类的大概过程为:

  • 场景内最亮的平行光一定是逐像素光源,当场景内没有平行光时,会默认为一个黑色的平行光
  • 在Project Settings 的 Quality 页签内可以设置场景内逐像素光源的最大数量 Pixel Light Count
    在这里插入图片描述
  • Render Mode 设置为 Important 的光源会被分配为逐像素光源
  • 如果没有达到设定的逐像素光源最大数量,按照重要性排序依次将重要性较高的光源分配为逐像素光源
  • 逐像素光源分配完成后,如果还有剩余的光源,则按照重要性排序依次分配为逐顶点光源,最多四个
  • 如果还有多余的光源,全部分配为SH光源

2.2 Pass类型

在前向渲染中包含两种类型的Pass,分别为Base Pass 和 Additional Pass。

2.2.1 Base Pass

通过在 Pass 的 Tags 中设置标签 “LightMode” = “ForwardBase”,可以指定当前Pass为前向渲染中的 Base Pass

添加 #pragma multi_compile_fwdbase ,通知引擎为 Pass 编译不同 keyword 的变体,如果不加这一行,Unity只会按照一个默认的组合条件进行编译,在该情况以外的环境中,光照就会出错

Base Pass会处理一个逐像素光源和所有的逐顶点光源、所有的SH光源

Base Pass处理的逐像素光源必须是平行光,如果当前场景中没有平行光,则会按照一个黑色的平行光进行处理。假如我们在场景中不放置平行光,只放置一个点光源,此时依然可以照亮物体,是因为该点光源按照逐顶点光源的方式对物体进行了光照

Base Pass的渲染结果包含了一个光照效果里的所有部分内容,比如光源带来的漫反射等、自发光、环境光、光照纹理影响、阴影效果等,或者说,Base Pass 负责完成一次基础且完整的光照效果渲染

2.2.2 Additional Pass

通过在 Pass 的 Tags 中设置标签 “LightMode” = “ForwardAdd”,可以指定当前Pass为前向渲染中的 Additional Pass

添加 #pragma multi_compile_fwdadd ,通知引擎为 Pass 编译不同 keyword 的变体,此时,该 Pass 不会进行阴影的渲染

也可以通过 #pragma multi_compile_fwdadd_fullshadows 来对 Additional Pass 进行变体编译,此时该 Pass 可以支持阴影渲染,但效率更低

Additional Pass 会依次处理剩余的所有逐像素光源,如果物体身上有 M 个 Additional Pass,且受到 N 个逐像素光源的影响(Base Pass 处理的逐像素光源除外),则会执行 M * N 次渲染

Additional Pass 中需要设置混合模式,通常可以设置为 Blend One One,否则会将已有的渲染结果覆盖掉

Additional Pass 只处理光源自身的光照影响,不计算自发光、环境光等固定部分的光照效果,因为这部分效果应该只生效一次,不应该随光源数量而叠加

2.2.3 总结

由上可知:

  • 前向渲染的原理为,先通过 Base Pass 渲染出基础的光照效果,然后对额外的逐像素光源依次执行 Additional Pass 计算出每个光源带来的附加效果,并叠加到基础效果上,得到最终的渲染结果
  • 每个 Base Pass 只会渲染一次,通常也只会有一个 Base Pass
  • 每个Addition Pass针对每个额外光源渲染一次

由于一个 Pass 就是一个完整的渲染过程,因此,在前向渲染中,渲染流水线和光源数量的关系可以大概理解为下图的样子
在这里插入图片描述

2.3 内置变量

在前向渲染中可以使用的内置变量如下:

变量类型描述
_LightColor0float4该Pass 处理的逐像素光源的颜色
_WorldSpaceLightPos0float4xyz表示逐像素光源的世界位置(平行光时为光源方向),w为0时表示当前处理的逐像素光源为平行光,否则为非平行光
_LightMatrix0float4x4世界空间到光源空间的变换矩阵
unity_4LightPosX0/unity_4LightPosY0/unity_4LightPosZ0float4仅可用于BasePass,前4个非重要点光源的世界空间位置的X值、Y值、Z值
unity_4LightAtten0float4仅可用于BasePass,前4个非重要点光源的衰减因子
unity_4LightColorfloat4[4]仅可用于BasePass,前4个非重要点光源的颜色

3. 延迟渲染路径

3.1 原理

在前向渲染中,每个逐像素光源都会至少执行一次对应的Pass,而每执行一次Pass都需要走一遍完整的渲染流水线,这其中需要进行很多的空间变换、可见性测试等计算。

但在这一帧中,摄像机和物体的空间关系并没有发生变化,也就是物体的可见性并不会发生改变。换句话讲,屏幕空间下,哪些像素需要渲染哪些像素不需要渲染是确定的,只需要进行一次计算即可。

延迟渲染的思路就是先计算出哪些像素需要显示,并记录下它们在进行渲染时所需的各种信息,然后只针对这些需要显示的像素挨个光源进行光照计算。

为此,延迟渲染通常需要两个 Pass 来完成:

  • 第一个 Pass 不进行光照计算,只进行可见性计算,获取到需要显示的像素,同时,将这些像素在光照计算中需要的各种信息存储到一个特殊的缓冲区——G-Buffer——中,供第二个Pass使用
  • 在第二个Pass中,针对那些需要显示的像素,从 G-Buffer 中获取该像素的相关 数据,对每个照射到当前像素的光源都进行一次光照计算,得到最终的光照结果(相当于每个光源都是逐像素的)。

因此,在延迟渲染中,渲染流水线和光源数量的关系可以大概理解为下图的样子:
在这里插入图片描述

3.2 G-Buffer

G-Buffer包含一系列的 RenderTexture 和缓冲,默认如下:

名字描述
RT0ARGB32,RGB通道存储漫反射颜色,A通道没有用到
RT1ARGB32,RGB通道存储高光反射颜色,A通道没有用到
RT2ARGB2101010,RGB通道存储法线,A通道没有用到
RT3ARGB32,存储自发光 + LightMap + 反射探针
深度缓冲
模板缓冲

由于在延迟渲染中,片元着色器计算光照的各种数据基本都要在 G-Buffer 中进行存储,而默认的四张纹理几乎已经都被占满了,所以当片元着色器计算比较复杂使用参数较多时,很可能就需要扩展纹理,从而带来较大的显存压力。

另外,由于延迟渲染是在片元着色器中对所有光源进行光照计算,因此所有光源都是使用的同一个光照模型,而且由于延迟渲染的目标是可见像素,也就是离摄像机最近的像素,因此对于半透的渲染支持较差。

另一方面,由于启用了 G-Buffer,在诸如生成深度纹理等操作时,可以直接从G-Buffer中读取所需信息,使得延迟渲染对于某些屏幕后处理的支持更好。

3.3 内置变量

延迟渲染中可用的内置光照变量如下:

变量类型描述
_LightColorfloat4当前正在处理的光源的颜色
_LightMatrixfloat4x4世界空间到当前光源空间的变换矩阵
  • 15
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity Shader是一种用于渲染图形的程序,它可以控制对象的表面颜色、纹理、透明度、反射等属性,从而实现特殊的视觉效果。对于游戏开发者来说,掌握Shader编写技巧是非常重要的。 以下是关于Unity Shader入门精要: 1. ShaderLab语言 ShaderLab是Unity中用于编写Shader的语言,它是一种基于标记的语言,类似于HTML。ShaderLab可以用于定义Shader的属性、子着色器渲染状态等信息。 2. CG语言 CG语言是Unity中用于编写Shader的主要语言,它是一种类似于C语言的语言,可以进行数学运算、向量计算、流程控制等操作。CG语言可以在ShaderLab中嵌入,用于实现Shader的具体逻辑。 3. Unity渲染管线 Unity渲染管线包括顶点着色器、片元着色器、几何着色器等组件,每个组件都有不同的作用。顶点着色器用于对对象的顶点进行变换,片元着色器用于计算每个像素的颜色,几何着色器用于处理几何图形的变形和细节等。 4. 模板和纹理 在Shader中,我们可以使用纹理来给对象添加图案或者贴图,也可以使用模板来控制对象的透明度、反射等属性。纹理可以通过内置函数tex2D()来获取,模板可以通过内置函数clip()来实现裁剪。 5. Shader的实现 Shader的实现需要注意以下几点: - 在ShaderLab中定义Shader的属性、子着色器渲染状态等信息。 - 在CG语言中实现Shader的具体逻辑,包括顶点着色器、片元着色器等内容。 - 使用纹理和模板来实现特定的视觉效果。 - 在对象上应用Shader,通过调整Shader的属性来达到不同的效果。 以上是关于Unity Shader入门精要,希望对你有所帮助。如果你想深入地了解Shader的编写技巧,可以参考官方文档或者相关教程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值