OpenGLES 縮放、幻覺、毛刺濾鏡效果

濾鏡效果.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、靈魂出竅

實現原理:兩個層疊加。并且上面一層隨時間逐漸放大、透明度逐漸降低。

靈魂出竅

實現步驟

  • 設置時間周期durationmod求余將時間戳變換值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;
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370