今天我们要在 UGUI 上实现图片RGB通道分离抖动效果,先看最终效果图
实现这个效果,使用了 Shader 和 C# 代码,Shader 用于实现效果,C# 用于控制抖动开关,也就是什么时候抖动,什么时候停止。Shader 的原理大概就是通过不同的参数,分别采样图片的RGB三个通道的颜色,然后再合成最终的颜色。Shader代码如下
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则是开启抖动效果。通过随机值来控制抖动间隔。
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# 代码,运行即可看到效果。