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

Shader入门精要(九)复杂光照
fasty复杂光照
在之前的学习中,我们使用的都是单一光照,实际在游戏中可能存在多个光源,不同的光源会互相影响构成真正的光照系统,在这一节我们将实现一个真正可用的光照模型。
渲染路径 Rendering Path
:book: 决定了光照是如何应用到Unity Shader中的。
我们只有为Shader正确地选择和设置了需要的渲染路径,该Shader的光照计算才能被正确执行。
:label:渲染路径的分类
- 前向渲染路径(Forward Rendering Path)
- 延迟渲染路径(Deferred Rendering Path)
- 顶点照明渲染路径(Vertex Lit Rendering Path)——已经被弃用
目前unity提供了新的渲染路径代替了原来的渲染路径。
默认使用 Graphics中的设置,可以在摄像机中对设置进行覆盖。
在Shader Pass中来指定该Pass使用的渲染路径:
1 | Pass { Tags { "LightMode" = "ForwardBase" } } |
LightMode标签可供使用的渲染路径:
:thought_balloon:为Pass指定正确的渲染路径对于Unity光照变量正确赋值具有重要意义。
Unity默认使用前向渲染光照路径.
前向渲染路径
前向渲染是传统渲染方式,也是我们常用的一种渲染路径。
:book: 原理:每进行一次完整的前向渲染,我们需要渲染该对象的渲染图元,并计算两个缓冲区的信息:颜色缓冲区和深度缓冲区。
每个光照下的物体都需要进行一次逐像素的Pass,也就是在一个场景中,n个物体m个光源的下,渲染场景需要n*m次Pass。
Unity中的前向渲染
Unity中照亮物体有3种方式:
- 逐顶点处理 Spherical
- 逐像素处理 Harmonics
- 球谐函数 SH
光源使用哪一种处理方式取决于它的类型和渲染模式。
将渲染类型设置为Important(重要的)来告诉Unity这个光源是重要的,把它当成一个逐像素光源来处理。
通常,Unity会自动根据远近、强度等参数对光源的重要性进行排序。
场景中最亮的平行光总是按逐像素处理的。
渲染模式被设置成Not Important的光源,会按逐顶点或者SH处理。·渲染模式被设置成Important的光源,会按逐像素处理。
如果根据以上规则得到的逐像素光源数量小于Quality Setting中的逐像素光源数量(Pixel Light Count),会有更多的光源以逐像素的方式进行渲染。
内置变量函数
相关参考
顶点照明渲染路径
顶点照明渲染路径是对硬件配置要求最少、运算性能最高,但同时也是得到的效果最差的一种类型,它不支持那些逐像素才能得到的效果,例如阴影、法线映射、高精度的高光反射等。
:book:同理,使用逐顶点的方式进行光照计算。——是前向渲染的一个子集。
延迟渲染路径
当场景中包含大量实时光源时,前向选人的性能会急速下降。
除了前向渲染中使用的颜色缓冲和深度缓冲之外,延迟渲染还需要利用额外的缓冲——这些缓冲被统称为GBuffer。
原理
在光照计算Pass中直接存储法线,表面情况等,从Gbuff取到数据后直接在光照Pass中计算,故而延迟渲染和场景复杂度不挂钩,通常就只使用两个Pass完成故而效率较高。
缺点
- 不支持真正的抗锯齿(anti-aliasing)功能。
- 不能处理半透明物体。
- 对显卡有一定要求。如果要使用延迟渲染的话,显卡必须支持MRT(Multiple Render Targets)、Shader Mode 3.0及以上、深度渲染纹理以及双面的模板缓冲。
通常我们使用前向渲染路径类型:)
Unity光源类型
阴影
不透明物体的阴影
将CastShaows 设置为Two Sided可以双面渲染。
Unity选择使用一个额外的Pass来专门更新光源的阴影映射纹理,这个Pass就是
LightMode标签被设置为ShadowCaster的Pass。
- 接收阴影:对阴影纹理进行采样,最终把阴影纹理和光照进行相乘。
- 投射阴影:加入到光源的阴影纹理计算中,通过指定的Pass来实现,如果使用了屏幕空间投射,还会生成一张摄像机的深度图。
接收阴影
- 在BasePass中包含内置文件:
1 |
- 在顶点着色器的输出结构体中添加
SHADOW_COORDS
SHADOW_COORDS(2)
- 在顶点着色器返回之前添加一个内置宏
TRANSFER_SHADOW
TRANSFER_SHADOW(o)
- 在片元着色器中计算阴影值,使用
SHADOW_ATTENUATION
fixed shadow=SHADOW_ATTENUATION(i)
:book:PS:由于这些宏中会使用上下文变量来进行相关计算,例如TRANSFER_SHADOW会使用v.vertex或a.pos来计算坐标,因此为了能够让这些宏正确工作,我们需要保证自定义的变量名和这些宏中使用的变量名相匹配。我们需要保证:a2f结构体中的顶点坐标变量名必须是vertex,顶点着色器的输出结构体v2f必须命名为v,且v2f中的顶点位置变量必须命名为pos。










