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

濾鏡效果.gif

案例demo

1、縮放效果

實(shí)現(xiàn)原理:通過修改頂點(diǎn)坐標(biāo)和紋理坐標(biāo)的對應(yīng)關(guān)系來實(shí)現(xiàn)。
實(shí)現(xiàn)步驟

實(shí)現(xiàn)原理

  • 設(shè)定縮放的時(shí)間周期。float duration = 0.6
    由于傳入的時(shí)間參數(shù)是時(shí)間戳,一直增長。通過mod求余函數(shù),對duration求余??梢詫r(shí)間限制在0.6以內(nèi)不斷循環(huán)的時(shí)間周期時(shí)間周期圖1。

    時(shí)間周期圖1

  • 設(shè)定縮放的振幅(最大放大多少,最小縮小多少)
    這里使用正弦函數(shù)sin的值域在[-1,1]范圍內(nèi)周期變化的特性。來設(shè)置紋理振幅的周期性變化


    振幅
  • 紋理坐標(biāo)乘以設(shè)置的振幅,實(shí)現(xiàn)紋理坐標(biāo)的放大和縮小
    頂點(diǎn)著色器代碼實(shí)現(xiàn)
attribute vec4 position;
attribute vec2 textureCoord;
varying lowp vec2 textureCoordVarying;

uniform float Time;//時(shí)間參數(shù)
const float PI = 3.1415926;

void main(){
    
    float duration = 0.6;//時(shí)間周期(一次縮放效果的時(shí)長)
    float maxAmplitude = 0.3;最大縮放幅度(振幅)
    
    //mod 求余函數(shù) 將時(shí)間對duration取余。
   //將時(shí)間變換成0.6以內(nèi)循環(huán)的時(shí)間周期[0,0.6)
    float time = mod(Time,duration);

    //amplitude振幅
   // 引入sin函數(shù)為了得到[0,1]循環(huán)變化的值域。將的到循環(huán)變化的振幅值
   // sin函數(shù)值域[-1,1],abs 取絕對值將值域變成[0,1]
  //振幅范圍[1, 1+ maxAmplitude];
    float amplitude = maxAmplitude * abs(sin(time * (PI / duration))) + 1.0;
    
    textureCoordVarying = textureCoord;
   // 將頂點(diǎn)坐標(biāo)xy乘以放大系數(shù)(振幅),在紋理坐標(biāo)不變的情況。就達(dá)到了縮放效果
    //將頂點(diǎn)坐標(biāo)x,y進(jìn)行縮放變化,zw保持不變
    gl_Position = vec4(position.x * amplitude,position.y * amplitude,position.zw);
}

2、靈魂出竅

實(shí)現(xiàn)原理:兩個(gè)層疊加。并且上面一層隨時(shí)間逐漸放大、透明度逐漸降低。

靈魂出竅

實(shí)現(xiàn)步驟

  • 設(shè)置時(shí)間周期durationmod求余將時(shí)間戳變換值duration內(nèi)的循環(huán)的時(shí)間周期time = mod(Time,duration)。
  • 獲取當(dāng)前時(shí)間時(shí)時(shí)間周期內(nèi)進(jìn)度(占比)。progress =time/duration
  • 透明度歲進(jìn)度降低alpha = 1 - progress,可以設(shè)置透明度變換的上限值alpha = (1 - progress) * maxAlpha
  • 紋理坐標(biāo)的放大
    設(shè)置圖片放大的上限 maxScale = 1.8
    設(shè)置縮放比例scale = 1.0 +(maxScale - 1) * progress
  • 獲取放大后的紋理坐標(biāo)、放大后紋理坐標(biāo)的紋素
  • 原紋理和放大后的紋理進(jìn)行顏色混合,賦值gl_FragColor
    放大后的紋理weakMask(在mask的基礎(chǔ)上做了放大處理) ,原紋理mask
    GLSL顏色混合方程式=mask * (1- alpha) + weakMask * alpha
alpha、scale變換

紋理坐標(biāo)的變換

片元著色器中實(shí)現(xiàn)

precision highp float;

