前言:本篇博客只是一个简单的实现方向光和点光源产生阴影功能的例子,主要是当做笔记使用。
核心要点:
1.光源(方向光或者点光源等)必须设置阴影类型,否则将不会产生对应光源的阴影。如下图所示:
2.阴影投射物体上面必须开启投射阴影功能,否则将不会传递光源产生的阴影。如下图所示:
3.阴影接收物体上面必须开启接收阴影功能,否则将不会显示光源产生的阴影。如下图所示:
4.可以写一个LightMode为ShadowCaster的pass来投射方向光阴影,也可以使用FallBack指定shader文件中的投射阴影类型。
5.接收光源阴影时,可以使用AutoLight.cginc文件中针对unity 4.0以及5.0或者更高版本的光照处理宏。如4.0中使用LIGHTING_COORDS宏定义阴影相关变量,在顶点着色器中使用TRANSFER_VERTEX_TO_FRAGMENT宏来赋值阴影相关变量,在片段着色器中使用LIGHT_ATTENUATION宏来使用阴影相关变量得到一个阴影强度值。然后使用该阴影强度值和获取的最终颜色值相乘,从而获取阴影处理后的颜色值。
6.在Forward渲染路径中,光照模型为ForwardBase时,可以使用#pragma multi_compile_fwdbase编译指令接收方向光阴影。光照模型为ForwardAdd时,可以使用#pragma multi_compile_fwdadd_fullshadows编译指令接收点光源阴影。具体的接收宏接口参见第5点。同时由于AutoLight.cginc文件中关于阴影处理相关宏实现部分使用v结构体成员,所以在着色器输入参数中需要将包含该成员的结构体参数名设定为v。
7.在多个pass处理不同光源阴影时,需要使用blend one one来混合每个pass的颜色值,从而保证pass处理的颜色值有效。
核心代码:如下所示:
Shader "Custom/MyShadow" {
Properties {
_MainColor ("MainColor", Color) = (1,1,1,1)
}
SubShader {
//pass {
// // 投射方向光阴影
// Tags { "LightMode"="ShadowCaster" }
//}
pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
#include "lighting.cginc"
#include "autolight.cginc"
#pragma multi_compile_fwdbase
struct v2f {
float4 pos:POSITION0;
fixed3 normal:POSITION1;
float4 vertex:POSITION2;
// 定义阴影相关的变量
LIGHTING_COORDS(0, 1)
};
fixed4 _MainColor;
v2f vert(appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.normal = v.normal;
o.vertex = v.vertex;
// 对阴影相关变量赋值
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o;
}
fixed4 frag(v2f v):COLOR0
{
// 获取世界空间中不受模型缩放影响的归一化法向量:模型到世界的转逆矩阵对模型顶点坐标进行变换
float3 N = UnityObjectToWorldNormal(v.normal);
// 获取世界空间中归一化的光照向量
float3 L = normalize(WorldSpaceLightDir(v.vertex));
// 获取光照强度:取法向量和光照向量点积值,值越大,夹角越小,光照强度越大。值为负数时光照在平面背面,可以不做光照处理
float ndotl = saturate(dot(N, L));
// 获取漫反射颜色
fixed4 diffuseCol = _MainColor * _LightColor0 * ndotl;
// 获取环境光颜色
fixed4 ambientCol = UNITY_LIGHTMODEL_AMBIENT;
// 使用阴影相关变量来获取阴影强度
float atten = LIGHT_ATTENUATION(v);
// 获取兰伯特模型光照颜色:漫反射颜色+环境光颜色
fixed4 col = diffuseCol + ambientCol;
col.rgb *= atten;
return col;
}
ENDCG
}
pass {
Tags { "LightMode"="ForwardAdd" }
blend one one
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
#include "lighting.cginc"
#include "autolight.cginc"
#pragma multi_compile_fwdadd_fullshadows
struct v2f {
float4 pos:POSITION0;
fixed3 normal:POSITION1;
float4 vertex:POSITION2;
// 定义阴影相关的变量
LIGHTING_COORDS(0, 1)
};
fixed4 _MainColor;
v2f vert(appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.normal = v.normal;
o.vertex = v.vertex;
// 对阴影相关变量赋值
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o;
}
fixed4 frag(v2f i):COLOR0
{
// 获取世界空间中不受模型缩放影响的归一化法向量:模型到世界的转逆矩阵对模型顶点坐标进行变换
float3 N = UnityObjectToWorldNormal(i.normal);
// 获取世界空间中归一化的光照向量
float3 L = normalize(WorldSpaceLightDir(i.vertex));
// 获取光照强度:取法向量和光照向量点积值,值越大,夹角越小,光照强度越大。值为负数时光照在平面背面,可以不做光照处理
float ndotl = saturate(dot(N, L));
// 获取漫反射颜色
fixed4 diffuseCol = _MainColor * _LightColor0 * ndotl;
// 获取环境光颜色
fixed4 ambientCol = UNITY_LIGHTMODEL_AMBIENT;
// 使用阴影相关变量来获取阴影强度
float atten = LIGHT_ATTENUATION(i);
// 获取兰伯特模型光照颜色:漫反射颜色+环境光颜色,由于上面pass已经加了环境光,这里就不加了
fixed4 col = diffuseCol;
col.rgb *= atten;
return col;
}
ENDCG
}
}
// 没有的部分从Diffuse着色器中去获取。比如:阴影
FallBack "Diffuse"
}
运行效果:如下图所示: