今天我们要在 UGUI 上实现图片RGB通道分离抖动效果,先看最终效果图

p002701_imageglitch

实现这个效果,使用了 Shader 和 C# 代码,Shader 用于实现效果,C# 用于控制抖动开关,也就是什么时候抖动,什么时候停止。Shader 的原理大概就是通过不同的参数,分别采样图片的RGB三个通道的颜色,然后再合成最终的颜色。Shader代码如下

1
2
3
4
5
6
7
8
9
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
Shader "iMoeGirl/DouYin" {
Properties {
[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
_ScanLineJitter("ScanLineJitter", Vector) = (0, 0, 0, 0)
_VerticalJump("VerticalJump", Vector) = (0, 0, 0, 0)
_HorizontalShake("HorizontalShake", Float) = 0.005
_ColorDrift("ColorDrift", Vector) = (0.06, 0, 0, 0)
_IsOpen("IsOpen", Int) = 1
}

SubShader {

pass {
Blend SrcAlpha OneMinusSrcAlpha

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

float2 _ScanLineJitter;
float2 _VerticalJump;
float _HorizontalShake;
float2 _ColorDrift;

struct appdata_t {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};

struct v2f {
float4 vertex : SV_POSITION;
half2 uv : TEXCOORD0;
};

float nrand(float x, float y)
{
return frac(sin(dot(float2(x, y), float2(12.9898, 78.233))) * 43758.5453);
}

v2f vert(appdata_t IN){
v2f OUT;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.uv = IN.uv;
return OUT;
}

sampler2D _MainTex;
float _Scale;
float _IsOpen;

fixed4 frag(v2f i) : SV_TARGET {
float u = i.uv.x;
float v = i.uv.y;

// Scan line jitter
float jitter = nrand(v, _Time.x) * 2 - 1;
jitter *= step(_ScanLineJitter.y, abs(jitter)) * _ScanLineJitter.x;

// vertical jump
float jump = lerp(v, frac(v + _VerticalJump.y), _VerticalJump.x);

// Horizontal shake
float shake = (nrand(_Time.x, 2) - 0.5) * _HorizontalShake;

// Color drift
float drift = (sin(jump + _ColorDrift.y )) * _ColorDrift.x;

float value = (nrand(_Time.x, 2) - 0.5) * 0.002 * _IsOpen;

half4 src1 = tex2D(_MainTex, frac(float2(u + (jitter + shake) * _IsOpen, jump)));
half4 src2 = tex2D(_MainTex, frac(float2(u + (jitter + shake + drift + value) * _IsOpen, jump)));
half4 src3 = tex2D(_MainTex, frac(float2(u + (jitter + shake - drift - value * 3) * _IsOpen, jump)));
return half4(src1.r, src2.g, src3.b, src1.a);

}

ENDCG
}
}
}

C# 代码通过控制Shader中的_IsOpen的值,设置为0则是关掉抖动效果,设置为1则是开启抖动效果。通过随机值来控制抖动间隔。

1
2
3
4
5
6
7
8
9
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
using UnityEngine;
using UnityEngine.UI;

public class ImageGlitch : MonoBehaviour
{
private Image mImage;

private float effectTicker = 0.0f;
private float stayTicker = 0.0f;

private void Start()
{
mImage = gameObject.GetComponent<Image>();
CloseEffect();
stayTicker = Random.Range(0.2f, 0.6f);
}

// Update is called once per frame
void Update()
{
if(stayTicker > 0)
{
stayTicker -= Time.deltaTime;
if(stayTicker <= 0)
{
effectTicker = Random.Range(0.2f, 0.6f);
OpenEffect();
}
}

if(effectTicker > 0)
{
effectTicker -= Time.deltaTime;
if(effectTicker <= 0)
{
stayTicker = Random.Range(1.0f, 2.0f);
CloseEffect();
}
}
}

private void OpenEffect()
{
mImage.material.SetInt("_IsOpen", 1);
}

private void CloseEffect()
{
mImage.material.SetInt("_IsOpen", 0);
}
}

新建立 一个 Image 组件,然后将自己的图片赋予 Image。新建一个 Material,使用我们上面写的 Shader,然后将 Material 赋予 Image 组件,挂载 C# 代码,运行即可看到效果。