You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity自定义Shader为何透显场景网格?已设不透明仍未解决

问题描述

在Unity编辑器Scene视图中,使用默认URP Lit Shader的物体可正常遮挡场景网格,但自定义简单Shader的物体无法遮挡,场景网格会透显。已为Shader添加URP不透明材质的常规设置:

ZWrite On
ZTest LEqual
Blend Off

但问题依旧,关闭Scene视图网格并非可行方案,需让自定义Shader和默认URP Lit Shader一样实现遮挡效果。

注:测试用的两个球体Y轴位置均为0,仅右侧使用自定义Shader的球体沿X轴偏移1单位,视觉上看似在网格后方,但实际位置与左侧球体一致。

用户提供的自定义Shader代码:

Shader "Custom/SimpleShader"
{
    Properties
    {
        base_color ("Base Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags {
            "RenderType"="Opaque"
            "Queue"="Geometry"
            "RenderPipeline"="UniversalPipeline"
        }
        LOD 100
        
        Pass
        {            
            ZWrite On
            ZTest LEqual
            Blend Off
            
            HLSLPROGRAM
            #pragma target 2.0
            
            #pragma vertex vert
            #pragma fragment frag
            
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            
            struct attributes
            {
                float4 position_os : POSITION;
                float3 normal_os : NORMAL;          
            };
            
            struct varyings
            {
                float4 position_cs : SV_POSITION;
                float3 position_ws : TEXCOORD0;
                float3 normal_ws : TEXCOORD1;
            };
            
            CBUFFER_START(UnityPerMaterial)
            float4 base_color;
            CBUFFER_END
            
            varyings vert (attributes input)
            {
                varyings output;
                
                output.position_cs = TransformObjectToHClip(input.position_os.xyz);
                output.position_ws = TransformObjectToWorld(input.position_os).xyz;
                output.normal_ws = TransformObjectToWorldNormal(input.normal_os);
                
                return output;
            }
            
            half4 frag (varyings input) : SV_Target
            {
                Light main_light = GetMainLight();
                float3 light_color = main_light.color.rgb;
                float3 light_direction_ws = normalize(main_light.direction.xyz);
                
                float3 normal_ws = normalize(input.normal_ws);
                float normal_dot_light = max(0,dot(normal_ws, light_direction_ws));
                
                float3 diffuse = light_color * normal_dot_light;
                float3 ambient = SampleSH(input.normal_ws);
                
                float4 lighting = float4(diffuse + ambient, 1);
                
                float4 final_color = base_color * lighting;
                
                return final_color;
            }
            
            ENDHLSL
        }
    }
}
解决方案

问题核心是自定义Shader缺少深度通道渲染Pass:URP的Scene视图网格依赖深度缓冲判断遮挡,默认URP Lit Shader包含DepthOnly Pass,会提前将物体深度信息写入缓冲;而你的自定义Shader仅包含颜色渲染Pass,即使开启ZWrite On,也可能因Scene视图渲染顺序问题,导致网格渲染时读取不到物体深度。

只需在SubShader中添加DepthOnly Pass即可解决,修改后的Shader代码如下:

Shader "Custom/SimpleShader"
{
    Properties
    {
        base_color ("Base Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags {
            "RenderType"="Opaque"
            "Queue"="Geometry"
            "RenderPipeline"="UniversalPipeline"
        }
        LOD 100

        // 添加深度渲染Pass
        Pass
        {
            Name "DepthOnly"
            Tags { "LightMode" = "DepthOnly" }

            ZWrite On
            ColorMask 0

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct Attributes
            {
                float4 positionOS   : POSITION;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct Varyings
            {
                float4 positionCS  : SV_POSITION;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            Varyings vert(Attributes input)
            {
                Varyings output;
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
                output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
                return output;
            }

            half4 frag() : SV_Target
            {
                return 0;
            }
            ENDHLSL
        }
        
        Pass
        {            
            ZWrite On
            ZTest LEqual
            Blend Off
            
            HLSLPROGRAM
            #pragma target 2.0
            
            #pragma vertex vert
            #pragma fragment frag
            
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            
            struct attributes
            {
                float4 position_os : POSITION;
                float3 normal_os : NORMAL;          
            };
            
            struct varyings
            {
                float4 position_cs : SV_POSITION;
                float3 position_ws : TEXCOORD0;
                float3 normal_ws : TEXCOORD1;
            };
            
            CBUFFER_START(UnityPerMaterial)
            float4 base_color;
            CBUFFER_END
            
            varyings vert (attributes input)
            {
                varyings output;
                
                output.position_cs = TransformObjectToHClip(input.position_os.xyz);
                output.position_ws = TransformObjectToWorld(input.position_os).xyz;
                output.normal_ws = TransformObjectToWorldNormal(input.normal_os);
                
                return output;
            }
            
            half4 frag (varyings input) : SV_Target
            {
                Light main_light = GetMainLight();
                float3 light_color = main_light.color.rgb;
                float3 light_direction_ws = normalize(main_light.direction.xyz);
                
                float3 normal_ws = normalize(input.normal_ws);
                float normal_dot_light = max(0,dot(normal_ws, light_direction_ws));
                
                float3 diffuse = light_color * normal_dot_light;
                float3 ambient = SampleSH(input.normal_ws);
                
                float4 lighting = float4(diffuse + ambient, 1);
                
                float4 final_color = base_color * lighting;
                
                return final_color;
            }
            
            ENDHLSL
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:05:00