varying lowp vec2 textureCoordVarying;
uniform sampler2D Texture;
uniform float Time;
void main(){
    
    float duration = 0.7;//時(shí)間周期
    float maxAlpha = 0.4;//透明度上限
    float maxScale = 1.8;//放大倍數(shù)上限
    
   //時(shí)間周期內(nèi)的進(jìn)度
    float progress = mod(Time, duration) / duration; // 0~1
    //該時(shí)間進(jìn)度下的透明度
    float alpha = maxAlpha * (1.0 - progress);
    //該時(shí)間進(jìn)度下的縮放比例
    float scale = 1.0 + (maxScale - 1.0) * progress;
    //紋理縮放變換后的紋理坐標(biāo)
   // 將像素點(diǎn)的紋理坐標(biāo)x、y到紋理中點(diǎn)的距離進(jìn)行縮放(放大),保持頂點(diǎn)坐標(biāo)不變,達(dá)到向四周拉伸的效果
    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、抖動(dòng)濾鏡

實(shí)現(xiàn)原理:顏色偏移 + 微弱的放大效果

抖動(dòng)濾鏡

實(shí)現(xiàn)步驟

  • 設(shè)置時(shí)間周期、進(jìn)度、縮放比例
  • 計(jì)算當(dāng)前進(jìn)度下顏色偏移、縮放比例
  • 獲取放大后的紋理坐標(biāo)的紋素、放大后的紋理顏色偏移后的紋素
  • 從放大的紋素、偏移的紋素獲取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;
    //放大后的紋理坐標(biāo)
    vec2 ScaleTextureCoords = vec2(0.5, 0.5) + (textureCoordVarying - vec2(0.5, 0.5)) / scale;
 
    //放大后的紋理紋素進(jìn)行顏色偏移 + offsetCoords
    vec4 maskR = texture2D(Texture, ScaleTextureCoords + offsetCoords);
   //放大后的紋理紋素進(jìn)行顏色偏移 - offsetCoords
    vec4 maskB = texture2D(Texture, ScaleTextureCoords - offsetCoords);
   // 放大后紋理坐標(biāo)的紋素
    vec4 mask = texture2D(Texture, ScaleTextureCoords);
   
    // 從3組顏色中取出RGBA顏色值,賦值gl_FragColor 
   // 也可以值取一個(gè)紋素偏移值和不發(fā)生偏移的紋素。方便觀察紋素偏移現(xiàn)象。
   //  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、閃白濾鏡

實(shí)現(xiàn)原理:添加白色圖層,白色圖層隨時(shí)間透明度進(jìn)行變化。

precision highp float;

varying lowp vec2 textureCoordVarying;
uniform sampler2D Texture;
uniform float Time;
const float PI = 3.1415926;
void main(){
   //時(shí)間周期
    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)));
    //紋理坐標(biāo)紋素
    vec4 mask = texture2D(Texture, textureCoordVarying);
    //顏色混合。白色遮照的透明度時(shí)間變化
    gl_FragColor = mask * (1.0 - amplitude) + whiteMask * amplitude;
}

5、毛刺濾鏡

實(shí)現(xiàn)原理:撕裂 + 微弱的顏色偏移。讓每一行像素隨機(jī)偏移-1~1的距離(相對紋理坐標(biāo)而言)。但是如果正畫面都偏移比較大的值,可能看不出原圖片的樣子。所以設(shè)定一個(gè)閥值,小于閥值的進(jìn)行偏移,大于的乘上一個(gè)縮小系數(shù)。最終絕大部分行都會(huì)進(jìn)行微小偏移,只有少量的行進(jìn)行較大偏移。

毛刺濾鏡

片元著色器

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的小數(shù)部分
    //返回 sin(n) * 43758.5453123
    return fract(sin(n) * 43758.5453123);
}
void main(){
    float maxJitter = 0.06;//最大抖動(dòng)
    float duration = 0.3;//時(shí)間周期(一次毛刺濾鏡的時(shí)長)
    float colorROffset = 0.01;//紅色顏色偏移
    float colorBOffset = -0.025;//綠色顏色偏移
    
    //將傳入的時(shí)間轉(zhuǎn)換成周期
    float time = mod(Time, duration * 2.0);
   //amplitude 振幅。引入PI是為了使用sin函數(shù)。將amplitude 限制在1.0 ~1.3之間,隨時(shí)間變化
    float amplitude = max(sin(time * (PI / duration)), 0.0);
    //像素隨機(jī)偏移范圍(-1,1)
    float jitter = rand(textureCoordVarying.y) * 2.0 - 1.0; // -1~1
   //判斷是否需要偏移,如果jitter范圍< 最大抖動(dòng) *振幅
    bool needOffset = abs(jitter) < maxJitter * amplitude;
    
   //獲取紋理坐標(biāo)x,根據(jù)needOffset 計(jì)算x的撕裂,yes,撕裂大,no撕裂小
    float textureX = textureCoordVarying.x + (needOffset ? jitter : (jitter * amplitude * 0.006));
  
    //獲取撕裂后的紋理坐標(biāo)
    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));
    //顏色主要撕裂,紅色和藍(lán)色部分,所以只調(diào)整紅色
    gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}

