首先光源要开启阴影类型 :Shadow Type 改为不是No的类型,一般选择Soft Shadows
地板(影子的载体) :
5.0以前,系统内建的shader,只能接收平行光产生的投影;5.0版以后的标准着色器则就可以接收任何形式的光源的投影
如果在4.x版本,如果想要让点光源投射的阴影也能显示,将playersettings中的Rendering Path 的 forward 改为其它延迟光照选项即可
自编写的Shader 要达到既能投射阴影,又能接收阴影的效果
如果只需要接收平行光的投影,可以只加入一个空的pass通道,将标签设为 "Shadowcaster", 阴影投射器
Pass
{
tags { " LightMode " = " Shadowcaster " }
}
,不需要作其它任何代码的编写。
加上阴影投射器后,就能对平行光投影的阴影产生效果,但是此时并不能对点光源产生效果。 如果需要对所有的光源都能投影产生阴影效果,显然,只用阴影投射器的做法是不能达到要求的。
使用 : fallback "Diffuse" ,即可以对所有的光源的投影都产生阴影效果。
接收阴影Shader(地板) :
#include "autolight.cginc"
4.x版本,使用三个宏 :
第一个宏 :LIGHTING_COORDS(idx1 , idx2) 有语义,所以只能在结构体和函数中使用,不需要分号
放在结构体中使用 :LIGHTING_COORDS(0 , 1)
// 包含了 unityShadowCoord3_LightCoord : TEXCOORD0;
unityShadowCoord3_ShadowCoord : TEXCOORD1; 两个变量
第二个宏 :TRANSFER_VERTEX_TO_FRAGMENT(struct) 放在顶点函数中,实质上是对第一个宏的两个变量进行赋值,不需要分号
第三个宏 :LIGHT_ATTENUATION(struct) ; 需要分号,放在片段函数中,描述光的衰减程度,返回一个float值
float atten = LIGHT_ATTENUATION(IN);
// atten变量描述最后渲染的部分是否为阴影所照射,照射后达到什么深度
5.x版本 :第三个宏 可以换成 :UNITY_LIGHT_ATTENUATION(destName , input , worldPos) ;
// 参数 :fixed类型,在宏的内部声明 、 结构体 、 顶点的世界坐标
此时,地板已经能够接收到平行光投射的阴影,如果想要再加上别的光源,很简单 :
完全复制、粘贴一份pass通道,然后将tags改为 :
tags { "LightMode" = "ForwardAdd"}
Blend one one
因为,当有两个pass通道时,系统只会保留第二个pass通道,达不到我们想要的结果,所以,需要作Blend操作。 在第二个pass中加上" Blend one one",目的是让当前pass通道全部通过。此时,便可以既能接收平行光投影,又能接收像素光的投影。
优化 :因为将两个pass完全混合,所以不需要两个环境光,可以删掉一个环境光
总结 :如果想要编写一个复杂的shader与光交互,建议使用surfaceshader。
Shader "Custom/MyDiffuseShadow" {
SubShader
{
Pass
{
Tags { "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
#include "lighting.cginc"
#include "autolight.cginc" // 包含三个宏
struct2 v2f {
float4 pos : POSITION;
fixed4 color : COLOR;
LIGHTING_COORDS(0,1)
// 第一个宏,在结构体中使用,unity自带的宏,包含两个变量 :unityShadowCoord3 _LightCoord : TEXCOORD0; 和 unityShadowCoord3 _ShadowCoord : TEXCOORD1;
};
v2f vert (appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP , v.vertex);
float3 N = normalize(v.normal);
float3 L = normalize(_WorldSpaceLightPos0);
N = mul(float4(N,0) , _World2Object).xyz ;
N = normalize(N);
float ndotl = saturate(dot(N,L));
o.color = _LightColor0 * ndotl; // 光线颜色
float3 wpos = mul(_Object2World , v.vertex).xyz; // 顶点在世界坐标系中的位置
o.color.rgb += Shade4PointLights( unity_4LightPosX0 , unity_4LightPosY0 , unity_4LightPosZ0 ,
unity_LightColor[0].rgb , unity_LightColor[1].rgb ,
unity_LightColor[2].rgb , unity_LightColor[3].rgb ,
unity_4LightAtten0 ,
wpos , N) ;
TRANSFER_VERTEX_TO_FRAGMENT(o) // 第二个宏 :实质上是对结构体中的宏(LIGHTING_COORDS) 的变量进行赋值
return o;
}
fixed4 frag(v2f IN) : COLOR
{
float atten = LIGHT_ATTENUATION(IN) ; // 第三个宏 :描述光的衰减程度,参数也是一个struct,返回一个float值
// atten变量,描述最后渲染的部分是否被阴影所照射,照射后达到什么深度
// UNITY_LIGHTMODEL_ATTENUATION(atten , IN , wpos)
5.x版本,atten是一个fixed类型,在宏内部声明的变量;IN是结构体,wpos是顶点在世界坐标系中的位置
fixed4 col = IN.color + UNITY_LIGHTMODEL_AMBIENT;
col.rgb *= atten;
return col ;
}
ENDCG
}
Pass
{
Tags { "LightMode" = "ForwardBase" }
Blend one one
CGPROGRAM
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
#include "lighting.cginc"
#include "autolight.cginc"
struct2 v2f {
float4 pos : POSITION;
fixed4 color : COLOR;
LIGHTING_COORDS(0,1)
};
v2f vert (appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP , v.vertex);
float3 N = normalize(v.normal);
float3 L = normalize(_WorldSpaceLightPos0);
N = mul(float4(N,0) , _World2Object).xyz ;
N = normalize(N);
float ndotl = saturate(dot(N,L));
o.color = _LightColor0 * ndotl; // 光线颜色
float3 wpos = mul(_Object2World , v.vertex).xyz; // 顶点在世界坐标系中的位置
o.color.rgb += Shade4PointLights( unity_4LightPosX0 , unity_4LightPosY0 , unity_4LightPosZ0 ,
unity_LightColor[0].rgb , unity_LightColor[1].rgb ,
unity_LightColor[2].rgb , unity_LightColor[3].rgb ,
unity_4LightAtten0 ,
wpos , N) ;
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o;
}
fixed4 frag(v2f IN) : COLOR
{
float atten = LIGHT_ATTENUATION(IN) ;
col.rgb *= atten;
return col ;
}
ENDCG
}
}
}
Pass
{
Tags { "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
#include "lighting.cginc"
#include "autolight.cginc" // 包含三个宏
struct2 v2f {
float4 pos : POSITION;
fixed4 color : COLOR;
LIGHTING_COORDS(0,1)
// 第一个宏,unity自带的宏,包含两个变量 :unityShadowCoord3 _LightCoord : TEXCOORD0; 和 unityShadowCoord3 _ShadowCoord : TEXCOORD1;
};
v2f vert (appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP , v.vertex);
float3 N = normalize(v.normal);
float3 L = normalize(_WorldSpaceLightPos0);
N = mul(float4(N,0) , _World2Object).xyz ;
N = normalize(N);
float ndotl = saturate(dot(N,L));
o.color = _LightColor0 * ndotl; // 光线颜色
float3 wpos = mul(_Object2World , v.vertex).xyz; // 顶点在世界坐标系中的位置
o.color.rgb += Shade4PointLights( unity_4LightPosX0 , unity_4LightPosY0 , unity_4LightPosZ0 ,
unity_LightColor[0].rgb , unity_LightColor[1].rgb ,
unity_LightColor[2].rgb , unity_LightColor[3].rgb ,
unity_4LightAtten0 ,
wpos , N) ;
TRANSFER_VERTEX_TO_FRAGMENT(o) // 第二个宏 :实质上是对结构体中的宏(LIGHTING_COORDS) 的变量进行赋值
return o;
}
fixed4 frag(v2f IN) : COLOR
{
float atten = LIGHT_ATTENUATION(IN) ; // 第三个宏 :参数也是一个struct,返回一个float值
fixed4 col = IN.color + UNITY_LIGHTMODEL_AMBIENT;
col.rgb *= atten;
return col ;
}
ENDCG
}