21.Shader阴影效果
1.理论基础
在Unity当中,一般会采用阴影映射纹理(shadow map)实现阴影效果 。
深度纹理:根据目标与相机的距离,越近颜色越深,反之越亮。
阴影映射纹理,则是在灯光视角的深度纹理。

很多效果可以通过深度图来实现,比如相交高亮,方向雾效,扫描效果,水体的深度效果等等。
传统的阴影实现
把顶点位置变换到光源空间下,然后对阴影映射纹理进行采样,得到该位置的深度信息。如果纹理的深度<顶点的深度 , 则说明该点位于阴影中。
而在Unity 5中,使用的是屏幕空间的阴影映射技术(Screenspace Shadow Map)。屏幕空间的阴影映射原本是延迟渲染中产生阴影。(显卡需要支持MRT)
与传统阴影差不多,区别在于是延迟渲染,只计算屏幕空间内阴影。
Unity的屏幕空间的阴影映射技术
使用ShadowCaster的Pass得到光源的阴影映射纹理以及摄像机的深度纹理。
由两者映射得到屏幕空间的阴影图,然后对阴影图采样即可。
阴影映射纹理生成过程:
Unity把摄像机放到光源的位置上,然后调用该Pass,由顶点变换得到光源空间位置,并保存深度信息到阴影映射纹理中。
屏幕空间的阴影图生成过程:
从摄像机的深度纹理里采样得到该fragment的深度值,利用矩阵变换,
视角空间->世界空间-> 光源空间坐标, 与对比光源的阴影纹理的深度对比。
如果坐标深度>纹理深度, 则在阴影中。将阴影颜色记录在阴影图中。
以上的步骤,Unity都帮忙封装好了,我只需要使用它提供的宏, 得到阴影图,然后进行采样...
2.投射阴影

生成ShadowMap,固定写法,模式为ShadowCaster,使用到3个宏
代码 (前篇的Lighting_mult.shader上修改)

核心宏
V2F_SHADOW_CASTER
TRANSFER_SHADOW_CASTER_NORMALOFFSET
SHADOW_CASTER_FRAGMENT
3.接收阴影
对阴影图采样即可。
核心代码
对于点光源 的阴影, 需要额外修改编译宏 ,其他的不变

接收到方块上阴影
核心宏
SHADOW_COORDS(n) 声明一个TEXCOORDn用于阴影采样坐标
TRANSFER_SHADOW(outputStruct o) 转换阴影的uv坐标
SHADOW_ATTENUATION(inputStruct i) 用来计算阴影值的, 相当于亮度值
完整代码
https://github.com/smartgrass/MyCodes/blob/main/ShaderLearning/Lighting_mult_shadow.shader