6、幻覺濾鏡

實(shí)現(xiàn)原理:殘影效果 + 顏色偏移
殘影效果:在移動(dòng)過程中,每經(jīng)過一段時(shí)間間隔,根據(jù)當(dāng)前的位置去創(chuàng)建一個(gè)新層,并且的不透明度隨時(shí)間逐漸減弱。在一個(gè)移動(dòng)周期內(nèi)??梢钥吹胶芏嗤该鞫炔煌膶盈B加在一起,從而形成殘影的效果,殘影,讓圖片時(shí)間做圓周運(yùn)動(dòng)。
顏色偏移:物體移動(dòng)的過程是藍(lán)色在前面,紅色在后面。搜一整個(gè)過程可以理解成:在移動(dòng)的過程中,每隔一段時(shí)間,遺失了一部分紅色通道的值在原來的位置。并且這部分紅色通道的值,隨著時(shí)間偏移,會(huì)逐漸恢復(fù)。

幻覺濾鏡

片元著色器

precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

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

//計(jì)算某時(shí)刻圖片的具體位置,每經(jīng)過一段時(shí)間,生成新的圖層
vec4 getMask(float time, vec2 textureCoords, float padding) {
   //圓周坐標(biāo)
    vec2 translation = vec2(sin(time * (PI * 2.0 / duration)),
                            cos(time * (PI * 2.0 / duration)));
    //紋理坐標(biāo) = 紋理坐標(biāo) + 圓周坐標(biāo) * 偏移量
    vec2 translationTextureCoords = textureCoords + padding * translation;

    //獲取新圖層的坐標(biāo)
    vec4 mask = texture2D(Texture, translationTextureCoords);
    
    return mask;
}
//計(jì)算某時(shí)刻創(chuàng)建的圖層、當(dāng)前時(shí)刻的透明度
float maskAlphaProgress(float currentTime, float hideTime, float startTime) {
    float time = mod(duration + currentTime - startTime, duration);
    return min(time, hideTime);
}

void main (void) {
   //獲取時(shí)間周期
    float time = mod(Time, duration);
   //放大倍數(shù)
    float scale = 1.2;
   //偏移量
    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;
   //時(shí)間間隔
    float timeGap = 0.2;
    //注意:只保留了紅色的透明的通道值?;糜X效果殘留紅色

    //新圖層 -- R色透明度
    float maxAlphaR = 0.5; // max R
    //新圖層 -- G色透明度
    float maxAlphaG = 0.05; // max G
    //新圖層 -- B色透明度
    float maxAlphaB = 0.05; // max B
    
    //獲取新的圖層坐標(biāo)
    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內(nèi)所獲取的運(yùn)動(dòng)后的紋理坐標(biāo)
        vec4 tmpMask = getMask(tmpTime, textureCoords, padding);
        
        //某時(shí)刻創(chuàng)建的層。在當(dāng)前時(shí)刻紅綠藍(lán)的透明度
        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;
     //累計(jì)每一層每個(gè)通道乘以透明度顏色通道
        resultMask += vec4(tmpMask.r * tmpAlphaR,
                           tmpMask.g * tmpAlphaG,
                           tmpMask.b * tmpAlphaB,
                           1.0);
        //透明度遞減
        alphaR -= tmpAlphaR;
        alphaG -= tmpAlphaG;
        alphaB -= tmpAlphaB;
    }

   //最終的顏色+=紅綠藍(lán) * 透明度
    resultMask += vec4(mask.r * alphaR, mask.g * alphaG, mask.b * alphaB, 1.0);
    gl_FragColor = resultMask;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容