效果:
案例:新仙劍,王者之劍。
在切換場景的時候,就會有這樣的全屏扭曲效果。
思路:
1.用GrabPass抓屏到一張紋理中。
2.進行扭曲,繪制到UGUI的Image上。
准備:
去官網下載Unity內置Shader,當前最新版本:builtin_shaders-5.3.1f1
http://unity3d.com/cn/get-unity/download/archive
里面有Image用的默認Shader:Sprites-Default
我們要在這個shader的基礎上加上扭曲效果。
GrabPass比較耗,加上我沒有好看的場景,這里就用一張全屏的背景圖進行扭曲了。
代碼中//–add 就是在原來基礎上添加部分
Shader "Custom/ImageSwirl" { Properties { [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {} _Color("Tint", Color) = (1,1,1,1) [MaterialToggle] PixelSnap("Pixel snap", Float) = 0 } SubShader { Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "PreviewType" = "Plane" "CanUseSpriteAtlas" = "True" } Cull Off Lighting Off ZWrite Off Blend One OneMinusSrcAlpha //-----add GrabPass { "_MyGrabTex" } //--------- Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile _ PIXELSNAP_ON #include "UnityCG.cginc" struct appdata_t { float4 vertex : POSITION; float4 color : COLOR; float2 texcoord : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; fixed4 color : COLOR; float2 texcoord : TEXCOORD0; }; fixed4 _Color; //------------add float _Radius; float _Angle; sampler2D _MyGrabTex; float2 swirl(float2 uv); float2 swirl(float2 uv) { //先減去貼圖中心點的紋理坐標,這樣是方便旋轉計算 uv -= float2(0.5, 0.5); //計算當前坐標與中心點的距離。 float dist = length(uv); //計算出旋轉的百分比 float percent = (_Radius - dist) / _Radius; if (percent < 1.0 && percent >= 0.0) { //通過sin,cos來計算出旋轉后的位置。 float theta = percent * percent * _Angle * 8.0; float s = sin(theta); float c = cos(theta); //uv = float2(dot(uv, float2(c, -s)), dot(uv, float2(s, c))); uv = float2(uv.x*c - uv.y*s, uv.x*s + uv.y*c); } //再加上貼圖中心點的紋理坐標,這樣才正確。 uv += float2(0.5, 0.5); return uv; } //--------------- v2f vert(appdata_t IN) { v2f OUT; OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex); OUT.texcoord = IN.texcoord; OUT.color = IN.color * _Color; #ifdef PIXELSNAP_ON OUT.vertex = UnityPixelSnap(OUT.vertex); #endif return OUT; } sampler2D _MainTex; sampler2D _AlphaTex; float _AlphaSplitEnabled; fixed4 SampleSpriteTexture(float2 uv) { fixed4 color = tex2D(_MainTex, uv); //----------modify //fixed4 color = tex2D(_MyGrabTex, float2(uv.x,1-uv.y)); //----------- #if UNITY_TEXTURE_ALPHASPLIT_ALLOWED if (_AlphaSplitEnabled) color.a = tex2D(_AlphaTex, uv).r; #endif //UNITY_TEXTURE_ALPHASPLIT_ALLOWED return color; } fixed4 frag(v2f IN) : SV_Target { //---add IN.texcoord = swirl(IN.texcoord); //-------- fixed4 c = SampleSpriteTexture(IN.texcoord) * IN.color; c.rgb *= c.a; return c; } ENDCG } } }
核心:
//uv = float2(dot(uv, float2(c, -s)), dot(uv, float2(s, c))); uv = float2(uv.x*c - uv.y*s, uv.x*s + uv.y*c);
我的另一篇文章:基礎知識:Q&A 中有對旋轉矩陣進行簡單推導。
C#腳本:以時間驅動來增長角度和半徑
using UnityEngine; using System.Collections; using UnityEngine.UI; public class Swirl : MonoBehaviour { float angle = 0; float radius = 0.1f; Material mat; void Start () { mat = this.GetComponent<Image>().material; //延遲2秒開始,每隔0.2s調用一次 InvokeRepeating("DoSwirl", 2f, 0.2f); } void DoSwirl() { angle += 1f; radius += 0.1f; mat.SetFloat("_Angle",angle); mat.SetFloat("_Radius",radius); //rest if (radius >= 0.6f) { angle = 0; radius = 0.1f; } } }
- 本文固定鏈接: http://www.shihuanjue.com/?p=284
- 轉載請注明: 喬 2016年01月11日 於 是幻覺 發表