這篇濾鏡效果的實現是在上一篇分屏濾鏡的基礎上來進行實現的,一樣的前提是能夠利用GLSL加載一張正常的圖片。bash
縮放濾鏡實際上基本的原理是能夠經過修改頂點座標和紋理座標的對應關係來實現放大縮小效果。ui
這個放大縮小的實現其實能夠在頂點着色器中實現,也能夠在片元着色器中實現。(注意:在運行時,着色器代碼中最好不要有中文) 頂點着色器代碼:spa
// 頂點座標
attribute vec4 Position;
// 紋理座標
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;
// 時間(經過uniform傳入一個時間Time)
uniform float Time;
const float PI = 3.1415926;
void main (void) {
// 一次縮放效果時長
float duration = 0.4;
// 最大縮放幅度
float maxAmplitude = 0.3;
// 表示時間週期
float time = mod(Time, duration);
// 縮放幅度 [1.0,1.3]
float amplitude = 1.0 + maxAmplitude * abs(sin(time * (PI / duration)));
// 頂點座標x/y 分別乘以放大係數[1.0,1.3]
gl_Position = vec4(Position.x * amplitude, Position.y * amplitude, Position.zw);
// 紋理座標
TextureCoordsVarying = TextureCoords;
}
複製代碼
實現效果: 3d
靈魂出竅濾鏡的原理: 是兩個層的疊加,而且上面的那層隨着時間的推移,會逐漸放大且不透明度逐漸下降。這裏也⽤到了放大的效果(基於縮放的原理),咱們此次用片元着⾊器來實現該效果。code
片元着色器代碼:orm
precision highp float;
// 紋理採樣器
uniform sampler2D Texture;
// 紋理座標
varying vec2 TextureCoordsVarying;
// 時間(經過uniform傳入一個時間Time)
uniform float Time;
void main (void) {
// 一次靈魂出竅效果的時長 1.0
float duration = 1.0;
// 透明度上限
float maxAlpha = 0.5;
// 放大圖片上限
float maxScale = 1.8;
// 進度值[0,1]
float progress = mod(Time, duration) / duration; // 0~1
// 透明度範圍[0,0.5]
float alpha = maxAlpha * (1.0 - progress);
// 縮放比例[1.0,1.8]
float scale = 1.0 + (maxScale - 1.0) * progress;
// 放大紋理座標
// 根據放大比例,獲得放大紋理座標 [0,0],[0,1],[1,1],[1,0]
float weakX = 0.5 + (TextureCoordsVarying.x - 0.5) / scale;
float weakY = 0.5 + (TextureCoordsVarying.y - 0.5) / scale;
// 放大紋理座標
vec2 weakTextureCoords = vec2(weakX, weakY);
// 獲取對應放大紋理座標下的紋素(顏色值rgba)
vec4 weakMask = texture2D(Texture, weakTextureCoords);
// 原始的紋理座標下的紋素(顏色值rgba)
vec4 mask = texture2D(Texture, TextureCoordsVarying);
// 顏色混合 默認顏色混合方程式 = mask * (1.0-alpha) + weakMask * alpha;
gl_FragColor = mask * (1.0 - alpha) + weakMask * alpha;
}
複製代碼
實現效果: cdn
抖動的過程當中也是基於縮放的原理,並且它的顏色值產生必定的誤差。 抖動效果: 顏⾊偏移 + 微弱的放大效果blog
片元着色代碼:圖片
precision highp float;
// 紋理
uniform sampler2D Texture;
// 紋理座標
varying vec2 TextureCoordsVarying;
// 時間(經過uniform傳入一個時間Time)
uniform float Time;
void main (void) {
// 一次抖動濾鏡的時長
float duration = 1.0;
// 放大圖片上限
float maxScale = 1.2;
// 顏色偏移步長
float offset = 0.02;
// 進度[0,1]
float progress = mod(Time, duration) / duration;
// 顏色偏移值範圍[0,0.02]
vec2 offsetCoords = vec2(offset, offset) * progress;
// 縮放範圍[1.0-1.2];
float scale = 1.0 + (maxScale - 1.0) * progress;
// 放大紋理座標.
vec2 ScaleTextureCoords = vec2(0.5, 0.5) + (TextureCoordsVarying - vec2(0.5, 0.5)) / scale;
// 獲取3組顏色rgb
// 原始顏色+offsetCoords
vec4 maskR = texture2D(Texture, ScaleTextureCoords + offsetCoords);
// 原始顏色-offsetCoords
vec4 maskB = texture2D(Texture, ScaleTextureCoords - offsetCoords);
// 原始顏色
vec4 mask = texture2D(Texture, ScaleTextureCoords);
// 從3組來獲取顏色:
// maskR.r,mask.g,maskB.b 注意這3種顏色取值能夠打亂或者隨意發揮.只是效果會有不同.
// mask.a 獲取原圖的透明度
gl_FragColor = vec4(mask.r, maskR.g, maskB.b, mask.a);
}
複製代碼
實現效果: ci
閃白濾鏡的原理: 在上層添加⽩色圖層 ,⽩色圖層的透明度隨着時間的變化而變化。
片元着色器代碼:
precision highp float;
// 紋理採樣器
uniform sampler2D Texture;
// 紋理座標
varying vec2 TextureCoordsVarying;
// 時間(經過uniform傳入一個時間Time)
uniform float Time;
void main (void) {
// 一次閃白濾鏡的時長
float duration = 0.5;
// 表示時間週期[0.0,0.5]
float time = mod(Time, duration);
// 白色顏色遮罩層
vec4 whiteMask = vec4(1.0, 1.0, 1.0, 1.0);
// 振幅: (0.0,1.0)
float amplitude = abs(sin(time * (PI / duration)));
// 紋理座標對應的紋素(RGBA)
vec4 mask = texture2D(Texture, TextureCoordsVarying);
// 利用混合方程式; 白色圖層 + 原始紋理圖片顏色 來進行混合
gl_FragColor = mask * (1.0 - amplitude) + whiteMask * amplitude;
}
複製代碼
實現效果:
⽑刺濾鏡的原理: 撕裂 + 微弱的顏⾊偏移。
片元着色器代碼:
precision highp float;
// 紋理
uniform sampler2D Texture;
// 紋理座標
varying vec2 TextureCoordsVarying;
// 時間(經過uniform傳入一個時間Time)
uniform float Time;
// 隨機數
float rand(float n) {
//fract(x),返回x的小數部分數據
return fract(sin(n) * 43758.5453123);
}
void main (void) {
// 最大抖動
float maxJitter = 0.06;
// 一次毛刺濾鏡的時長
float duration = 0.5;
// 紅色顏色偏移量
float colorROffset = 0.01;
//綠色顏色偏移量
float colorGOffset = -0.02;
// 藍色顏色偏移量
float colorBOffset = -0.035;
// 時間週期[0.0,1.0];
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; // -1~1
// 是否要作偏移.
bool needOffset = abs(jitter) < maxJitter * amplitude;
// 獲取紋理X值.根據needOffset,來計算它X撕裂.
// needOffset = YES,撕裂較大;
// needOffset = NO,撕裂較小.
float textureX = TextureCoordsVarying.x + (needOffset ? jitter : (jitter * amplitude * 0.006));
// 撕裂後的紋理座標x,y
vec2 textureCoords = vec2(textureX, TextureCoordsVarying.y);
// 顏色偏移3組顏色
// 根據撕裂後獲取的紋理顏色值
vec4 mask = texture2D(Texture, textureCoords);
// 撕裂後的紋理顏色偏移
vec4 maskR = texture2D(Texture, textureCoords + vec2(colorROffset * amplitude, 0.0));
vec4 maskG = texture2D(Texture, textureCoords + vec2(colorGOffset * amplitude, 0.0));
vec4 maskB = texture2D(Texture, textureCoords + vec2(colorBOffset * amplitude, 0.0));
// 顏色部分發生撕裂.
gl_FragColor = vec4(maskR.r, maskG.g, maskB.b, mask.a);
}
複製代碼
實現效果: