OpenGL ES 動效濾鏡實現

注:本文旨在記錄筆者的學習過程,僅表明筆者我的的理解,若是有表述不許確的地方,歡迎各位指正!由於涉及到的概念來源自網絡,因此若有侵權,也望告知!markdown

前言

本文主要在GLSL顯示普通圖⽚的基礎上實現動態濾鏡效果。網絡

正文

1、添加時間線

動效濾鏡與上一篇文章提到靜態的馬賽克濾鏡的不一樣之處,在於咱們再實現着色器代碼的時候添加了一個time參數,time參數是經過CADisplayLink定時器觸發輸入的。ide

- (void)startFilerAnimation {
    //1.CADisplayLink 定時器
    if (self.displayLink) {
        [self.displayLink invalidate];
        self.displayLink = nil;
    }
    //2.設置displayLink 的方法
    self.startTimeInterval = 0;
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(timeAction)];
    //3.將displayLink 添加到runloop 運行循環
    [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}

- (void)timeAction {
    //DisplayLink 的當前時間撮
    if (self.startTimeInterval == 0) {
        self.startTimeInterval = self.displayLink.timestamp;
    }
    //使用program
    glUseProgram(self.program);
    //綁定buffer
    glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer);

    // 傳入時間
    CGFloat currentTime = self.displayLink.timestamp - self.startTimeInterval;
    GLuint time = glGetUniformLocation(self.program, "Time");
    glUniform1f(time, currentTime);

    // 清除畫布
    glClear(GL_COLOR_BUFFER_BIT);
    glClearColor(1, 1, 1, 1);

    // 重繪
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    //渲染到屏幕上
    [self.context presentRenderbuffer:GL_RENDERBUFFER];
}
複製代碼

2、實現動態濾鏡

與靜態的馬賽克濾鏡相同的,首先得能經過GLSL方式正常顯示一張紋理圖片。對應的頂點着色器和片元着色器的代碼以下:oop

a.頂點着色器post

attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;

void main (void) {
    gl_Position = Position;
    TextureCoordsVarying = TextureCoords;
}
複製代碼
複製代碼

b.片元着色器學習

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

void main (void) {
    vec4 mask = texture2D(Texture, TextureCoordsVarying);
    gl_FragColor = vec4(mask.rgb, 1.0);
}
複製代碼

1.縮放濾鏡

實現原理經過修改頂點座標和紋理座標的對應關係來實現。ui

片元着色器實現: spa

precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;

void main (void) {
    float duration = 0.6;
    float maxAmplitude = 0.3;

    float time = mod(Time, duration);
    float amplitude = 1.0 + maxAmplitude * abs(sin(time * (PI / duration)));

    float weakX = 0.5 + (TextureCoordsVarying.x - 0.5) / amplitude;
    float weakY = 0.5 + (TextureCoordsVarying.y - 0.5) / amplitude;
    vec2 weakTextureCoords = vec2(weakX, weakY);

    vec4 mask = texture2D(Texture, weakTextureCoords);
    gl_FragColor = vec4(mask.rgb, 1.0);
}
複製代碼

2.靈魂出竅濾鏡

實現原理:經過兩個紋理圖層的疊加,而且上⾯的圖層隨着時間的推移,會逐漸放⼤且不透明度逐漸下降來實現。3d

片元着色器實現:code

precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

void main (void) {
    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;

    float weakX = 0.5 + (TextureCoordsVarying.x - 0.5) / scale;
    float weakY = 0.5 + (TextureCoordsVarying.y - 0.5) / scale;
    vec2 weakTextureCoords = vec2(weakX, weakY);

    vec4 weakMask = texture2D(Texture, weakTextureCoords);

    vec4 mask = texture2D(Texture, TextureCoordsVarying);

    gl_FragColor = mask * (1.0 - alpha) + weakMask * alpha;
}
複製代碼

3.抖動濾鏡

實現原理:經過對像素點顏⾊進行偏移,加上微弱的放⼤效果來實現

片元着色器實現:

precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

void main (void) {
    float duration = 0.7;
    float maxScale = 1.1;
    float offset = 0.02;

    float progress = mod(Time, duration) / duration; // 0~1
    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);
    vec4 mask = texture2D(Texture, ScaleTextureCoords);

    gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}
複製代碼

4.閃白濾鏡

實現原理:經過添加⽩⾊圖層 ,⽩⾊圖層的透明度隨着時間變化來實現。

片元着色器實現:

precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;

void main (void) {
    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, TextureCoordsVarying);

    gl_FragColor = mask * (1.0 - amplitude) + whiteMask * amplitude;
}
複製代碼

5.毛刺濾鏡

實現原理:經過修改紋理座標對紋理進行撕裂,加上微弱的像素點顏⾊偏移來實現。咱們讓每⼀⾏像素隨機偏移 -1 ~ 1 的距離(這⾥的 -1 ~ 1 是對於紋理座標來講的),可是若是整個畫⾯都偏移⽐較⼤的值,那咱們可能都看不出原來圖像的樣⼦。因此咱們的邏輯是,設定⼀個閾值,⼩於這個閾值才進⾏偏移,超過這個閾值則乘上⼀個縮⼩係數。

片元着色器實現:

precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;

float rand(float n) {
    return fract(sin(n) * 43758.5453123);
}

void main (void) {
    float maxJitter = 0.06;
    float duration = 0.3;
    float colorROffset = 0.01;
    float colorBOffset = -0.025;

    float time = mod(Time, duration * 2.0);
    float amplitude = max(sin(time * (PI / duration)), 0.0);

    float jitter = rand(TextureCoordsVarying.y) * 2.0 - 1.0; // -1~1
    bool needOffset = abs(jitter) < maxJitter * amplitude;

    float textureX = TextureCoordsVarying.x + (needOffset ? jitter : (jitter * amplitude * 0.006));
    vec2 textureCoords = vec2(textureX, TextureCoordsVarying.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;

    float maxAlphaR = 0.5; // max R
    float maxAlphaG = 0.05; // 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);

    for (float f = 0.0; f < duration; f += timeGap) {
        float tmpTime = f;
        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;
}
複製代碼
相關文章
相關標籤/搜索