1. 程式人生 > >unity Shader 扭曲效果

unity Shader 扭曲效果

原理

所謂扭曲就是擾動一個物體的uv座標,表現出來就是一個擾動效果,如火焰扭曲空氣,和水波對水底的影響。
1. 在shader 中我們需要一張當前渲染的紋理
2. 給一個物體渲染並使用當前紋理,用螢幕座標作為uv座標加上一個擾動值

unity

1.
unity提供了抓取的pass: GrabPass unity官網介紹

//每次遇到這個pass就去抓取一次提供了了一個預設名稱_GrabTexture 不推薦使用
GrabPass
{ 
}
//第一次遇到去抓取一次每幀只會抓取一次,名稱由你自己定義
 GrabPass
 {
     "_BackgroundTexture"
 }

2.
獲取物體的螢幕座標,unity也給出了內建函式

//官網程式碼
 v2f vert(appdata_base v) {
      v2f o;
       // use UnityObjectToClipPos from UnityCG.cginc to calculate 
       // the clip-space of the vertex
       o.pos = UnityObjectToClipPos(v.vertex);
       // use ComputeGrabScreenPos function from UnityCG.cginc
       // to get the correct texture coordinate
o.grabPos = ComputeGrabScreenPos(o.pos); return o; }

ComputeGrabScreenPos 函式就是得到螢幕座標,下面是UnityCG.cginc裡面的函式原始碼

inline float4 ComputeGrabScreenPos (float4 pos) {
    #if UNITY_UV_STARTS_AT_TOP
    float scale = -1.0;
    #else
    float scale = 1.0;
    #endif
    float4 o = pos * 0.5f;
o.xy = float2(o.x, o.y*scale) + o.w; #ifdef UNITY_SINGLE_PASS_STEREO o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w); #endif o.zw = pos.zw; return o; }

UNITY_UV_STARTS_AT_TOP 和裝置的紋理座標有關如圖
這裡寫圖片描述

pos傳進來的座標是齊次裁剪座標x,y都在[-w,w]之間,不在這個範圍的會在光柵化之前(之後執行片段著色器)裁剪掉。轉換如圖 A->B 就是o.xy = float2(o.x, o.y*scale) + o.w;
最後還要歸一化得到最終紋理座標是除o.w實現的這個在tex2Dproj 紋理取樣中內建函式中實現的(紋理座標在[0,1])
這裡寫圖片描述

UV 擾動

UV擾動是對一張噪聲紋理採用加上偏移值,同時讓噪聲紋理做uv移動,達到每次採用不同來實現一個動態的效果

關鍵程式碼

fixed4 frag (v2f i) : SV_Target
{
    //讓噪聲紋理的uv移動
    fixed4 col = tex2D(_Noise, i.uv+=_Time.xy*_distortFactorTime);
    // 加上一個偏移值
    i.grabPos.xy +=col.xy*_distortFactor;
     half4 bgcolor = tex2Dproj(_BackgroundTexture, i.grabPos);
    return bgcolor;
}

效果圖

這裡寫圖片描述

完整程式碼

Shader "Custom/Distort"
{
    Properties
    {
        _Noise ("Noise", 2D) = "white" {}
        _distortFactorTime("FactorTime",Range(0,5)) = 0.5
        _distortFactor("factor",Range(0.04,1)) = 0
    }
    SubShader
    {
        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
        LOD 100
        Cull Off Lighting Off ZWrite Off
         GrabPass
        {
            "_BackgroundTexture"
        }
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;

            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float4 grabPos:TEXCOORD1;
            };

            sampler2D _Noise;
            float4 _Noise_ST;
            fixed _distortFactorTime;
            fixed _distortFactor;
            sampler2D _BackgroundTexture;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _Noise);
                o.grabPos = ComputeGrabScreenPos(o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_Noise, i.uv+=_Time.xy*_distortFactorTime);

                i.grabPos.xy +=col.xy*_distortFactor;
                 half4 bgcolor = tex2Dproj(_BackgroundTexture, i.grabPos);
                return bgcolor;
            }
            ENDCG
        }
    }
}