OpenGL ES實(shí)現(xiàn)動(dòng)效濾鏡

本文通過自定義著色器的方式實(shí)現(xiàn)縮放、靈魂出竅癣疟、閃爍挣柬、閃白、毛刺睛挚、幻覺等濾鏡效果邪蛔。由于主要的代碼邏輯在著色器這塊,客戶端代碼就不再贅述竞川。

縮放濾鏡

scale.gif

實(shí)現(xiàn)思路

可以看到這個(gè)濾鏡的實(shí)現(xiàn)思路是將圖片周期性放大店溢,我們可以在著色器傳入一個(gè)時(shí)間,并模以動(dòng)畫時(shí)長委乌,用正弦函數(shù)的周期性性質(zhì)實(shí)現(xiàn)周期變化的效果床牧。

實(shí)現(xiàn)代碼

具體可以在頂點(diǎn)著色器實(shí)現(xiàn)。代碼如下遭贸。


attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;
// 外部傳入時(shí)間
uniform float Time;

const float PI = 3.1415926;

void main (void) {
    // 動(dòng)畫時(shí)間
    float duration = 0.6;
    // 最大放大比例
    float maxAmplitude = 0.3;
    // 得到當(dāng)前時(shí)間處于單個(gè)周期哪個(gè)段
    float time = mod(Time, duration);
    // 也可以不取絕對值戈咳,因?yàn)橹辉?~pi之間變化
    float amplitude = 1.0 + maxAmplitude * abs(sin(time * (PI / duration)));
    
    gl_Position = vec4(Position.x * amplitude, Position.y * amplitude, Position.zw);
    
    TextureCoordsVarying = TextureCoords;
}

靈魂出竅

soulout.gif

實(shí)現(xiàn)思路

這個(gè)效果除了底下的原圖外,還有一個(gè)放大且透明度逐漸降低的圖層壕吹,所以我們可以用一個(gè)透明放大的圖層與原圖進(jìn)行顏色混合實(shí)現(xiàn)這個(gè)效果

實(shí)現(xiàn)代碼

因?yàn)樯婕暗筋伾焐埽晕覀冃枰谄髦袑?shí)現(xiàn)這個(gè)效果。


precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

void main (void) {
    // 動(dòng)畫時(shí)長
    float duration = 0.7;
    // 最大縮放比例
    float maxScale = 1.8;
    // 最大透明度
    float maxAlpha = 0.4;
    // 通過時(shí)間和動(dòng)畫時(shí)長計(jì)算當(dāng)前進(jìn)度
    float progress = mod(Time, duration) / duration;
    // 通過進(jìn)度計(jì)算當(dāng)前透明度
    float alpha = maxAlpha * (1.0 - progress);
    // 當(dāng)前縮放比例
    float scale = 1.0 + (maxScale - 1.0) * progress;
    // 獲取放大的紋理坐標(biāo)
    float weakX = 0.5 + (TextureCoordsVarying.x - 0.5) / scale;
    float weakY = 0.5 + (TextureCoordsVarying.y - 0.5) / scale;
    vec2 wekTextureCoords = vec2(weakX, weakY);
    // 得到放大后的紋素
    vec4 weakMask = texture2D(Texture, wekTextureCoords);
    // 放大后的紋素和原紋素混合
    vec4 mask = texture2D(Texture, TextureCoordsVarying);
    gl_FragColor = mask * (1.0 - alpha) + weakMask * alpha;
}

閃爍濾鏡

shake.gif

實(shí)現(xiàn)思路

這個(gè)效果是一個(gè)放大的效果耳贬,并且有一個(gè)同時(shí)放大且發(fā)生顏色偏移的圖層踏堡,兩個(gè)圖層顏色混合的結(jié)果。

實(shí)現(xiàn)代碼

同樣咒劲,這個(gè)效果需要在片元著色器中實(shí)現(xiàn)顷蟆。


precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

