寫在前面,本文所展現的濾鏡效果,實現方式多種多樣,這裏僅提供一個思路參考。
複製代碼
先上效果圖: 思路分析:經過效果圖能夠看出,圖片的大小隨着時間的推移,呈現週期性的變化。那麼咱們能夠根據發現的這個規律,選用正弦三角函數
sin
來幫助咱們實現這個效果。markdown
正弦函數變化規律以下,取值在[-1,1]之間。 ide
圖片的縮放,只須要在頂點着色器裏改變一下頂點座標便可,思惟導圖以下: 函數
實現代碼:oop
//頂點座標
attribute vec4 Position;
//紋理座標
attribute vec2 TextureCoords;
//紋理座標
varying vec2 TextureCoordsVarying;
//時間戳
uniform float Time;
//π
const float PI = 3.1415926;
void main (void) {
//縮放的時間週期
float duration = 0.6;
//最大放大倍數
float maxAmplitude = 0.3;
//Time / duration * PI 當前時間相對多少個PI
//abs(sin(Time / duration * PI) 計算sin 並取絕對值
//maxAmplitude * abs(sin(Time / duration * PI)) 求得當前放大係數
float amplitude = 1.0 + maxAmplitude * abs(sin(Time / duration * PI));
//將頂點座標的x y分別乘以放大係數, 在紋理座標不變的狀況下達到拉伸效果
//xy放大 zw不變
gl_Position = vec4(Position.x * amplitude, Position.y * amplitude, Position.zw);
TextureCoordsVarying = TextureCoords;
}
複製代碼
效果圖: 思路分析:spa
思惟導圖: 3d
實現代碼:code
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
//時間戳
uniform float Time;
void main (void) {
//時間週期
float duration = 0.7;
//透明度上限
float maxAlpha = 0.4;
//放大上限
float maxScale = 1.8;
//進度(0-1)
float progress = mod(Time, duration)/duration;
//透明度(0-4)
float alpha = maxAlpha * (1.0 - progress);
//縮放比例
float scale = 1.0 + (maxScale - 1.0) * progress;
//放大紋理座標
//將頂點座標對應的紋理座標的x值到紋理中點的距離,放大必定的比例. 此次咱們是改變了紋理座標, 而保持頂點座標不變, 一樣達到了拉伸的效果
float weakX = 0.5 + (TextureCoordsVarying.x - 0.5) / scale;
float weakY = 0.5 + (TextureCoordsVarying.y - 0.5) / scale;
//獲得放大的紋理座標
vec2 weakTextureCoords = vec2(weakX, weakY);
//讀取放大後的紋理座標對應紋素的顏色值
vec4 weakMask = texture2D(Texture, weakTextureCoords);
//讀取原始的紋理座標對應紋素的顏色值
vec4 mask = texture2D(Texture, TextureCoordsVarying);
//在GLSL 實現顏色混合方程式. 默認顏色混合方程式 = mask * (1.0 - alpha) + weakMask *alpha
//混合後的顏色 賦值給gl_FragColor
gl_FragColor = mask * (1.0 - alpha) + weakMask * alpha;
}
複製代碼
效果圖: 思路分析:orm
思惟導圖: 代碼實現:事件
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
uniform float Time;
void main (void) {
//一次抖動效果的時長
float duration = 0.7;
//放大圖片的上限
float maxScale = 1.1;
//顏色偏移的步長
float offset = 0.02;
//進度 0 ~ 1
float progress = mod(Time, duration) / duration;
//顏色偏移值0 ~ 0.02
vec2 offsetCoords = vec2(offset, offset) * progress;
//縮放比例 1.0 ~ 1.1
float scale = 1.0 + (maxScale - 1.0) * progress;
//放大後的紋理座標
vec2 ScaleTextureCoords = vec2(0.5, 0.5) + (TextureCoordsVarying - vec2(0.5, 0.5)) / scale;
//獲取三組顏色
//原始顏色 + offset
vec4 maskR = texture2D(Texture, ScaleTextureCoords + offsetCoords);
//原始顏色 - offset
vec4 maskB = texture2D(Texture, ScaleTextureCoords - offsetCoords);
//原始顏色
vec4 mask = texture2D(Texture, ScaleTextureCoords);
//從3組顏色中分別取出 紅色R,綠色G,藍色B,透明度A填充到內置變量gl_FragColor內
gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}
複製代碼
效果圖: 圖片
思路分析:
思惟導圖:
實現代碼:
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
uniform float Time;
const float PI = 3.1415926;
void main (void) {
float duration = 0.6;
float time = mod(Time, duration);
//定義一個白色顏色遮罩
vec4 whiteMask = vec4(1.0, 1.0, 1.0, 1.0);
float amplitude = abs(sin(time * (PI / duration)));
vec4 mask = texture2D(Texture, TextureCoordsVarying);
gl_FragColor = mask * (1.0 - amplitude) + whiteMask * amplitude;
}
複製代碼
效果圖: 思路分析:
思惟導圖: 代碼實現:
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
//時間戳
uniform float Time;
//PI常量
const float PI = 3.1415926;
//GLSL中不提供隨機生成數 須要本身實現一個
//fract(x) 返回x的小數部分
//隨機生成0-1的小數
float rand(float n) {
return fract(sin(n) * 43758.5453123);
}
void main (void) {
//最大抖動上限
float maxJitter = 0.06;
//一次毛刺效果的時長
float duration = 0.3;
//紅色顏色偏移
float colorROffset = 0.01;
//綠色顏色偏移
float colorBOffset = -0.025;
//表示將傳入的事件轉換到一個週期內,範圍是 0 ~ 0.6,抖動時長變成0.6
float time = mod(Time, duration * 2.0);
//振幅,隨着時間變化,範圍是[0, 1]
float amplitude = max(sin(time * (PI / duration)), 0.0);
//像素隨機偏移範圍 [-1,1]
float jitter = rand(TextureCoordsVarying.y) * 2.0 - 1.0;
//判斷是否須要偏移,若是jitter範圍 < 最大範圍*振幅
bool needOffset = abs(jitter) < maxJitter * amplitude;
//獲取紋理x座標,根據needOffset來計算它的x撕裂
float textureX = TextureCoordsVarying.x + (needOffset ? jitter : (jitter * amplitude * 0.006));
//獲取紋理撕裂後的紋理
vec2 textureCoords = vec2(textureX, TextureCoordsVarying.y);
//顏色偏移:獲取3組顏色
//撕裂後的原圖顏色
vec4 mask = texture2D(Texture, textureCoords);
//根據撕裂計算後的紋理座標,獲取紋素
vec4 maskR = texture2D(Texture, textureCoords + vec2(colorROffset * amplitude, 0.0));
//根據撕裂計算後的紋理座標,獲取紋素
vec4 maskB = texture2D(Texture, textureCoords + vec2(colorBOffset * amplitude, 0.0));
//顏色主要撕裂,紅色和藍色部分,因此只調整紅色
gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}
複製代碼
效果圖: 思路分析:
思惟導圖: 代碼實現:
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
uniform float Time;
const float PI = 3.1415926;
//一次幻覺效果的時長
const float duration = 2.0;
//這個函數能夠計算出,在某個時刻圖片的具體位置,經過它咱們能夠每通過一段時間,去生成一個新的圖層
//返回當前圖層像素點的顏色值
vec4 getMask(float time, vec2 textureCoords, float padding) {
vec2 translation = vec2(sin(time * (PI * 2.0 / duration)),
cos(time * (PI * 2.0 / duration)));
vec2 translationTextureCoords = textureCoords + padding * translation;
vec4 mask = texture2D(Texture, translationTextureCoords);
return mask;
}
//這個函數能夠計算出,某個時刻建立的層,在當前時刻的透明度
float maskAlphaProgress(float currentTime, float hideTime, float startTime) {
float time = mod(duration + currentTime - startTime, duration);
return min(time, hideTime);
}
void main (void) {
//將傳入的時間戳轉換到一個週期內,time的範圍是 [0,2]
float time = mod(Time, duration);
//放大倍數
float scale = 1.2;
//偏移量
float padding = 0.5 * (1.0 - 1.0 / scale);
//放大後的紋理座標
vec2 textureCoords = vec2(0.5, 0.5) + (TextureCoordsVarying - vec2(0.5, 0.5)) / scale;
//放大後紋理座標對應紋素的顏色值
vec4 mask = getMask(time, textureCoords, padding);
//隱藏時間
float hideTime = 0.9;
//時間間隔
float timeGap = 0.2;
//注意:只保留了紅色的透明的通道值,由於幻覺效果殘留紅色
//幻影殘留數據
//max RGB alpha
//新圖層的 R透明度
float maxAlphaR = 0.5;
//新圖層的 G透明度
float maxAlphaG = 0.05;
//新圖層的 B透明度
float maxAlphaB = 0.05;
float alphaR = 1.0; // R
float alphaG = 1.0; // G
float alphaB = 1.0; // B
//最終圖層顏色
vec4 resultMask = vec4(0, 0, 0, 0);
for (float f = 0.0; f < duration; f += timeGap) {
float tmpTime = f;
//得到幻影當前時間的顏色值
vec4 tmpMask = getMask(tmpTime, textureCoords, padding);
//某個時刻建立的層,在當前時刻的紅綠藍的透明度
float tmpAlphaR = maxAlphaR - maxAlphaR * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
float tmpAlphaG = maxAlphaG - maxAlphaG * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
float tmpAlphaB = maxAlphaB - maxAlphaB * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
//累計每一層臨時RGB * RGB的臨時透明度
resultMask += vec4(tmpMask.r * tmpAlphaR,
tmpMask.g * tmpAlphaG,
tmpMask.b * tmpAlphaB,
1.0);
//透明度遞減
alphaR -= tmpAlphaR;
alphaG -= tmpAlphaG;
alphaB -= tmpAlphaB;
}
//最終顏色 += 原始紋理的RGB * 透明度
resultMask += vec4(mask.r * alphaR, mask.g * alphaG, mask.b * alphaB, 1.0);
//將最終顏色填充到像素點裏
gl_FragColor = resultMask;
}
複製代碼
demo在這裏