屏幕空间的阴影投射
unity会调用lightmode为ShadowCaster的Pass来得到可投射阴影的光源的阴影投射纹理和摄像机的深度纹理,然后根据它们的纹理来得到屏幕空间的阴影图,如果摄像机的深度纹理记录的深度值大于转换到阴影投射纹理中的深度值,就证明该表面在阴影中。
如果想要物体接受投影,只需要在shader中对阴影图采样,首先把表面坐标从模型空间变换到屏幕空间中,然后使用这个坐标对阴影图进行采样。
不透明物体投射阴影
通用过Mesh Renderer组件中的Cast Shadows 和 Receive Shadows属性控制投射或接受阴影。
有的shader虽然没有使用ShadowCaster的Pass但仍然可以投射阴影,是因为fallback中最后会调用到unity内置的VertexLit,里面包含了该Pass
让物体接收阴影
需要注意的:里面的宏辉使用上下文变量来计算,如 TRANSFER_SHADOW必须保证a2v的顶点坐标变量名为vertex,v2f中的顶点位置变量名为pos
Shader "Unity Shaders Book/Chapter 9/Shadow" {
Properties {
_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
_Specular ("Specular", Color) = (1, 1, 1, 1)
_Gloss ("Gloss", Range(8.0, 256)) = 20
}
SubShader {
Tags {
"RenderType"="Opaque" }
Pass {
// Pass for ambient light & first pixel light (directional light)
Tags {
"LightMode"="ForwardBase" }
CGPROGRAM
// Apparently need to add this declaration
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
// Need these files to get built-in macros
#include "Lighting.cginc"
//计算阴影的宏在该文件中
#include "AutoLight.cginc"
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
//声明一个用于对阴影纹理采样的坐标,参数必须是下一个可用的插值寄存器的索引值
SHADOW_COORDS(2)
};
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
// Pass shadow coordinates to pixel shader
//计算v2f中声明的阴影纹理坐标,如果平台可以使用屏幕空间的阴影投射技术(判断是否定义UNITY_NO_SCREENSPACE_SHADOWS)
//如果定义了,就会调用ComputerScreenPos函数来计算_ShadowCoord,把顶点坐标从模型空间变换到光源空间后存储到_ShadowCoord中
TRANSFER_SHADOW(o);
return o;
}
fixed4 frag(v2f i