You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

为何Shader中调用UnityObjectToClipPos()会导致场景内其他Shader对象不可见?

问题分析与解决方案

首先,咱们先搞懂UnityObjectToClipPos(v.vertex)到底在做什么——这是Unity内置的顶点变换宏,核心作用是把模型空间下的顶点坐标一步步转换到裁剪空间,让GPU能正确计算顶点在屏幕上的位置。它展开后的逻辑大致是:

o.vertex = mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, v.vertex));

也就是依次应用模型矩阵(转世界空间)、视图矩阵(转相机空间)、投影矩阵(转裁剪空间),这是3D/2D物体正常渲染的必要步骤。

为什么它会导致其他UI元素不可见?

你的问题大概率出在渲染队列、深度测试/写入的设置冲突上:

  • UI元素(尤其是Screen Space - OverlayScreen Space - Camera模式的Canvas)默认使用Transparent渲染队列,并且关闭ZWrite(不向深度缓冲写入数据),这样UI才能正常叠加在其他内容之上。
  • 而你用Shadero Sprite生成的Shader,可能默认开启了ZWrite On,并且渲染队列和UI重叠(比如也是Transparent)。当你的Shader执行正确的顶点变换后,物体的深度值会被写入深度缓冲,那些UI自定义Shader如果设置了严格的深度测试(比如ZTest Less),就会因为深度测试不通过被GPU直接剔除,导致完全不可见。
  • 当你换成o.vertex = v.vertex时,顶点没有经过空间转换,会被渲染到视口之外(完全不可见),自然不会写入深度缓冲,UI的深度测试也就不会被干扰,所以能正常显示。

解决方法

1. 调整你的Shader的渲染队列与深度设置

这是最直接的解决方案,让你的Shader和UI的渲染逻辑彻底隔离:

  • 如果你的Shader是不透明物体用的:
    SubShader {
        Tags { "RenderType"="Opaque" "Queue"="Geometry" } // 用默认的3D物体队列
        ZWrite On
        ZTest LEqual
        // ... 其他原有代码
    }
    
  • 如果是透明Sprite用的:
    SubShader {
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        ZWrite Off // 必须关闭深度写入,避免干扰UI
        Blend SrcAlpha OneMinusSrcAlpha // 开启透明混合
        // ... 其他原有代码
    }
    

2. 手动替换UnityObjectToClipPos的等效代码

如果怀疑是宏展开的潜在问题(比如Shadero Sprite生成的宏和UI的宏冲突),可以直接用手动矩阵乘法替换这个宏,逻辑完全一致,但能避免宏的不确定性:

v2f vert(appdata v) {
    v2f o;
    // 替换UnityObjectToClipPos为手动矩阵乘法
    float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
    o.vertex = mul(UNITY_MATRIX_VP, worldPos);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    UNITY_TRANSFER_FOG(o,o.vertex);
    return o;
}

3. 调整UI自定义Shader的设置

如果不想修改自己的Shader,也可以针对不可见的UI元素调整它们的Shader:

  • 把UI Shader的ZTest设置为ZTest Always(完全跳过深度测试),这样无论深度缓冲里有什么,UI都会被渲染。
  • 或者把UI的渲染队列改得更靠后(比如Queue="Transparent+100"),让UI在你的物体之后渲染,即使有深度值也能覆盖显示。

额外排查点

可以检查Shadero Sprite生成的Shader里的#pragma指令,有没有多编译宏(比如#pragma multi_compile)意外修改了全局状态,导致和UI Shader的编译逻辑冲突。

内容的提问来源于stack exchange,提问作者Josh1billion

火山引擎 最新活动