URP 渲染实战 / 第 16 章 透明、混合与模板测试 / 案例 16.6
案例 16.6双面材质入门
目标:让只有一层面的网格(树叶、纸片、旗帜、布料、开口的碗)正反两面都正确受光,并能给背面不同的颜色。
原理:Cull Off 只是让背面也生成片元,但插值出来的法线依然是网格的正面法线。当我们从背面看时,法线背对着我们,光照结果就是“错的那一面”的光照。修正方法是在片元里判断当前片元来自正面还是背面,背面就把法线取反。HLSL 的系统值 SV_IsFrontFace 提供这个信息,URP(准确说是 Core RP 的平台抽象层)把它包装成了三个宏,屏蔽了平台差异:
// 摘自 Core RP 14 ShaderLibrary/API/Metal.hlsl(D3D11.hlsl 中相同) #define FRONT_FACE_SEMANTIC SV_IsFrontFace #define FRONT_FACE_TYPE bool #define IS_FRONT_VFACE(VAL, FRONT, BACK) ((VAL) ? (FRONT) : (BACK))
Assets/Cookbook/Ch16/TwoSided.shader(节选:frag)
half4 frag(Varyings i, FRONT_FACE_TYPE face : FRONT_FACE_SEMANTIC) : SV_Target { // IS_FRONT_VFACE 屏蔽了平台差异:D3D/Metal 是 bool,旧的 GL 是 float 符号 bool isFront = IS_FRONT_VFACE(face, true, false); float3 N = normalize(i.normalWS); if (!isFront && _FlipBackNormal > 0.5) N = -N; half3 albedo = isFront ? _BaseColor.rgb : _BackColor.rgb; return half4(SimpleLighting(albedo, N, i.positionWS, 0.3h), 1); }

常见坑① 双面材质的阴影 Pass 也要
Cull Off,否则薄片只有一面投影,阴影会随光照角度时有时无。② 如果用了法线贴图,背面除了翻转几何法线,还要翻转 TBN 中的副切线方向(或者直接在世界空间翻转最终法线),否则凹凸方向是反的。③ 双面渲染不等于两倍开销:被剔除的三角形本来就不产生片元,Cull Off 只是让原本被剔除的那些也参与着色。真正的开销取决于背面实际被看到的面积。