(轉)熱空氣扭曲效果shader


轉自:http://blog.sina.com.cn/s/blog_89d90b7c0102vaqy.html

熱空氣扭曲在大自然中形成是比較復雜的,這里只是通過取屏幕紋理和移動UV來模擬熱扭曲效果。

先看效果:

shader實例(十七)熱空氣扭曲效果

詳細的原理和實現在下面的代碼中。

Shader "Xffect/my_distortion" {
 Properties {
  _NoiseTex ("絮亂圖", 2D) = "white" {}           // 絮亂圖
  _AreaTex ("區域圖(Alpha):白色為顯示區域,透明為不顯示區域", 2D) = "white" {} // 區域圖
  _MoveSpeed  ("絮亂圖移動速度", range (0,1.5)) = 1        // 絮亂圖移動速度
  _MoveForce  ("絮亂圖疊加后移動強度", range (0,0.1)) = 0.1      // 絮亂圖疊加強度,多張運動紋理疊加后再相乘的系數
 }

 Category {
  // 【渲染隊列】在透明物體前,類型為【透明】
  Tags { "Queue"="Transparent+1" "RenderType"="Transparent" }
  // 最終透明混合 = 貼圖RGB*貼圖A + 背景RGB*(1-貼圖A)
  // 透明混合【源的A值】【1-SrcAlpha】
  Blend SrcAlpha OneMinusSrcAlpha   // 該寫法為最常用最真實的透明混合顯示,半透明圖的正常顯示
  // GEuqal 點的alpha值大於等於0.01時渲染
  AlphaTest Greater .01     // 在PS區域圖時,不顯示的地方透明度為0即可。
  // 關閉剔除,關閉燈光,不記錄深度
  Cull Off Lighting Off ZWrite Off
 
  SubShader {
   GrabPass {       
    Name "BASE"//在后續的通道中可以使用給定的名字來引用這個紋理。當你在1個場景中有多個對象使用grab pass 時候,這樣做會提高效率。
    Tags { "LightMode" = "Always" }
    }

   Pass {
    Name "BASE"
    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; // 輸出的紋理做標集0
     float2 uvmain : TEXCOORD1; // 輸出的紋理坐標集1
    };

    float _MoveSpeed;  // 聲明絮亂圖移動速度
    float _MoveForce;  // 聲明運動強度
    float4 _NoiseTex_ST; // 絮亂圖采樣
    float4 _AreaTex_ST;  // 區域圖采樣

    sampler2D _NoiseTex; // 絮亂圖樣本對象
    sampler2D _AreaTex;  // 區域圖樣本對象
    sampler2D _GrabTexture; // 全屏幕紋理的樣本對象,由GrabPass賦值

    v2f vert (appdata_t v)
    {
     v2f o;
     // 從模型坐標-世界坐標-視坐標-(視覺平截體乘以投影矩陣並進行透視除法)-剪裁坐標
     o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
     // 將裁剪坐標中的【頂點信息】進行換算給uvgrab賦值
     #if UNITY_UV_STARTS_AT_TOP  // Direct3D類似平台scale為-1;OpenGL類似平台為1。
     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;

     // 區域圖紋理:獲取輸入的紋理坐標集,並且使用_MainTex_ST采樣圖,支持在視檢器調節縮放和偏移值
     o.uvmain = TRANSFORM_TEX(v.texcoord, _AreaTex);
     return o;
    }

    half4 frag( v2f i ) : COLOR
    {
     // 控制【UV的運動】,這樣在進行采樣時,offsetColor1拿到的顏色也是運動的。
     half4 offsetColor1 = tex2D(_NoiseTex, i.uvmain + _Time.xz * _MoveSpeed);// 將xy與xz交叉位移
     half4 offsetColor2 = tex2D(_NoiseTex, i.uvmain - _Time.yx * _MoveSpeed);// 將xy與yx交叉位移
     // 將【正在移動的絮亂圖紋理信息】的rg用於給uvgrab累加,加2個col就會出現2個絮亂圖紋理
     i.uvgrab.x += ((offsetColor1.r + offsetColor2.r) - 1) * _MoveForce; // 疊加強度
     i.uvgrab.y += ((offsetColor1.g + offsetColor2.g) - 1) * _MoveForce;

     // 本來只會顯示物體背后的屏幕紋理(視覺上該物體透明了)
     // 但是上面給x,y疊加了運動的rg值,所以就形成透明絮亂圖運動的效果
     half4 noiseCol = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uvgrab));
     // 屏幕紋理不需要透明,所以設置為1。
     noiseCol.a = 1f;
     // 對區域圖進行采樣。
     half4 areaCol = tex2D(_AreaTex, i.uvmain);
     // 紋理相乘:區域紋理RBG都為1,區域紋理A為O的像素將不會顯示
     // 即可達到絮亂圖在區域圖中才顯示的效果。
     return  noiseCol * areaCol;
    }
    ENDCG
   }//end pass 
  }//end subshader

  // 用於老式顯卡
  SubShader {
   Blend DstColor Zero
   Pass {
    Name "BASE"
    SetTexture [_MainTex] { combine texture }
   }
  }
 }
}
配合粒子的發射,就可以在刀光上實現熱扭曲效果等。

 

 

注:

此shader在部分手機上會有問題,是因為對grabpass的支持不夠,

這里可以采用攝像機獲取屏幕紋理的方式代替_GrabTexture。

原理在http://blog.sina.com.cn/s/blog_89d90b7c0102va4m.html的最下面。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM