Unity特效(1) 梦幻旋屏

Unity特效(1) 梦幻旋屏

本帖最后由 仅为年时 于 2016-12-29 17:04 编辑

游戏开发中,往往会用到一些屏幕特效。下图展现的是一种“旋屏”效果,它会旋转屏幕图像,且距离中心点越远的点旋转角度越大。这种效果特别适合营造“梦幻”感,比如,在RPG游戏中,经过一段“旋屏”特效,主角穿越到了10年前。

Unity3D 梦幻旋屏122.png (503.56 KB, 下载次数: 4)

下载附件  保存到相册

2016-12-14 20:59 上传







By 知乎@罗培羽

1、编写Shader

下面的着色器代码使用了顶点/片元着色器处理旋屏特效的功能。这里定义3个属性,其中_MainTex代表屏幕贴图,_Rot 代表基准的旋转角度。核心代码在片元着色器frag中实现。

如下图所示,屏幕图像被归一到[0,1]的空间中,中心点为(0.5,0.5)。假设某个点的uv坐标为(x,y),经过一系列处理,它的坐标变为(x1,y1),而(x1,y1)便是实现旋转效果后的uv坐标。

Unity3D 梦幻旋屏337.png (47.55 KB, 下载次数: 0)

下载附件  保存到相册

2016-12-14 21:00 上传






由“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代码如下所示:

[C#] 纯文本查看 复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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)与材质混合起来。

[C#] 纯文本查看 复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
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组件,设置刚刚创建的材质,如下图所示。

Unity3D 梦幻旋屏2433.png (68.05 KB, 下载次数: 3)

下载附件  保存到相册

2016-12-14 21:01 上传






运行游戏,调整材质的“Rotation”属性,即可看到旋转特效。

Unity3D 梦幻旋屏2468.png (219.89 KB, 下载次数: 4)

下载附件  保存到相册

2016-12-14 21:02 上传




3、代码中引用

Shader中并没有涉及时间的控制,旋转速度需要由c#代码控制,将ScreenRot修改成下面的代码,即可让屏幕自动旋转。

[C#] 纯文本查看 复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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网络游戏实战》。该书通过一个完整的多人坦克对战实例,详细介绍网络游戏开发过程中涉及到的知识和技巧。书中还介绍了服务端框架、客户端网络模块、UI系统的架构等内容。相信透过本书,读者能够掌握Unity3D网络游戏开发的大部分知识,也能够从框架设计中了解游戏蛮牛2017商业游戏的设计思路,感谢大家支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值