Unity特效设计教程:实现“梦幻旋屏”

作者:罗培羽 授权游资网发布 2019-01-15




关联文章:

Unity特效设计教程:实现“梦幻旋屏”
Unity特效设计教程:图片的切割与翻转
Unity特效设计教程(四) :标题光效
Unity特效设计教程:滚动的背景

游戏开发中,往往会用到一些屏幕特效。下图展现的是一种“旋屏”效果,它会旋转屏幕图像,且距离中心点越远的点旋转角度越大。这种效果特别适合营造“梦幻”感,比如,在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,故而:

  1. x1 = 0.5 + distance *cos(angle)

  2. y1 = 0.5 + distance *sin(angle)

  3. Shader代码如下所示:

  4. Shader "Lpy/ScreenRot"
  5. {
  6.     Properties
  7.     {
  8.         _MainTex ("Main Tex", 2D) = "white" {}
  9.         _Rot ("Rotation", float) = 0
  10.     }

  11.     SubShader
  12.     {
  13.         Tags {"Queue"="Geometry"}
  14.         Pass
  15.         {
  16.             Tags { "LightMode"="ForwardBase" }
  17.             ZWrite Off

  18.             CGPROGRAM
  19.             #pragma vertex vert  
  20.             #pragma fragment frag
  21.             #include "UnityCG.cginc"
  22.             #define PI 3.14159265358979  

  23.             sampler2D _MainTex;
  24.             float _Rot;
  25.             struct a2v
  26.             {  
  27.                 float4 vertex : POSITION;
  28.                 float3 texcoord : TEXCOORD0;
  29.             };  

  30.             struct v2f
  31.             {  
  32.                 float4 pos : SV_POSITION;
  33.                 float2 uv : TEXCOORD0;
  34.             };  

  35.             v2f vert (a2v v)
  36.             {  
  37.                 v2f o;  
  38.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  39.                 o.uv = v.texcoord;
  40.                 return o;
  41.             }

  42.             fixed4 frag (v2f i) : SV_Target
  43.             {
  44.                 //与中心点(0.5,0.5)的距离
  45.                 float distance = sqrt((i.uv.x - 0.5)*(i.uv.x - 0.5) +(i.uv.y - 0.5)*(i.uv.y - 0.5));
  46.                 //距离越大,旋转角度越大
  47.                 _Rot *=distance;
  48.                 //计算旋转角度
  49.                 float angle = step(i.uv.x,0.5)*PI+ atan((i.uv.y - 0.5)/(i.uv.x - 0.5)) + _Rot;
  50.                 //计算坐标
  51.                 i.uv.x = 0.5 +   distance *cos(angle);
  52.                 i.uv.y = 0.5 +   distance *sin(angle);

  53.                 fixed4 c = tex2D(_MainTex, i.uv);
  54.                 return c;
  55.             }
  56.         ENDCG
  57.         }  
  58.     }
  59.     FallBack "Specular"
  60. }
复制代码


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修改成下面的代码,即可让屏幕自动旋转。

  1. using UnityEngine;
  2. using System.Collections;

  3. public class ScreenRot : MonoBehaviour
  4. {
  5.     public Material mtl;
  6.     public  float rot;

  7.     // Update is called once per frame
  8.     void Update ()
  9.     {
  10.         rot += 0.1f;
  11.     }

  12.     void OnRenderImage(RenderTexture src, RenderTexture dest)
  13.     {
  14.         if (rot == 0.0)
  15.             return;
  16.         mtl.SetFloat("_Rot", rot);
  17.         Graphics.Blit (src, dest,mtl);
  18.     }
  19. }
复制代码

这个效果能够运用在很多场合,比如使用“正向旋转→切换场景→反向旋转”实现切屏特效。

最后依然到了广告时间:笔者出版了一本Unity3D实战类书籍《Unity3D网络游戏实战》。该书通过一个完整的多人坦克对战实例,详细介绍网络游戏开发过程中涉及到的知识和技巧。书中还介绍了服务端框架、客户端网络模块、UI系统的架构等内容。相信透过本书,读者能够掌握Unity3D网络游戏开发的大部分知识,也能够从框架设计中了解商业游戏的设计思路,感谢大家支持。

Unity3D热更新框架教程:https://zhuanlan.zhihu.com/p/21386682


专栏地址:https://zhuanlan.zhihu.com/p/24371823


最新评论
暂无评论
参与评论

商务合作 查看更多

编辑推荐 查看更多