濾鏡效果.gif
案例demo
1、縮放效果
實現原理:通過修改頂點坐標和紋理坐標的對應關系來實現。
實現步驟
實現原理
-
設定縮放的時間周期。float duration = 0.6
由于傳入的時間參數是時間戳,一直增長。通過mod求余函數,對duration求余。可以將時間限制在0.6以內不斷循環的時間周期時間周期圖1
。
時間周期圖1 -
設定縮放的振幅(最大放大多少,最小縮小多少)
這里使用正弦函數sin的值域在[-1,1]范圍內周期變化的特性。來設置紋理振幅的周期性變化
振幅
- 紋理坐標乘以設置的振幅,實現紋理坐標的放大和縮小
頂點著色器代碼實現
attribute vec4 position;
attribute vec2 textureCoord;
varying lowp vec2 textureCoordVarying;
uniform float Time;//時間參數
const float PI = 3.1415926;
void main(){
float duration = 0.6;//時間周期(一次縮放效果的時長)
float maxAmplitude = 0.3;最大縮放幅度(振幅)
//mod 求余函數 將時間對duration取余。
//將時間變換成0.6以內循環的時間周期[0,0.6)
float time = mod(Time,duration);
//amplitude振幅
// 引入sin函數為了得到[0,1]循環變化的值域。將的到循環變化的振幅值
// sin函數值域[-1,1],abs 取絕對值將值域變成[0,1]
//振幅范圍[1, 1+ maxAmplitude];
float amplitude = maxAmplitude * abs(sin(time * (PI / duration))) + 1.0;
textureCoordVarying = textureCoord;
// 將頂點坐標xy乘以放大系數(振幅),在紋理坐標不變的情況。就達到了縮放效果
//將頂點坐標x,y進行縮放變化,zw保持不變
gl_Position = vec4(position.x * amplitude,position.y * amplitude,position.zw);
}
2、靈魂出竅
實現原理:兩個層疊加。并且上面一層隨時間逐漸放大、透明度逐漸降低。
靈魂出竅
實現步驟
- 設置時間周期
duration
,mod
求余將時間戳變換值duration
內的循環的時間周期time = mod(Time,duration)
。 - 獲取當前時間時時間周期內進度(占比)。
progress =time/duration
- 透明度歲進度降低
alpha = 1 - progress
,可以設置透明度變換的上限值alpha = (1 - progress) * maxAlpha
- 紋理坐標的放大
設置圖片放大的上限maxScale = 1.8
設置縮放比例scale = 1.0 +(maxScale - 1) * progress
- 獲取放大后的紋理坐標、放大后紋理坐標的紋素
- 原紋理和放大后的紋理進行顏色混合,賦值gl_FragColor
放大后的紋理weakMask(在mask的基礎上做了放大處理) ,原紋理mask
GLSL顏色混合方程式=mask * (1- alpha) + weakMask * alpha
alpha、scale變換
紋理坐標的變換
片元著色器中實現
precision highp float;
varying lowp vec2 textureCoordVarying;
uniform sampler2D Texture;
uniform float Time;
void main(){
float duration = 0.7;//時間周期
float maxAlpha = 0.4;//透明度上限
float maxScale = 1.8;//放大倍數上限
//時間周期內的進度
float progress = mod(Time, duration) / duration; // 0~1
//該時間進度下的透明度
float alpha = maxAlpha * (1.0 - progress);
//該時間進度下的縮放比例
float scale = 1.0 + (maxScale - 1.0) * progress;
//紋理縮放變換后的紋理坐標
// 將像素點的紋理坐標x、y到紋理中點的距離進行縮放(放大),保持頂點坐標不變,達到向四周拉伸的效果
float weakX = 0.5 + (textureCoordVarying.x - 0.5) / scale;
float weakY = 0.5 + (textureCoordVarying.y - 0.5) / scale;
vec2 weakTextureCoords = vec2(weakX, weakY);
//紋理縮放變換的紋素
vec4 weakMask = texture2D(Texture, weakTextureCoords);
//原紋理的紋素
vec4 mask = texture2D(Texture, textureCoordVarying);
//顏色混合
gl_FragColor = mask * (1.0 - alpha) + weakMask * alpha;
}
3、抖動濾鏡
實現原理:顏色偏移 + 微弱的放大效果
抖動濾鏡
實現步驟
- 設置時間周期、進度、縮放比例
- 計算當前進度下顏色偏移、縮放比例
- 獲取放大后的紋理坐標的紋素、放大后的紋理顏色偏移后的紋素
- 從放大的紋素、偏移的紋素獲取RGBA,賦值gl_FragColor
precision highp float;
varying lowp vec2 textureCoordVarying;
uniform sampler2D Texture;
uniform float Time;
void main(){
float duration = 0.7;
float maxScale = 1.1;
//顏色偏移步長
float offset = 0.02;
float progress = mod(Time, duration) / duration; // 0~1
//顏色偏移值(0,0.02)
vec2 offsetCoords = vec2(offset, offset) * progress;
float scale = 1.0 + (maxScale - 1.0) * progress;
//放大后的紋理坐標
vec2 ScaleTextureCoords = vec2(0.5, 0.5) + (textureCoordVarying - vec2(0.5, 0.5)) / scale;
//放大后的紋理紋素進行顏色偏移 + offsetCoords
vec4 maskR = texture2D(Texture, ScaleTextureCoords + offsetCoords);
//放大后的紋理紋素進行顏色偏移 - offsetCoords
vec4 maskB = texture2D(Texture, ScaleTextureCoords - offsetCoords);
// 放大后紋理坐標的紋素
vec4 mask = texture2D(Texture, ScaleTextureCoords);
// 從3組顏色中取出RGBA顏色值,賦值gl_FragColor
// 也可以值取一個紋素偏移值和不發生偏移的紋素。方便觀察紋素偏移現象。
// gl_FragColor = vec4(maskR.r, mask.g, maskR.b, mask.a);
// gl_FragColor = vec4(maskB.r, mask.g, maskB.b, mask.a);
gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}
4、閃白濾鏡
實現原理:添加白色圖層,白色圖層隨時間透明度進行變化。
precision highp float;
varying lowp vec2 textureCoordVarying;
uniform sampler2D Texture;
uniform float Time;
const float PI = 3.1415926;
void main(){
//時間周期
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, textureCoordVarying);
//顏色混合。白色遮照的透明度時間變化
gl_FragColor = mask * (1.0 - amplitude) + whiteMask * amplitude;
}
5、毛刺濾鏡
實現原理:撕裂 + 微弱的顏色偏移
。讓每一行像素隨機偏移-1~1的距離(相對紋理坐標而言)。但是如果正畫面都偏移比較大的值,可能看不出原圖片的樣子。所以設定一個閥值,小于閥值的進行偏移,大于的乘上一個縮小系數。最終絕大部分行都會進行微小偏移,只有少量的行進行較大偏移。
毛刺濾鏡
片元著色器
precision highp float;
varying lowp vec2 textureCoordVarying;
uniform sampler2D Texture;
uniform float Time;
const float PI = 3.1415926;
float rand(float n) {
//fract(x)返回x的小數部分
//返回 sin(n) * 43758.5453123
return fract(sin(n) * 43758.5453123);
}
void main(){
float maxJitter = 0.06;//最大抖動
float duration = 0.3;//時間周期(一次毛刺濾鏡的時長)
float colorROffset = 0.01;//紅色顏色偏移
float colorBOffset = -0.025;//綠色顏色偏移
//將傳入的時間轉換成周期
float time = mod(Time, duration * 2.0);
//amplitude 振幅。引入PI是為了使用sin函數。將amplitude 限制在1.0 ~1.3之間,隨時間變化
float amplitude = max(sin(time * (PI / duration)), 0.0);
//像素隨機偏移范圍(-1,1)
float jitter = rand(textureCoordVarying.y) * 2.0 - 1.0; // -1~1
//判斷是否需要偏移,如果jitter范圍< 最大抖動 *振幅
bool needOffset = abs(jitter) < maxJitter * amplitude;
//獲取紋理坐標x,根據needOffset 計算x的撕裂,yes,撕裂大,no撕裂小
float textureX = textureCoordVarying.x + (needOffset ? jitter : (jitter * amplitude * 0.006));
//獲取撕裂后的紋理坐標
vec2 textureCoords = vec2(textureX, textureCoordVarying.y);
//顏色偏移
//撕裂后紋素
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);
}
6、幻覺濾鏡
實現原理:殘影效果 + 顏色偏移
殘影效果:在移動過程中,每經過一段時間間隔,根據當前的位置去創建一個新層,并且的不透明度隨時間逐漸減弱。在一個移動周期內。可以看到很多透明度不同的層疊加在一起,從而形成殘影的效果,殘影,讓圖片時間做圓周運動。
顏色偏移:物體移動的過程是藍色在前面,紅色在后面。搜一整個過程可以理解成:在移動的過程中,每隔一段時間,遺失了一部分紅色通道的值在原來的位置。并且這部分紅色通道的值,隨著時間偏移,會逐漸恢復。
幻覺濾鏡
片元著色器
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) {
//獲取時間周期
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;
//隱藏時間
float hideTime = 0.9;
//時間間隔
float timeGap = 0.2;
//注意:只保留了紅色的透明的通道值。幻覺效果殘留紅色
//新圖層 -- R色透明度
float maxAlphaR = 0.5; // max R
//新圖層 -- G色透明度
float maxAlphaG = 0.05; // max G
//新圖層 -- B色透明度
float maxAlphaB = 0.05; // max B
//獲取新的圖層坐標
vec4 mask = getMask(time, textureCoords, padding);
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;
//獲取0~2s內所獲取的運動后的紋理坐標
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;
//累計每一層每個通道乘以透明度顏色通道
resultMask += vec4(tmpMask.r * tmpAlphaR,
tmpMask.g * tmpAlphaG,
tmpMask.b * tmpAlphaB,
1.0);
//透明度遞減
alphaR -= tmpAlphaR;
alphaG -= tmpAlphaG;
alphaB -= tmpAlphaB;
}
//最終的顏色+=紅綠藍 * 透明度
resultMask += vec4(mask.r * alphaR, mask.g * alphaG, mask.b * alphaB, 1.0);
gl_FragColor = resultMask;
}