Преобразование многопроходного шейдера размытия в однопроходный (режим рендеринга)

#c# #c #unity3d #shader #fragment-shader

#c# #c #unity3d #шейдер #фрагмент-шейдер

Вопрос:

У меня есть шейдер размытия в Unity, и этот шейдер не поддерживает режим однопроходного рендеринга (после сборки на Oculus GO с однопроходными графическими артефактами появляются). Я попытался реализовать поддержку однопроходного рендеринга с использованием руководств Unity, но без каких-либо эффектов. У меня нет никаких идей, что может быть не так.

Однопроходные руководства Unity, которые я пробовал применять: https://docs.unity3d.com/Manual/SinglePassStereoRendering.html
https://docs.unity3d.com/Manual/SinglePassInstancing.html

СТАРАЯ ВЕРСИЯ НЕ ПОДДЕРЖИВАЛА ОДНОПРОХОДНЫЙ РЕНДЕРИНГ:

Шейдер «Пользовательский / РАЗМЫТИЕ» { Свойства { _Radius(«Радиус», диапазон (1, 255)) = 1 }

 Category
{
    Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Opaque" }

    SubShader
    {
        GrabPass
        {
            Tags{ "LightMode" = "Always" }
        }

        Pass
        {
            Tags{ "LightMode" = "Always" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma fragmentoption ARB_precision_hint_fastest
            #include "UnityCG.cginc"

            struct appdata_t
            {
                float4 vertex : POSITION;
                float2 texcoord: TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : POSITION;
                float4 uvgrab : TEXCOORD0;
            };

            v2f vert(appdata_t v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                #if UNITY_UV_STARTS_AT_TOP
                float scale = -1.0;
                #else
                float scale = 1.0;
                #endif
                o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale)   o.vertex.w) * 0.5;
                o.uvgrab.zw = o.vertex.zw;
                return o;
            }

            sampler2D _GrabTexture;
            float4 _GrabTexture_TexelSize;
            float _Radius;

            half4 frag(v2f i) : COLOR
            {
                half4 sum = half4(0,0,0,0);

                #define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x   _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y   _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))

                sum  = GRABXYPIXEL(0.0, 0.0);
                int measurments = 1;

                for (float range = 0.1f; range <= _Radius; range  = 0.1f)
                {
                    sum  = GRABXYPIXEL(range, range);
                    sum  = GRABXYPIXEL(range, -range);
                    sum  = GRABXYPIXEL(-range, range);
                    sum  = GRABXYPIXEL(-range, -range);
                    measurments  = 4;
                }

                return sum / measurments;
            }
            ENDCG
        }
        GrabPass
        {
            Tags{ "LightMode" = "Always" }
        }

        Pass
        {
            Tags{ "LightMode" = "Always" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma fragmentoption ARB_precision_hint_fastest
            #include "UnityCG.cginc"

            struct appdata_t
            {
                float4 vertex : POSITION;
                float2 texcoord: TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : POSITION;
                float4 uvgrab : TEXCOORD0;
            };

            v2f vert(appdata_t v)
            {
                v2f o;
                 o.vertex = UnityObjectToClipPos(v.vertex);
                #if UNITY_UV_STARTS_AT_TOP
                float scale = -1.0;
                #else
                float scale = 1.0;
                #endif                  
                o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale)   o.vertex.w) * 0.5;
                o.uvgrab.zw = o.vertex.zw;
                return o;
            }

            sampler2D _GrabTexture;
            float4 _GrabTexture_TexelSize;
            float _Radius;

            half4 frag(v2f i) : COLOR
            {

                half4 sum = half4(0,0,0,0);
                float radius = 1.41421356237 * _Radius;

                #define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x   _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y   _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))

                sum  = GRABXYPIXEL(0.0, 0.0);
                int measurments = 1;

                for (float range = 1.41421356237f; range <= radius * 1.41; range  = 1.41421356237f)
                {
                    sum  = GRABXYPIXEL(range, 0);
                    sum  = GRABXYPIXEL(-range, 0);
                    sum  = GRABXYPIXEL(0, range);
                    sum  = GRABXYPIXEL(0, -range);
                    measurments  = 4;
                }

                return sum / measurments;
            }
            ENDCG
        }
    }
}
  

}

