如何实现透过不可见游戏对象查看时隐藏部分游戏对象?
解决AR帽子与头部的遮挡问题
嘿,我来帮你搞定这个头疼的遮挡逻辑!先把需求掰明白:头部作为不可见的遮罩,要挡住帽子被它覆盖的区域,但当视线落在帽子自身区域时,被头部挡住的那部分帽子不能变透明——说白了就是,帽子戴在头上时,内侧被头挡住的部分要隐藏,但从外面看帽子的外侧,哪怕和头重叠也得正常显示。
第一步:完善头部的遮罩着色器
你现有的遮罩着色器方向是对的,但得把模板缓冲和深度的设置补全,让它只做标记不输出颜色:
Shader "Custom/Stencil/HeadMask" { SubShader { Tags { "RenderType"="Opaque" "Queue"="Geometry-1" // 比普通几何体早渲染,确保先写入模板缓冲 } ColorMask 0 // 不输出任何颜色,只做遮罩标记 ZWrite On // 写入深度,避免后续物体错误覆盖 Cull Off // 确保头部所有面都能标记模板,不管朝向 Stencil { Ref 1 // 设置模板参考值为1 Comp Always // 总是通过模板测试 Pass Replace // 将对应像素的模板值设为1 } Pass { // 空Pass,只执行模板和深度操作 } } }
把这个着色器给你的头部对象,记得禁用它的MeshRenderer的阴影相关选项(不需要投射/接收阴影),先确保头部的Mesh能完整覆盖需要遮挡帽子的区域。
第二步:设置帽子的专属着色器
帽子的着色器要结合模板缓冲和深度来判断是否显示:只有当帽子像素在头部后面且处于头部模板标记区域时,才会被隐藏;如果帽子在头部前面,哪怕和头重叠也要正常渲染。
Shader "Custom/Stencil/HatShader" { Properties { _MainTex ("Texture", 2D) = "white" {} _Color ("Color", Color) = (1,1,1,1) } SubShader { Tags { "RenderType"="Opaque" "Queue"="Geometry" // 在遮罩之后渲染,确保能读取到模板值 } ZWrite On Cull Off // 根据你的帽子模型调整,比如帽子内侧需要显示就开Off Stencil { Ref 1 Comp Equal // 只处理被头部标记过的区域(模板值为1) Pass Keep // 保留模板值,不修改 Fail Keep } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float depth : DEPTH; }; sampler2D _MainTex; float4 _MainTex_ST; float4 _Color; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.depth = -UnityObjectToViewPos(v.vertex).z * _ProjectionParams.w; // 获取视图空间深度 return o; } fixed4 frag (v2f i) : SV_Target { // 从深度缓冲中采样头部的深度值 float headDepth = LinearEyeDepth(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.vertex)).r); // 如果帽子像素在头部后面(深度更大),就丢弃该像素实现遮挡 if (i.depth > headDepth) { discard; } // 否则正常渲染帽子 fixed4 col = tex2D(_MainTex, i.uv) * _Color; return col; } ENDCG } } FallBack "Diffuse" }
关键逻辑拆解
- 头部遮罩先渲染,在模板缓冲中标记出自己的区域(值为1),同时把深度写入缓冲。
- 帽子渲染时,先筛选出被头部标记的区域,再对比当前像素和头部的深度:
- 帽子在头部后面 → 丢弃像素(实现遮挡)
- 帽子在头部前面 → 正常渲染(避免透过帽子看时那部分透明)
额外小提示
- 确保相机能渲染头部所在的Layer,否则模板缓冲不会被正确写入。
- 测试时可以暂时打开头部MeshRenderer的颜色(注释掉
ColorMask 0),确认遮罩区域是否覆盖正确,之后再改回去。
内容的提问来源于stack exchange,提问作者alex okochutin
相关产品推荐
相关产品推荐

