GameTech/URP 渲染实战

案例 16.8传送门 / 窗口进阶

目标:一扇门框里能看到另一个世界——紫色天幕、青色地面和几个物体,它们只在门框范围内可见;从侧面看,门里的世界依然在“门后”。

原理:用一块不可见的遮罩(门洞大小的 Quad)在模板缓冲里写 1,门里世界的所有物体都设置“模板 = 1 才画”。遮罩必须在门里的物体之前绘制,所以它的队列是 Geometry-10:

Assets/Cookbook/Ch16/StencilMask.shader(节选:state)
ColorMask 0
ZWrite Off
Cull Off
Stencil
{
    Ref [_StencilRef]
    Comp Always
    Pass Replace      // 通过(含深度测试)就把模板值替换为 Ref
}
ColorMask 0
ZWrite Off
Cull Off
Stencil
{
    Ref [_StencilRef]
    Comp Always
    Pass Replace      // 通过(含深度测试)就把模板值替换为 Ref
}

遮罩不写颜色(ColorMask 0)也不写深度——如果写了深度,门后的物体就会被这块看不见的 Quad 挡住。门里的物体用 StencilLit,设置 Comp Equal、Ref 1;门里的天幕是一个很大的球,Cull Front 从内部看,用无光照模式输出纯色。

还有一个容易忽略的地方:门外的地面是一张 60 米的大平面,它在门洞后面的部分在深度上可能比门里的物体更近(比如门里的地面在同样高度),如果门外地面不做任何模板测试,就会把门里的世界盖掉。所以门外地面也要设置模板条件:Comp NotEqual。一个可靠的规则是:凡是会出现在门洞后方的“外部”物体,都要设置 NotEqual;只出现在门前的外部物体可以不管。

图 16-13左:正面看门洞,门里是另一个世界(不同的天空、地面和物体);右:从侧面看,门里的物体依然在“门后”,透视关系正确,而门框以外完全看不到它们
常见坑① 门里的物体关掉了阴影投射(ShadowCastingMode.Off),因为阴影 Pass 不做模板测试,它们的影子会出现在门外的地面上。门外物体的影子却会落到门里的地面上(图中门里地面的一道影子),如果不想要,可以让门里的材质不接收阴影,或为门里的世界使用独立的灯光层。② 透明物体、粒子在门里也要有模板测试,否则会“漏”出门外。③ 想让门里的世界有自己的天空盒、雾和后处理,模板就不够了,需要用第二台相机渲染到 RT,再贴到门洞上(这也是很多游戏的传送门做法,代价更高但更灵活)。