МОИ НЕРАБОЧИЕ ИЗМЕНЕНИЯ:

Шейдер «Пользовательский / РАЗМЫТИЕ» { Свойства { _Radius(«Радиус», диапазон (1, 255)) = 1 }

 Category
{
    Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Opaque" }

    SubShader
    {
        GrabPass
        {
            Tags{ "LightMode" = "Always" }
        }

        Pass
        {
            Tags{ "LightMode" = "Always" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma fragmentoption ARB_precision_hint_fastest
            #include "UnityCG.cginc"

            struct appdata_t
            {
                float4 vertex : POSITION;
                float2 texcoord: TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : POSITION;
                float4 uvgrab : TEXCOORD0;
            };

            v2f vert(appdata_t v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                #if UNITY_UV_STARTS_AT_TOP
                float scale = -1.0;
                #else
                float scale = 1.0;
                #endif

                o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale)   o.vertex.w) * 0.5;
                o.uvgrab.zw = o.vertex.zw;
                return o;
            }

            sampler2D _GrabTexture;
            float4 _GrabTexture_TexelSize;
            float _Radius;
            half4 _MainTex_ST;

            half4 frag(v2f i) : SV_Target
            {
                half4 sum = half4(0,0,0,0);

                #if UNITY_SINGLE_PASS
                    #define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(UnityStereoScreenSpaceUVAdjust(float4(i.uvgrab.x   _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y   _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w),_MainTex_ST)))
                #else
                    #define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x   _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y   _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))
                #endif
                sum  = GRABXYPIXEL(0.0, 0.0);
                int measurments = 1;

                for (float range = 0.1f; range <= _Radius; range  = 0.1f)
                {
                    sum  = GRABXYPIXEL(range, range);
                    sum  = GRABXYPIXEL(range, -range);
                    sum  = GRABXYPIXEL(-range, range);
                    sum  = GRABXYPIXEL(-range, -range);
                    measurments  = 4;
                }

                return sum / measurments;
            }
            ENDCG
        }
        GrabPass
        {
            Tags{ "LightMode" = "Always" }
        }

        Pass
        {
            Tags{ "LightMode" = "Always" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma fragmentoption ARB_precision_hint_fastest
            #include "UnityCG.cginc"

            struct appdata_t
            {
                float4 vertex : POSITION;
                float2 texcoord: TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : POSITION;
                float4 uvgrab : TEXCOORD0;
            };

            v2f vert(appdata_t v)
            {
                v2f o;
                 o.vertex = UnityObjectToClipPos(v.vertex);
                #if UNITY_UV_STARTS_AT_TOP
                float scale = -1.0;
                #else
                float scale = 1.0;
                #endif

                o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale)   o.vertex.w) * 0.5;
                o.uvgrab.zw = o.vertex.zw;
                return o;
            }

            sampler2D _GrabTexture;
            float4 _GrabTexture_TexelSize;
            float _Radius;
            half4 _MainTex_ST;

            half4 frag(v2f i) : SV_Target
            {

                half4 sum = half4(0,0,0,0);
                float radius = 1.41421356237 * _Radius;

                #if UNITY_SINGLE_PASS
                #define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(UnityStereoScreenSpaceUVAdjust(float4(i.uvgrab.x   _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y   _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w),_MainTex_ST)))
                #else
                #define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x   _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y   _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))
                #endif
                sum  = GRABXYPIXEL(0.0, 0.0);
                int measurments = 1;

                for (float range = 1.41421356237f; range <= radius * 1.41; range  = 1.41421356237f)
                {
                    sum  = GRABXYPIXEL(range, 0);
                    sum  = GRABXYPIXEL(-range, 0);
                    sum  = GRABXYPIXEL(0, range);
                    sum  = GRABXYPIXEL(0, -range);
                    measurments  = 4;
                }

                return sum / measurments;
            }
            ENDCG
        }
    }
}
  

}

Я ожидаю, что этот шейдер будет поддерживать однопроходный режим рендеринга VR.

Комментарии:

1. Я не совсем разбираюсь в шейдерах Unity, но в вашем «новом» все еще есть два Pass блока. Вы уверены, что это правильно?

2. @Immersive, однопроходный проход в данном случае относится к рендерингу обоих глаз одновременно для виртуальной реальности — это не связано с проходами рендеринга внутри шейдера.