Шейдер ZTest ведет себя не так, как ожидалось - PullRequest
0 голосов
/ 07 июня 2018
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"
}

Этот шейдер применяется к объекту, который выбрал пользователь.Он добавляет проход для рисования частей объекта, которые могут быть закрыты, например, рентгеновский эффект.Шейдер включается во время выполнения и работает должным образом, если начальный шейдер является стандартным шейдером Unity.
Проблема : я делаю шейдер вместо стандартного шейдера, чтобывключить создание экземпляров графического процессора.При свопинге с инстансированного шейдера эффект отрисовывается только после того, как объект полностью прошел свой окклюдер.
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.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;  

Что в экземпляре шейдера может вызывать различный эффект рентгеновского шейдера?

1 Ответ

0 голосов
/ 11 июня 2018

Прежде чем ответить на актуальную проблему здесь, я должен указать на это:

Если у вас есть более двух проходов для многопроходных шейдеров, могут быть созданы только первые проходы.Это связано с тем, что Unity заставляет более поздние проходы обрабатываться вместе для каждого объекта, вызывая изменения материала.

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

Таким образом, в сущности, с вашей текущей реализацией, использующей проходы, вы все равно не сможете использовать создание экземпляров GPU .

Теперь проблема с вашим шейдером в том, что все ваши проходы непрозрачны, поэтому нет никакой гарантии в порядке рисования сеток,Если окклюдеры отображаются после окклюзии, в Zbuffer не будет никакой информации для проверки.Решение состоит в том, чтобы просто увеличить порядок рендеринга материала, чтобы он рисовался сразу после всех других непрозрачных (ZWrite On) пикселей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...