Shader入门精要(九)复杂光照

复杂光照

在之前的学习中,我们使用的都是单一光照,实际在游戏中可能存在多个光源,不同的光源会互相影响构成真正的光照系统,在这一节我们将实现一个真正可用的光照模型。

渲染路径 Rendering Path

:book: 决定了光照是如何应用到Unity Shader中的。

我们只有为Shader正确地选择和设置了需要的渲染路径,该Shader的光照计算才能被正确执行。

:label:渲染路径的分类

  • 前向渲染路径(Forward Rendering Path)
  • 延迟渲染路径(Deferred Rendering Path)
  • 顶点照明渲染路径(Vertex Lit Rendering Path)——已经被弃用

目前unity提供了新的渲染路径代替了原来的渲染路径。

默认使用 Graphics中的设置,可以在摄像机中对设置进行覆盖。

image-20220902112709918

在Shader Pass中来指定该Pass使用的渲染路径:

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

LightMode标签可供使用的渲染路径:

image-20220902112959760

:thought_balloon:为Pass指定正确的渲染路径对于Unity光照变量正确赋值具有重要意义。

Unity默认使用前向渲染光照路径.

前向渲染路径

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

:book: 原理:每进行一次完整的前向渲染,我们需要渲染该对象的渲染图元,并计算两个缓冲区的信息:颜色缓冲区和深度缓冲区。

前向渲染伪代码

image-20220902140220407

每个光照下的物体都需要进行一次逐像素的Pass,也就是在一个场景中,n个物体m个光源的下,渲染场景需要n*m次Pass。

Unity中的前向渲染

Unity中照亮物体有3种方式:

  1. 逐顶点处理 Spherical
  2. 逐像素处理 Harmonics
  3. 球谐函数 SH

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

image-20220902141112298

将渲染类型设置为Important(重要的)来告诉Unity这个光源是重要的,把它当成一个逐像素光源来处理。

通常,Unity会自动根据远近、强度等参数对光源的重要性进行排序。

  • 场景中最亮的平行光总是按逐像素处理的。

  • 渲染模式被设置成Not Important的光源,会按逐顶点或者SH处理。·渲染模式被设置成Important的光源,会按逐像素处理。

  • 如果根据以上规则得到的逐像素光源数量小于Quality Setting中的逐像素光源数量(Pixel Light Count),会有更多的光源以逐像素的方式进行渲染。

内置变量函数

image-20220902142017381

image-20220902142034183

相关参考

Unity渲染路径 - 知乎 (zhihu.com)

顶点照明渲染路径

顶点照明渲染路径是对硬件配置要求最少、运算性能最高,但同时也是得到的效果最差的一种类型,它不支持那些逐像素才能得到的效果,例如阴影、法线映射、高精度的高光反射等。

:book:同理,使用逐顶点的方式进行光照计算。——是前向渲染的一个子集。

延迟渲染路径

当场景中包含大量实时光源时,前向选人的性能会急速下降。

除了前向渲染中使用的颜色缓冲和深度缓冲之外,延迟渲染还需要利用额外的缓冲——这些缓冲被统称为GBuffer。

原理

image-20220902143817442

在光照计算Pass中直接存储法线,表面情况等,从Gbuff取到数据后直接在光照Pass中计算,故而延迟渲染和场景复杂度不挂钩,通常就只使用两个Pass完成故而效率较高。

缺点

  • 不支持真正的抗锯齿(anti-aliasing)功能。
  • 不能处理半透明物体。
  • 对显卡有一定要求。如果要使用延迟渲染的话,显卡必须支持MRT(Multiple Render Targets)、Shader Mode 3.0及以上、深度渲染纹理以及双面的模板缓冲。

通常我们使用前向渲染路径类型:)

Unity光源类型

阴影

不透明物体的阴影

image-20220913113734111

通过MeshRender可以设置阴影

将CastShaows 设置为Two Sided可以双面渲染。

Unity选择使用一个额外的Pass来专门更新光源的阴影映射纹理,这个Pass就是LightMode标签被设置为ShadowCasterPass

  • 接收阴影:对阴影纹理进行采样,最终把阴影纹理和光照进行相乘。
  • 投射阴影:加入到光源的阴影纹理计算中,通过指定的Pass来实现,如果使用了屏幕空间投射,还会生成一张摄像机的深度图。

接收阴影

  1. 在BasePass中包含内置文件:
1
#include "AutoLight.cginc"
  1. 在顶点着色器的输出结构体中添加SHADOW_COORDS

SHADOW_COORDS(2)

  1. 在顶点着色器返回之前添加一个内置宏TRANSFER_SHADOW

TRANSFER_SHADOW(o)

  1. 在片元着色器中计算阴影值,使用SHADOW_ATTENUATION

fixed shadow=SHADOW_ATTENUATION(i)

:book:PS:由于这些宏中会使用上下文变量来进行相关计算,例如TRANSFER_SHADOW会使用v.vertex或a.pos来计算坐标,因此为了能够让这些宏正确工作,我们需要保证自定义的变量名和这些宏中使用的变量名相匹配。我们需要保证:a2f结构体中的顶点坐标变量名必须是vertex,顶点着色器的输出结构体v2f必须命名为v,且v2f中的顶点位置变量必须命名为pos。

透明物体的阴影