文章內使用Unity 2019 LTS
昨天Day19的做出來陰影效果並沒有考慮到透明物體,所以今天來補完透明物體這一塊...
在之前的半透明物體中,提過深度緩衝與半透明這兩個會產生矛盾的地方,而陰影貼圖又需要利用深度緩衝來幫忙製作,所以讓半透明物體產生陰影會是一件奇怪的事(光會透過去),所以如果要像Day19利用Fallaback來處理陰影,會使用:
...
Fallback "Transparent/VertexLit"
...
這裡面的Fallback就沒有關於ShadowCaster的處理,如果有需要讓半透明物體可以投射影子,還是可以用:
...
Fallback "VertexLit"
...
同時也是在半透明物體這一篇的下面,很簡短的補充透明測試是甚麼,回顧一下,透明測試像是深度測試類似,開發者可以設定一個界線,只要沒有過該界線的Alpha值就直接淘汰。
以下是利用透明測試做出來的半透明效果Shader:
Shader "Learning/Ch8/alpha-test-both-sided"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
// 預設0.5,只要貼圖的Alpha值小0.5就直接剃除
_Cutoff ("Cutoff", Range(0, 1)) = 0.5
}
SubShader
{
Tags { "Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }
Pass
{
Tags { "LightMode"="ForwardBase" }
// 關閉面剃除
// 當不足Alpha值的那面被剃除時
// 需要看得到後面的通過測試的
Cull off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _Cutoff;
struct v2f
{
float4 pos : SV_POSITION;
float3 worldPos : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
float2 uv : TEXCOORD2;
};
v2f vert(appdata_base app)
{
v2f o;
o.pos = UnityObjectToClipPos(app.vertex);
o.worldPos = mul(unity_ObjectToWorld, app.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(app.normal);
o.uv = TRANSFORM_TEX(app.texcoord, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed3 norm = normalize(i.worldNormal);
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_MainTex, i.uv);
// 把沒痛過透明測試的片段剃除
clip(texColor.a - _Cutoff);
fixed3 albedo = texColor.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(norm, lightDir));
return fixed4(ambient + diffuse, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
這裡我們可以利用透明測試做出陰影效果,把陰影效果跟透明測試合起來:
Shader "Learning/AlphaTestShadow" {
Properties {
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_MainTex ("Main Tex", 2D) = "white" {}
_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5
}
SubShader {
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
Pass {
Tags { "LightMode"="ForwardBase" }
Cull Off
CGPROGRAM
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "AutoLight.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _Cutoff;
struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
SHADOW_COORDS(3)
};
v2f vert(appdate_base v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
TRANSFER_SHADOW(o);
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_MainTex, i.uv);
clip (texColor.a - _Cutoff);
fixed3 albedo = texColor.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
fixed shadow = SHADOW_ATTENUATION(i);
return fixed4((ambient + diffuse) * shadow, 1.0);
}
ENDCG
}
}
// 換成這個來做出陰影投射
FallBack "Transparent/Cutout/VertexLit"
}