如何在植被Shader中实现半透明阴影接收
解读
国内项目里植被(草、树叶、蕨类)普遍使用Alpha Test + Alpha Blend混合渲染,但Unity内置ShadowCaster只认Alpha Test(clip/discard),导致半透明区域无法接收阴影;面试官想确认你能否在URP/HDRP下把阴影收集(Shadow Collector) 阶段也做半透明采样,并兼顾移动端带宽与Overdraw压力。
知识点
- 阴影映射管线:Unity在Shadow Pass里只渲染深度,默认Alpha Test;半透明物体不参与,因此阴影贴图里没有半透明信息。
- 阴影收集(Shadow Collector)/屏幕空间阴影:URP在Additional Lights和Main Light分别走Screen Space Shadow和Cascade Shadowmap;需要把阴影衰减乘进半透明片元。
- 自定义Shadow Receiver:在ForwardBase或ForwardTransparent里手动采样_MainLightShadowmapTexture与_AdditionalLightsShadowmapTexture,用植被世界坐标计算shadowCoord,再与Alpha做lerp(1, shadowAttenuation, alpha)。
- 半透明排序与ZWrite冲突:植被需关闭ZWrite、队列=Transparent+250、ShadowCaster单独写Alpha Test版本,防止阴影断裂。
- 移动端优化:
- 用4-tap PCF代替7×7 PCF;
- 在Shader Variant里**#pragma skip_variants DIRLIGHTMAP_COMBINED**减少变体;
- 级联混合用lerp而非branch防止warp divergence。
答案
分四步落地:
-
ShadowCaster Pass仍用Alpha Test保证深度写入:
Pass { Name "ShadowCaster" ZWrite On Cull Off HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" half4 frag (Varyings i) : SV_TARGET { half alpha = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv).a; clip(alpha - _Cutoff); return 0; } ENDHLSL } -
Transparent Pass里手动采样阴影:
half4 frag (Varyings i) : SV_TARGET { half4 col = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv); float4 shadowCoord = TransformWorldToShadowCoord(i.worldPos); half shadowAtt = MainLightRealtimeShadow(shadowCoord); // 内置URP函数 col.rgb *= lerp(1, shadowAtt, col.a); // 半透明越淡,阴影越弱 return col; } -
队列与混合设置:
Tags { "Queue"="Transparent+250" "RenderType"="TransparentCutout" } Blend SrcAlpha OneMinusSrcAlpha ZWrite Off -
美术规范:
- Alpha通道用渐变而非硬边,防止阴影跳变;
- 植被面片不超过300三角,Overdraw控制在**2×**以内;
- 关闭级联阴影的Soft Shadow选项,iOS A14以下机型用2级联。
拓展思考
- HDRP下可用Micro Shadow+Contact Shadow做次表面散射阴影,但需Custom Pass把shadow mask写入VT(Virtual Texture),带宽翻倍,中高端机才开。
- WebGL无Native Shadowmap,可预烘焙植被Shadow Mask到Lightmap的Alpha8通道,运行时采样代替实时阴影,包体+0.8 MB但帧率+15%。
- GPU Driven场景可用Clustered Shadow把植被实例化ID写入StructuredBuffer,在Compute Shader里一次PCF完成256草的阴影接收,DrawCall=1,骁龙888实测0.4 ms。