void main (void) {
    // 動(dòng)畫時(shí)長
    float duration = 0.7;
    // 最大縮放比例
    float maxScale = 1.1;
    // 偏移值
    float offset = 0.02;
    // 當(dāng)前進(jìn)度
    float progress = mod(Time, duration) / duration;
    // 顏色偏移向量
    vec2 offsetCoords = vec2(offset, offset) * progress;
    // 放大比例
    float scale = 1.0 + (maxScale - 1.0) * progress;
    // 放大后的紋素
    vec2 ScaleTextureCoords = vec2(0.5, 0.5) + (TextureCoordsVarying - vec2(0.5, 0.5)) / scale;
    // 顏色偏移紋素值
    vec4 maskR = texture2D(Texture, ScaleTextureCoords + offsetCoords);
    vec4 maskB = texture2D(Texture, ScaleTextureCoords - offsetCoords);
    // 未發(fā)生偏移紋素值
    vec4 mask = texture2D(Texture, ScaleTextureCoords);
    
    // 顏色混合
    gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}

閃白濾鏡

shakewhite.gif

實(shí)現(xiàn)思路

這個(gè)效果比較簡單,是一個(gè)紋理圖層和一個(gè)白色透明度漸變的圖層混合的結(jié)果腐魂。

時(shí)間思路

同樣需要片元著色器中實(shí)現(xiàn)帐偎。


precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;

void main (void) {
    
    // 動(dòng)畫周期
    float duration = 0.7;
    // 當(dāng)前處于周期哪個(gè)階段
    float time = mod(Time, duration);
    // 當(dāng)前透明度
    float alpha = abs(sin(PI * time/duration));
    // 白色圖層紋素
    vec4 whiteMask = vec4(vec3(1.0), alpha);
    // 原圖層紋素
    vec4 mask = texture2D(Texture, TextureCoordsVarying);
    
    // 混合
    gl_FragColor = mask * (1.0 - alpha) + whiteMask * alpha;
}

毛刺濾鏡

glitch.gif

實(shí)現(xiàn)思路

這個(gè)效果是兩個(gè)效果組成而成的,一個(gè)是細(xì)微的顏色偏移蛔屹,一個(gè)隨機(jī)的x軸方向的較大的偏移削樊,由于GLSL沒有隨機(jī)數(shù)函數(shù),所以需要自己實(shí)現(xiàn)一個(gè)隨機(jī)數(shù)函數(shù)兔毒。

實(shí)現(xiàn)代碼


precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;

// 隨機(jī)數(shù)生成函數(shù)
float rand(float n) {
    return fract(sin(n) * 43758.3842949);
}

void main (void) {
    // 動(dòng)畫時(shí)長
    float duration = 0.3;
    // 最大抖動(dòng)
    float maxJitter = 0.06;
    // 紅色偏移
    float rOffset = 0.01;
    // 藍(lán)色偏移
    float bOffset = -0.025;
    // 當(dāng)前周期時(shí)間段
    float time = mod(Time, duration*2.0);
    // 當(dāng)前進(jìn)度 (0~1)
    float amplitude = max(sin(PI * (time / duration)), 0.0);
    // 隨機(jī)抖動(dòng)
    float jitter = rand(TextureCoordsVarying.y) * 2.0 - 1.0;
    // 通過是否大于最大都懂判斷是否需要偏移
    bool needOffset = abs(jitter) < maxJitter * amplitude;
    // 發(fā)生抖動(dòng)的紋理x坐標(biāo)
    float textureX = TextureCoordsVarying.x + (needOffset ? jitter : (jitter * amplitude * 0.006));
    // 紋理坐標(biāo)
    vec2 textureCoords = vec2(textureX, TextureCoordsVarying.y);
    
    vec4 mask = texture2D(Texture, textureCoords);
    vec4 maskR = texture2D(Texture, textureCoords + vec2(rOffset * amplitude, 0.0));
    vec4 maskB = texture2D(Texture, textureCoords + vec2(bOffset * amplitude, 0.0));
    
    gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}

幻覺濾鏡

huanjue.gif

實(shí)現(xiàn)思路

這個(gè)效果比較復(fù)雜漫贞,首先,最明顯是一個(gè)放大的育叁、周期性旋轉(zhuǎn)的圖層绕辖,另外,有各個(gè)不同偏移值擂红、不同透明度的圖層混合而成仪际。

實(shí)現(xiàn)代碼

precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;
const float duration = 2.0;

