unity-game-engine - Shader ZTest 未按预期运行

标签 unity-game-engine shader

Shader "Custom/Selected Object" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Emission ("EmissionColor", Color) = (0.5, 0.5, 0.5, 1)
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0

        _Mode ("Blend Mode", Range(0,3)) = 0
        _ZWrite ("ZWrite", Int) = 0
        _SrcBlend ("SrcBlend", Int) = 0
        _DstBlend ("DstBlend", Int) = 0

        _Cutoff ("Alpha Cutoff", Float) = 0.05
    }
    SubShader{
        //Behind other geometry
        Pass
        {
            ZTest GEqual
            ZWrite [_ZWrite]
            Blend [_SrcBlend] [_DstBlend]

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata 
            {
                float2 uv : TEXCOORD0;
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float3 viewDir : TEXCOORD1;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.normal = UnityObjectToWorldNormal(v.normal);
                o.viewDir = normalize(UnityWorldSpaceViewDir(o.pos));

                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;

            fixed4 frag(v2f i) : SV_Target
            {
                //Note you have to normalize these again since they are being interpolated between vertices
                float rim = 1 - dot(normalize(i.normal), normalize(i.viewDir));
                fixed4 rimLight = lerp(half4(.95, .95, .95, 1), half4(0.65, 0.65, .95, 1), rim);
                fixed4 t = tex2D(_MainTex, i.uv);
                clip(t.a < 0.2);
                return t * rimLight;
            }

            ENDCG
        }

        ZTest Less
        ZWrite On
        Blend [_SrcBlend][_DstBlend]

        //Front geometry
        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        // And generate the shadow pass with instancing support
        #pragma surface surf Standard fullforwardshadows addshadow alphatest:_Cutoff //alpha:blend //keepalpha
        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        #pragma multi_compile __ EMISSIVE_ON

        sampler2D _MainTex;
        fixed4 _Emission;
        fixed4 _Color;
        //float _Mode;

        struct Input {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;

        void surf(Input IN, inout SurfaceOutputStandard o) {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            #if EMISSIVE_ON //Glowing
                o.Emission = _Emission;
            #endif
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }

        ENDCG
    }
    FallBack "Instanced/InstancedSurfaceShader"
}

此着色器应用于用户选择的对象。它添加了一个 channel 来绘制可能被遮挡的对象部分,如 X 射线效果。该着色器在运行时进行交换,如果起始着色器是 Unity 标准着色器,则该着色器将正常工作。
问题:我正在制作一个着色器来代替标准着色器,以启用 GPU 实例化。从实例化着色器进行交换时,只有在对象完全通过其遮挡物后才会绘制效果。
ZTest failing

ZTest working
除非对象完全超过遮挡对象,否则 ZTest GEqual 似乎会失败。在上面的图像中,在第二个图像中看到的效果也应该在第一个图像中看到,其中对象被遮挡。

事实上,它与标准着色器配合得很好,这让我相信这个问题是我在实例着色器中遗漏的,在这里:

Shader "Custom/Instanced/InstancedSurfaceShader - Glow" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Emission ("EmissionColor", Color) = (1, 1, 1, 1)
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0

        _Mode ("Blend Mode", Range(0,3)) = 0
        _Cutoff("Alpha Cutoff", Float) = 0.05
    }
    SubShader {
        ZTest Less
        ZWrite On

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        // And generate the shadow pass with instancing support
        #pragma surface surf Standard fullforwardshadows addshadow alphatest:_Cutoff

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        // Enable instancing for this shader
        #pragma multi_compile_instancing

        // Config maxcount. See manual page.
        // #pragma instancing_options

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
        };

        fixed4 _Emission;
        half _Glossiness;
        half _Metallic;

        // Declare instanced properties inside a cbuffer.
        // Each instanced property is an array of by default 500(D3D)/128(GL) elements. Since D3D and GL imposes a certain limitation
        // of 64KB and 16KB respectively on the size of a cubffer, the default array size thus allows two matrix arrays in one cbuffer.
        // Use maxcount option on #pragma instancing_options directive to specify array size other than default (divided by 4 when used
        // for GL).
        // https://docs.unity3d.com/Manual/GPUInstancing.html
        UNITY_INSTANCING_BUFFER_START(Props)
            UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color) // Make _Color an instanced property (i.e. an array)
#define _Color_arr Props
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o) {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * UNITY_ACCESS_INSTANCED_PROP(_Color_arr, _Color);
            o.Albedo = c.rgb;
            o.Emission = _Emission;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Instanced/InstancedSurfaceShader"
}  

这是在着色器切换时直接影响 Material /着色器的代码片段:

material.SetOverrideTag("RenderType", "");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = -1;  

实例化着色器中的哪些因素可能导致 X 射线着色器的效果不同?

最佳答案

在回答这里的实际问题之前,我需要指出这一点:

If you have more than two passes for multi-pass Shaders, only the first passes can be instanced. This is because Unity forces the later passes to be rendered together for each object, forcing Material changes.

https://docs.unity3d.com/Manual/GPUInstancing.html

因此,从本质上讲,在您当前使用 Pass 实现的情况下,无论如何您都将无法使用 GPU 实例

现在,您的着色器的问题是您的所有 channel 都是不透明的,因此无法保证网格的绘制顺序。如果遮挡物在被遮挡物之后渲染,则 Zbuffer 中不会有任何信息可供测试。解决方案只是增加 Material 的渲染顺序,因为它会在所有其他不透明(ZWrite On)像素之后绘制。

关于unity-game-engine - Shader ZTest 未按预期运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50749891/

相关文章:

opengl - GLEW 着色器似乎不受支持

glsl - smoothstep() 为 "identical"参数返回不同的值

openGL - 创建弯曲表面

iphone - GLSL 'texture2D' : no matching overloaded function found OpenGL ES2 on iPhone

javascript - Playerprefs 只能在场景本身内部访问吗?

android - 无论我做什么,Unity Android 构建在 Gradle 阶段都会失败

ios - 将unity 2018项目嵌入Xcode9.4.1

android - 将 Canvas 内的游戏对象移动到接触点

c# - 将 Oculus Unity Integration 升级到 v12 后,传送无法在 Quest 上运行

three.js - 使用 Three.js 在 3D 模型之间转换顶点