Shader en Unity toma la pantalla y logra un efecto de distorsión (optimización)


Prefacio

Optimice el sombreador implementado en el artículo anterior.


1. En la entrada anterior del sombreador de vértices se abandonó la estructura y los parámetros se pasaron directamente desde la etapa de aplicación. Si se escribe de esta manera, sería inconveniente que el programa se expandiera, por lo que es necesario modificarlo.

lograr

1. Defina una estructura para pasar en el sistema de coordenadas de vértice.

struct appdata
{ float4 vertex: POSITION; // Desde la entrada de la etapa de aplicación, agregue un uv más para muestrear la textura distorsionada float2 uv: TEXCOORD; };



2. Debido a que UnityObjectToClipPos se convierte del espacio local al espacio de recorte, pero no se realiza la división de perspectiva, es necesario realizar la división de perspectiva, que se puede realizar utilizando xyz/w del resultado convertido.

v2f vert (appdata v)
{ v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv,_DistortTex) + _Distort.xy * _Time.y; //Convierte el espacio local al next El resultado después de recortar el espacio se pasa a screenUV después de la división de perspectiva o.screenUV.xyz = o.pos.xyz / o.pos.w; return o; }







3. Debido a que el origen de las coordenadas de la pantalla generalmente está en la esquina superior izquierda (DirectX) o en la esquina inferior izquierda (OpenGL) (la mía es una plataforma DirectX, por lo que está en la esquina superior izquierda), provocará que la posición mostrada es diferente de la posición que necesitamos, por lo que es necesario corregirlo. Realiza la traducción de cálculos y el procesamiento de escala

Insertar descripción de la imagen aquí

DirectX:fixed2 uv = fix2(i.screenUV.x * 0.5,i.screenUV.y * -0.5) + 0.5;
OpenGL平台:fixed2 uv = i.screenUV * 0.5 + 0.5;

Cambie al sombreador de vértices para calcular

DirectX:
o.screenUV.x = o.screenUV.x * 0,5 + 0,5;
o.pantallaUV.y = o.pantallaUV.y * -0,5 + 0,5;
OpenGL:
o.screenUV.x = o.screenUV * 0,5 + 0,5;

Insertar descripción de la imagen aquí

Sin embargo, este cálculo de interpolación tendrá errores y fallas, por lo que es mejor calcularlo en el sombreador de fragmentos.

DirectX:
fix2 uv = i.screenUV.xy / i.screenUV.w;
uv.x = uv.x * 0,5 +0,5;
uv.y = uv.y * -0,5 + 0,5;


2. Cambie a los métodos proporcionados por Unity (interoperabilidad entre plataformas)

ComputeScreenPos(float4 pos)
pos es la posición de las coordenadas en el espacio de recorte y devuelve la posición de las coordenadas de la pantalla bajo un determinado punto de proyección.
Dado que el valor de las coordenadas devueltas por esta función no se divide por las coordenadas homogéneas, si el valor de retorno de la función se usa directamente, necesita usar: tex2Dproj(_ScreenTexture, uv.xyw);
también puede manejar las coordenadas secundarias usted mismo, use: tex2D(_ScreenTexture, uv.xy / uv.w);

En el sombreador de vértices: o.screenUV = ComputeScreenPos(o.pos);
En el sombreador de fragmentos: fix4 grabTex = tex2Dproj(_GrabTex,i.screenUV);


3. Finalmente agrega el twist

Shader "MyShader/P0_10_5"
{
    Properties
    {
        //实现扭曲,就需要传入贴图来实现扰度
        _DistortTex("DistortTex",2D) = "white"{}
        
        _Distort("SpeedX(X) SpeedY(y) Distort(Z)",vector) = (0,0,0,0)
    }
    SubShader
    {
        Tags{"Queue" = "Transparent"}
        //屏幕抓取需要单独使用一个Pass —— GrabPass{} 里面什么都不写,或者GrabPass{"_GrabTex"}
        GrabPass{"_GrabTex"}
        //使用Cull off 让两面都有扭曲
        Cull Off
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                //从应用程序阶段的输入,多加一个uv,用于对扭曲纹理的采样
                float2 uv : TEXCOORD;
                
            };
            
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
                float4 screenUV:TEXCOORD1;
            };

            //在使用抓取的屏幕前,需要像使用属性一样定义一下,_GrabTexture这个名字是Unity定义好的
            sampler2D _GrabTex;
            sampler2D _DistortTex;float4 _DistortTex_ST;
            float4 _Distort;

            
            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv,_DistortTex) + _Distort.xy * _Time.y;
                //pos为裁剪空间下的坐标位置,返回的是某个投影点下的屏幕坐标位置
                o.screenUV = ComputeScreenPos(o.pos);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //DirectX平台:
                /*fixed2 uv = i.screenUV.xy / i.screenUV.w;
                uv.x = uv.x * 0.5  +0.5;
                uv.y = uv.y * -0.5 + 0.5;*/
                
                fixed4 distortTex = tex2D(_DistortTex,i.uv);

                //使用线性插值来控制UV的扭曲程度
                float2 uv = lerp(i.screenUV.xy/i.screenUV.w,distortTex,_Distort.z);
                //对抓取的屏幕进行采样
                fixed4 grabTex = tex2D(_GrabTex,uv);
                return grabTex;
                
            }
            ENDCG
        }
    }
}


Efecto:
Por favor agregue la descripción de la imagen.

Supongo que te gusta

Origin blog.csdn.net/qq_51603875/article/details/132796248
Recomendado
Clasificación