目录
一、效果图和Shader
Shader "Unlit/ShadowCasterTest"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_Color("Color", Color) = (1,1,1,1)
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 100
Pass
{
Tags
{
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
float3 normal : NORMAL;
float4 worldPos : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
v2f vert(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.normal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
fixed3 normal = normalize(i.normal);
fixed3 lightDir = UnityWorldSpaceLightDir(i.worldPos.xyz);
fixed3 albedo = col.rgb * UNITY_LIGHTMODEL_AMBIENT.xyz * _Color.rgb; //纹理颜色 环境颜色 自定义颜色混合
fixed3 diff = albedo * _LightColor0.rgb * saturate(dot(normal, lightDir));//再混合平行光颜色 进行漫反射系数相乘
return fixed4(diff, 1);
}
ENDCG
}
//投射阴影的Pass 即本章节主题:ShadowCaster
Pass
{
Tags{
"LightMode" = "ShadowCaster"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float4 uv : TEXCOORD0;
};
struct v2f {
V2F_SHADOW_CASTER;
};
v2f vert(appdata v) {
v2f o;
TRANSFER_SHADOW_CASTER(o);
return o;
}
fixed4 frag(v2f i) : SV_Target {
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
}
二、ShadowCaster讲解
1、LightMode="ShadowCaster"
把物体的深度信息渲染到阴影映射纹理(shadowmap)或一张深度纹理中
2、#pragma_compile_shadowcaster (未知,留坑)
3、V2F_SHADOW_CASTER
它是一个在UnityCG.cginc声明的宏,作用是声明投射阴影所需的参数,如下:
// Declare all data needed for shadow caster pass output (any shadow directions/depths/distances as needed),
// plus clip space position.
#define V2F_SHADOW_CASTER V2F_SHADOW_CASTER_NOPOS UNITY_POSITION(pos)
有两种情况:①当投射阴影是相对于点光源时 ②相对于其他光源时(如平行光和聚光灯)
①:#define V2F_SHADOW_CASTER_NOPOS float3 vec : TEXCOORD0;
②:#define V2F_SHADOW_CASTER_NOPOS
是的,你没看错,②的情况是一个空的宏。那么①声明的float3 vec是什么?后面解释。
UNITY_POSITION(pos):float4 pos : SV_POSITION;
4、TRANSFER_SHADOW_CASTER(o); // o是指v2f类型的对象,即顶点着色器的输出结构体(片元着色器的输入结构体)
// Vertex shader part, legacy. No support for normal offset shadows - because
// that would require vertex normals, which might not be present in user-written shaders.
#define TRANSFER_SHADOW_CASTER(o) TRANSFER_SHADOW_CASTER_NOPOS_LEGACY(o,o.pos)
它是一个在UnityCG.cginc声明的宏,作用于没有法线偏移的阴影情况下。同样有①和②情况(同上)
①:#define TRANSFER_SHADOW_CASTER_NOPOS_LEGACY(o,opos)
o.vec = mul(unity_ObjectToWorld, v.vertex).xyz - _LightPositionRange.xyz;
opos = UnityObjectToClipPos(v.vertex);
②:#define TRANSFER_SHADOW_CASTER_NOPOS_LEGACY(o,opos)
opos = UnityObjectToClipPos(v.vertex.xyz);
opos = UnityApplyLinearShadowBias(opos);
//暂时还未看懂,日后再理清
float4 UnityApplyLinearShadowBias(float4 clipPos)
{
#if defined(UNITY_REVERSED_Z)
// We use max/min instead of clamp to ensure proper handling of the rare case
// where both numerator and denominator are zero and the fraction becomes NaN.
clipPos.z += max(-1, min(unity_LightShadowBias.x / clipPos.w, 0));
float clamped = min(clipPos.z, clipPos.w*UNITY_NEAR_CLIP_VALUE);
#else
clipPos.z += saturate(unity_LightShadowBias.x/clipPos.w);
float clamped = max(clipPos.z, clipPos.w*UNITY_NEAR_CLIP_VALUE);
#endif
clipPos.z = lerp(clipPos.z, clamped, unity_LightShadowBias.y);
return clipPos;
}
5、SHADOW_CASTER_FRAGMENT(i)
它是一个在UnityCG.cginc的宏,参数是v2f类型,如下:
①:#define SHADOW_CASTER_FRAGMENT(i) return UnityEncodeCubeShadowDepth ((length(i.vec) + unity_LightShadowBias.x) * _LightPositionRange.w);
float4 UnityEncodeCubeShadowDepth (float z)
{
#ifdef UNITY_USE_RGBA_FOR_POINT_SHADOWS
return EncodeFloatRGBA (min(z, 0.999));
#else
return z;
#endif
}
②:#define SHADOW_CASTER_FRAGMENT(i) return 0;
这里可以看出来,点光源的情况是光源和顶点的向量长度与阴影深度值成正比关系,其他两个系数暂且未知(留坑)
unity_LightShadowBias: 光源的Bias参数值(其作用下方解释)
_LightPositionRange: xyz = pos, w = 1/range xyz是点光源位置xyz, w是点光源影响半径倒数。(下方验证)
从这里你已经隐约猜测到,点光源的奇葩情况如下动态图:
结论:点光源离物体越远阴影越明显,聚光灯离物体越近阴影越明显
-------------------2020年4月26日15:36:36---------------------更新(验证一些内置变量)
_LightPositionRange
位于UnityShaderVariables.cginc的一个内置变量float4
点光源位置:_LightPositionRange.xyz
_LightPositionRange.w是Range的倒数 (0.027),我发现这些数值是进行了四舍五入的(即精度会丢失)
unity_LightShadowBias
位于UnityShaderVariables.cginc的内置变量float4类型,其中只发现了x分量是光源的Bias值
至于yzw分量,还未知(留坑)
关于Light的Bias介绍另起一文解释:(留链接坑)
2020年5月5日00:02:45更新:补坑Bias介绍
https://blog.youkuaiyun.com/qq_39574690/article/details/105772719