// 根據(jù)當(dāng)前周期時(shí)間短,紋理坐標(biāo)昵骤,縮放生成紋理圖層
vec4 getMask(float time, vec2 textureCoords, float padding) {
   // 計(jì)算位于圓周路徑的位置
    vec2 translation = vec2(sin(time * (PI * 2.0 / duration)),
                            cos(time * (PI * 2.0 / duration)));
    // 顏色偏移坐標(biāo)
    vec2 translationTextureCoords = textureCoords + padding * translation;
    vec4 mask = texture2D(Texture, translationTextureCoords);
    
    return mask;
}
// 獲得當(dāng)前位于周期哪個(gè)時(shí)間段
float maskAlphaProgress(float currentTime, float hideTime, float startTime) {
    float time = mod(duration + currentTime - startTime, duration);
    // 如果超過過期時(shí)間树碱,則返回過期時(shí)間
    return min(time, hideTime);
}

void main (void) {
    float time = mod(Time, duration);
    float scale = 1.2;
    // 獲得縮放的坐標(biāo)偏移量
    float padding = 0.5 * (1.0 - 1.0 / scale);
    // 放大后的紋理坐標(biāo)
    vec2 textureCoords = vec2(0.5, 0.5) + (TextureCoordsVarying - vec2(0.5, 0.5)) / scale;
    // 隱藏時(shí)間
    float hideTime = 0.9;
    // 每個(gè)圖層之間的時(shí)間間隔
    float timeGap = 0.2;
    // 紅綠藍(lán)的最大透明度,用于顏色混合
    float maxAlphaR = 0.05; // max R
    float maxAlphaG = 0.5; // max G
    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);
    // 循環(huán)生成圖層
    for (float f = 0.0; f < duration; f += timeGap) {
        float tmpTime = f;
        // 圖層
        vec4 tmpMask = getMask(tmpTime, textureCoords, padding);
        
        // 計(jì)算這個(gè)圖層的各個(gè)透明度
        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;
        // 與上個(gè)透明圖層混合
        resultMask += vec4(tmpMask.r * tmpAlphaR,
                           tmpMask.g * tmpAlphaG,
                           tmpMask.b * tmpAlphaB,
                           1.0);
        // 獲取當(dāng)前透明度变秦,用于與主圖層混合
        alphaR -= tmpAlphaR;
        alphaG -= tmpAlphaG;
        alphaB -= tmpAlphaB;
    }
    // 幻覺圖層與主圖層混合
    resultMask += vec4(mask.r * alphaR, mask.g * alphaG, mask.b * alphaB, 1.0);

    gl_FragColor = resultMask;
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末成榜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蹦玫,更是在濱河造成了極大的恐慌赎婚,老刑警劉巖刘绣,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異挣输,居然都是意外死亡纬凤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門撩嚼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來停士,“玉大人,你說我怎么就攤上這事完丽×导迹” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵逻族,是天一觀的道長蜻底。 經(jīng)常有香客問我,道長聘鳞,這世上最難降的妖魔是什么朱躺? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮搁痛,結(jié)果婚禮上长搀,老公的妹妹穿的比我還像新娘。我一直安慰自己鸡典,他們只是感情好源请,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著彻况,像睡著了一般谁尸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上纽甘,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天良蛮,我揣著相機(jī)與錄音,去河邊找鬼悍赢。 笑死决瞳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的左权。 我是一名探鬼主播皮胡,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赏迟!你這毒婦竟也來了屡贺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎甩栈,沒想到半個(gè)月后泻仙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡量没,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年玉转,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片允蜈。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蒿柳,靈堂內(nèi)的尸體忽然破棺而出饶套,到底是詐尸還是另有隱情,我是刑警寧澤垒探,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布妓蛮,位于F島的核電站,受9級特大地震影響圾叼,放射性物質(zhì)發(fā)生泄漏蛤克。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一夷蚊、第九天 我趴在偏房一處隱蔽的房頂上張望构挤。 院中可真熱鬧,春花似錦惕鼓、人聲如沸筋现。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矾飞。三九已至,卻和暖如春呀邢,著一層夾襖步出監(jiān)牢的瞬間洒沦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工价淌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留申眼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓蝉衣,卻偏偏與公主長得像豺型,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子买乃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353