ShadowMap说起来十分简单,把摄像机和光源的位置重叠,那么场景中该光源的阴影区域就是那些摄像机看不到的地方,主要应用在前向渲染路径中。
具体实现分以下几个步骤:
延迟渲染中的光照计算绝大部分都是在屏幕空间里进行的,同样也包括阴影。这种屏幕空间的阴影实现主要有这么几个步骤:
二者的主要异同就是:两者都会渲染光源空间的深度图,但前者的采样发生在光源空间,片元坐标转换到光源空间对ShadowMap采样,而后者会做一次阴影收集计算(Shadow Collecctor)得到屏幕空间阴影纹理,片元在屏幕空间对阴影纹理采样。
截止到Unity 5.4,当项目工程的目标平台是Mobile的时候,就不会使用屏幕空间的阴影映射技术,即使用原始的Shadows Map方法。在代码里,Unity会定义内置宏UNITY_NO_SCREENSPACE_SHADOWS来控制。而当项目工程的目标平台是支持屏幕空间阴影的话,例如PC, Mac & Linux Standalone平台时,会开启屏幕空间的阴影映射技术。
我们可以通过帧调试器(Frame Debugger)来分辨当前是否使用了屏幕空间的阴影映射技术:
三个内置宏(SHADOW_COORDS, TRANSFER_SHADOW, SHADOW_ATTENUATION) 就是计算阴影的三个主要部分。可以在AutoLight.cginc中找到它们的声明。
作用:让物体能够接收阴影,原理是采样“LightMode” = “ShadowCaster" Pass里渲染出来的阴影深度图,然后与光照融合,阴影越强烈,贴图像素数值越靠近0
需要在Pass中包含新的内置文件 #include "AutoLight.cginc"
它的作用是声明一个用于对阴影纹理采样的uv坐标。一般用于片元着色器的输入结构体中,而且这个宏的参数需要是下一个可用插值寄存器的索引值,本例中是2。
例如:
// 片元着色器的输入结构体
struct Interpolators{
flaot4 uv : TEXCOORD0;
float3 normal : TEXCOORD1;
float4 pos : SV_POSITION; //裁剪坐标,变量名要写死为pos,配合TRANSFER_SHADOW
SHADOW_COORDS(2) // 相当于float4 _ShadowCoord : TEXCOORD2
}
源码:
#define SHADOW_COORDS(idx1) unityShadowCoord4 _ShadowCoord : TEXCOORD##idx1;
作用:得到一个用于采样阴影贴图的坐标
TRANSFER_SHADOW 会根据平台的不同而有所差异:
1:如果当前平台可以使用屏幕空间的阴影映射技术(SCREENSPACE_SHADOWS),则会调用内置的ComputeScreenPos函数计算屏幕空间的uv坐标,存储在_ShadowCoord,后续直接用屏幕uv坐标采样屏幕阴影贴图;
2:如果不支持则会使用传统的阴影映射技术,TRANSFER_SHADOW会把顶点坐标从模型空间转换到光源空间后存储到_ShadowCoord中,后续根据坐标信息对ShadowMap采样。
例如:
// 顶点着色器, 参数命名要写死v,v里面的顶点坐标要写死vertex,配合TRANSFER_SHADOW
Interpolators MyVertexProgram(appdata v){
Interpolators o;
o.pos = UnityObjectToClipPos(v.vertex); // 裁剪坐标,变量名要写死为pos,配合TRANSFER_SHADOW
TRANSFER_SHADOW(o);
return o;
}
源码:
红框部分:
用法1:在片元着色器中,把片元函数输入结构体传给SHADOW_ATTENUATION,直接得到衰减
UnityLight light;
// 片元着色器中使用
float attenuation = SHADOW_ATTENUATION(i)
light.color = _LightColor0.rgb * attenuation;
用法2:在片元着色器中,把片元函数输入结构体传给UNITY_LIGHT_ATTENUATION(attenuation, i, i.worldPos)的第二个参数,然后间接调用SHADOW_ATTENUATION
UnityLight light;
// 片元着色器中使用
UNITY_LIGHT_ATTENUATION(attenuation, i, i.worldPos);
light.color = _LightColor0.rgb * attenuation;
UNITY_LIGHT_ATTENUATION解析:https://blog.csdn.net/zengjunjie59/article/details/109533698
源码:
红框部分:
以上是以直射光作为例子讲解的,不同灯光类型的宏会略有不同,具体请看unity buildin的源码