美文网首页
OpenGL ES - 滤镜 缩放+出窍+抖动+闪白+毛刺+幻觉

OpenGL ES - 滤镜 缩放+出窍+抖动+闪白+毛刺+幻觉

作者: MrDemon_ | 来源:发表于2020-08-17 23:12 被阅读0次

    一、添加时间线

    - (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];
    }
    

    二、实现动态滤镜

    与静态的马赛克滤镜相同的,首先得能通过GLSL方式正常显示一张纹理图片。对应的顶点着色器和片元着色器的代码如下:

    a.顶点着色器

    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.缩放滤镜

    image

    实现原理:通过修改顶点坐标和纹理坐标的对应关系来实现。

    片元着色器实现:

    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.灵魂出窍滤镜

    image

    实现原理:通过两个纹理图层的叠加,并且上⾯的图层随着时间的推移,会逐渐放⼤且不透明度逐渐降低来实现。

    片元着色器实现:

    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.抖动滤镜

    image

    实现原理:通过对像素点颜⾊进行偏移,加上微弱的放⼤效果来实现。

    片元着色器实现:

    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.闪白滤镜

    image

    实现原理:通过添加⽩⾊图层 ,⽩⾊图层的透明度随着时间变化来实现。

    片元着色器实现:

    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.毛刺滤镜

    image

    实现原理:通过修改纹理坐标对纹理进行撕裂,加上微弱的像素点颜⾊偏移来实现。我们让每⼀⾏像素随机偏移 -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.幻觉滤镜

    image

    实现原理:通过残影和颜⾊偏移的叠加来实现。在移动的过程中,每经过⼀段时间间隔,根据当前的位置去创建⼀个新层,并且新层的不透明度随着时间逐渐减弱。于是在⼀个移动周期内,可以看到很多透明度不同的层叠加在⼀起,从⽽形成残影的效果。同时在移动的过程中,每间隔⼀段时间,遗失了⼀部分红⾊通道的值在原来的位置,并且这部分红⾊通道的值,随着时间偏移,会逐渐恢复。

    片元着色器实现:

    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;
    }
    

    相关文章

      网友评论

          本文标题:OpenGL ES - 滤镜 缩放+出窍+抖动+闪白+毛刺+幻觉

          本文链接:https://www.haomeiwen.com/subject/nfcfjktx.html