这里光照模型为了简单只使用了漫反射
在forwardbase中使用如下宏采样平行光阴影:
SHADOW_COORDS(1) // 接受shadowmap的uv索引值
TRANSFER_SHADOW(o); // 根据光的范围进行缩放和再计算uv值
SHADOW_ATTENUATION(i); // 采样阴影贴图
在forwardadd由于光源类型不同(光源衰减值不同)同时又需要计算阴影,Unity内置了一个宏可以完成这两件事:
LIGHTING_COORDS(5, 6) // 定义光照衰减的uv 和 shadowmap 的uv
TRANSFER_VERTEX_TO_FRAGMENT(o); // 计算 shadowmap uv 和 light 衰减 uv
half attenuation = LIGHT_ATTENUATION(i); // 可以使用宏直接计算衰减*阴影的结果
这些宏需要使用到物体的世界坐标信息,因此对于a2v,v2f结构体中必须有指定的名称:
v2f vert(a2v v) {
v2f o; // 这里必须是o
o.pos = UnityObjectToClipPos(v.vertex); // 两个结构体中必须有o.pos 和 v.vertex
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
TRANSFER_SHADOW(o); // 宏-阴影uv计算
return o;
}
由于forwardadd中需要处理多个光源的光照,如果需要显示多个光源的阴影需要定义如下的命令:
#pragma multi_compile_fwdadd_fullshadows
// multi_compile_fwdadd_fullshadows 多光照阴影(可以物体可接受多个光照的阴影)
// multi_compile_fwdadd 只能接受一个,如果定义这个则不会传递其他光照的阴影贴图进来
如果需要自定义衰减值也可以自己通过宏来区分光源的类型,来自定义对不同光源的衰减值进行处理:
//【不同光源的光照方向】
#ifdef USING_DIRECTIONAL_LIGHT
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
#else
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
#endif
fixed3 diffuse = _LightColor0.rgb * max(0, dot(worldNormal, worldLightDir));
// 不同光源的衰减值
#ifdef USING_DIRECTIONAL_LIGHT // 平行光
fixed atten = 1.0;
#else
#if defined (POINT) // 点光灯
float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;
fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
#elif defined (SPOT) // 聚光灯
float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1));
fixed atten = (lightCoord.z > 0)
* tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w
* tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
#else
fixed atten = 1.0;
#endif
#endif
float shadow = SHADOW_ATTENUATION(i); // 采样阴影贴图
完整代码
ForwardBase Pass
Pass
{
Tags { "LightMode"="ForwardBase" } //计算平行光
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase // forward base 光照
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION; // 这个坐标名称一定要是 pos, TRANSFER_SHADOW会使用
float3 pos_world : TEXCOORD3;
SHADOW_COORDS(1) // 使用TEXCOORD1 存放
float3 normal_world : TEXCOORD2;
};
v2f vert(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.pos_world = mul(unity_ObjectToWorld, v.vertex).xyz;
o.normal_world = UnityObjectToWorldNormal(v.normal);
TRANSFER_SHADOW(o);
return o;
}
float4 _LightColor0; // unity内置变量 - lightcolor
half4 frag(v2f i) : SV_Target
{
i.normal_world = normalize(i.normal_world);
float3 light_dir = normalize(UnityWorldSpaceLightDir(i.pos.xyz));
float3 diffuse = max(0., dot(i.normal_world, light_dir)) * _LightColor0.rgb;
half shadow = SHADOW_ATTENUATION(i);
float3 final_col = diffuse * shadow;
return half4(final_col, 1.0f);
}
ENDCG
}
ForwardAdd Pass
Pass
{
Tags { "LightMode"="ForwardAdd" }
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdadd_fullshadows // 多个阴影
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION; // 这个坐标名称一定要是 pos, TRANSFER_SHADOW会使用
float3 pos_world : TEXCOORD3;
LIGHTING_COORDS(5, 6) // 定义光照衰减的uv 和 shadowmap 的uv
float3 normal_world : TEXCOORD2;
};
v2f vert(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.pos_world = mul(unity_ObjectToWorld, v.vertex).xyz;
o.normal_world = UnityObjectToWorldNormal(v.normal);
TRANSFER_VERTEX_TO_FRAGMENT(o); // 计算 shadowmap uv 和 light 衰减 uv
return o;
}
float4 _LightColor0; // unity内置变量 - lightcolor
half4 frag(v2f i) : SV_Target
{
// v2f中定义了 _LightCoord 可以使用宏直接计算 衰减值*阴影值
half attenuation = LIGHT_ATTENUATION(i);
fixed3 light_dir = normalize(UnityWorldSpaceLightDir(i.pos_world));
fixed3 normal_dir = normalize(i.normal_world);
half3 diffuse = max(0., dot(normal_dir, light_dir)) * _LightColor0.rgb * attenuation;
half3 final_color = diffuse * attenuation;
return half4(final_color, 1.0f);
}
ENDCG
}
Shadow Caster Pass
Fallback "Diffuse"