Unity特效(1) 夢幻旋屏

遊戲開發中,往往會用到一些屏幕特效。下圖展現的是一種「旋屏」效果,它會旋轉屏幕圖像,且距離中心點越遠的點旋轉角度越大。這種效果特別適合營造「夢幻」感,比如,在RPG遊戲中,經過一段「旋屏」特效,主角穿越到了10年前。

1、編寫Shader

下面的著色器代碼使用了頂點/片元著色器處理旋屏特效的功能。這裡定義3個屬性,其中_MainTex代表屏幕貼圖,_Rot 代表基準的旋轉角度。核心代碼在片元著色器frag中實現。

如下圖所示,屏幕圖像被歸一到[0,1]的空間中,中心點為(0.5,0.5)。假設某個點的uv坐標為(x,y),經過一系列處理,它的坐標變為(x1,y1),而(x1,y1)便是實現旋轉效果後的uv坐標。

由「float distance = sqrt((i.uv.x - 0.5)*(i.uv.x - 0.5) +(i.uv.y - 0.5)*(i.uv.y - 0.5));」可以計算點到屏幕中心的距離distance。由於距離越遠旋轉角度越大,使用「_Rot *=distance」將角度增量基準與距離聯繫起來,即可獲取需要旋轉的角度:angle = _Rot*distance + A。

由反正切公式可得∠A = atan((y - 0.5)/(x - 0.5)),由於atan的取值為[-π/2,π/2],還需根據y值確定∠A所在的象限,故而∠A = step(x,0.5)*PI+ atan((y - 0.5)/(x - 0.5)) 。計算∠A 後,便可由angle = _Rot*distance + A計算總的旋轉角度。

前面已經計算了點到屏幕中心的距離distance,故而:

x1 = 0.5 + distance *cos(angle)

y1 = 0.5 + distance *sin(angle)

Shader代碼如下所示:

Shader "Lpy/ScreenRot"{ Properties { _MainTex ("Main Tex", 2D) = "white" {} _Rot ("Rotation", float) = 0 } SubShader { Tags {"Queue"="Geometry"} Pass { Tags { "LightMode"="ForwardBase" } ZWrite Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #define PI 3.14159265358979 sampler2D _MainTex; float _Rot; struct a2v { float4 vertex : POSITION; float3 texcoord : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert (a2v v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord; return o; } fixed4 frag (v2f i) : SV_Target { //與中心點(0.5,0.5)的距離 float distance = sqrt((i.uv.x - 0.5)*(i.uv.x - 0.5) +(i.uv.y - 0.5)*(i.uv.y - 0.5)); //距離越大,旋轉角度越大 _Rot *=distance; //計算旋轉角度 float angle = step(i.uv.x,0.5)*PI+ atan((i.uv.y - 0.5)/(i.uv.x - 0.5)) + _Rot; //計算坐標 i.uv.x = 0.5 + distance *cos(angle); i.uv.y = 0.5 + distance *sin(angle); fixed4 c = tex2D(_MainTex, i.uv); return c; } ENDCG } } FallBack "Specular"}

2、使用材質

新建c#文件,編寫ScreenRot類,它由一個共有變數mtl,在它的OnRenderImage方法中調用Graphics.Blit將屏幕圖像(對應shader中的_MainTex)與材質混合起來。

using UnityEngine;using System.Collections; public class ScreenRot : MonoBehaviour { public Material mtl; void OnRenderImage(RenderTexture src, RenderTexture dest) { Graphics.Blit (src, dest,mtl); }}

然後給新建一個名為ScreenRot的材質,使用上述編寫的Shader。然後給攝像機添加ScreenRot組件,設置剛剛創建的材質,如下圖所示。

運行遊戲,調整材質的「Rotation」屬性,即可看到旋轉特效。

3、代碼中引用

Shader中並沒有涉及時間的控制,旋轉速度需要由c#代碼控制,將ScreenRot修改成下面的代碼,即可讓屏幕自動旋轉。

using UnityEngine;using System.Collections; public class ScreenRot : MonoBehaviour { public Material mtl; public float rot; // Update is called once per frame void Update () { rot += 0.1f; } void OnRenderImage(RenderTexture src, RenderTexture dest) { if (rot == 0.0) return; mtl.SetFloat("_Rot", rot); Graphics.Blit (src, dest,mtl); }}

這個效果能夠運用在很多場合,比如使用「正向旋轉→切換場景→反向旋轉」實現切屏特效。

最後依然到了廣告時間:筆者出版了一本Unity3D實戰類書籍《Unity3D網路遊戲實戰》。該書通過一個完整的多人坦克對戰實例,詳細介紹網路遊戲開發過程中涉及到的知識和技巧。書中還介紹了服務端框架、客戶端網路模塊、UI系統的架構等內容。相信透過本書,讀者能夠掌握Unity3D網路遊戲開發的大部分知識,也能夠從框架設計中了解商業遊戲的設計思路,感謝大家支持。

Unity3D熱更新框架教程:zhuanlan.zhihu.com/p/21


推薦閱讀:

手游逆向分析<二>: Unity內還原《鎮魔曲》角色渲染效果
Unity命令行模式,也能「日誌實時輸出」
利用GPU實現無盡草地的實時渲染

TAG:Unity游戏引擎 | shader | 游戏开发 |