OpenGL ES 动态效果滤镜

2020-08-17  本文已影响0人  Maji1

这篇文章介绍一下带有动态效果的滤镜,大家可以先了解下 分屏滤镜马赛克滤镜

动态效果的滤镜其实就是根据当前时间的变化来进行动态的绘制,所以我们就需要添加一个计时器进行不断的绘制。控制器添加计时器代码:

// 开始一个滤镜动画
- (void)startFilerAnimation {
    //1.判断displayLink 是否为空
    //CADisplayLink 定时器
    if (self.displayLink) {
        [self.displayLink invalidate];
        self.displayLink = nil;
    }
    //2. 设置displayLink 的方法
    self.startTimeInterval = 0;
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render)];
    
    //3.将displayLink 添加到runloop 运行循环
    [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop]
                           forMode:NSRunLoopCommonModes];
}

添加了计时器,绘制代码需要将当前时间传给顶点着色器或者片元着色器,以便着色器程序利用当前时间动态的绘制滤镜,修改代码:

- (void)render {
       //DisplayLink 的当前时间撮
    if (self.startTimeInterval == 0) {
        self.startTimeInterval = self.displayLink.timestamp;
    }
    //使用program
    glUseProgram(self.programID);
    //绑定buffer
    glBindBuffer(GL_ARRAY_BUFFER, self.vertexBufferID);
    
    // 传入时间
    CGFloat currentTime = self.displayLink.timestamp - self.startTimeInterval;
    GLuint time = glGetUniformLocation(self.programID, "time");
    glUniform1f(time, currentTime);
    
    // 清除画布
    glClear(GL_COLOR_BUFFER_BIT);
    glClearColor(1, 1, 1, 1);
    
    // 重绘
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    //渲染到屏幕上
    [self.currentContext presentRenderbuffer:GL_RENDERBUFFER];
}

下面我们来看下不同的动态效果如何如何修改着色器代码。

一、缩放滤镜

缩放滤镜我们这里修改的是顶点着程序的代码,只需要将顶点坐标根据时间变化来进行放大缩小。看下Scale.vsh代码:

attribute vec4 position;
attribute vec2 texCoordinate;
varying vec2 textureCoords;
uniform float time;

const float PI = 3.1415926;

void main()
{
    float duration = 0.6;
    float maxAmplitude = 0.3;
    float timeProgress = mod(time, duration);
    float currentAmplitude = 1.0 + maxAmplitude * abs(sin(timeProgress * (PI / duration)));
    
    gl_Position = vec4(position.x * currentAmplitude, position.y * currentAmplitude, position.zw);
    
    textureCoords = texCoordinate;
}

二、灵魂出窍效果

这种效果实际上是对两个层的叠加,并且上面的那层随着时间的推移,会逐渐放⼤大且不透明度逐渐降低。这里也⽤到了放⼤的效果,我们需要对纹理坐标进行处理。看SoulOut.fsh代码:

precision highp float;
varying vec2 textureCoords;
uniform sampler2D texture;

uniform float time;

void main()
{
    float duration = 0.7;
    float maxAlpha = 0.4;
    float maxScale = 1.8;
    
    float timeProgress = mod(time, duration) / duration;
    float currentAlpha = timeProgress * (1.0 - maxAlpha);
    float currentScale = 1.0 + (maxScale -  1.0) * timeProgress;
    
    float weakX = 0.5 + (textureCoords.x - 0.5) / currentScale;
    float weakY = 0.5 + (textureCoords.y - 0.5) / currentScale;
    vec2 weakTextureCoords = vec2(weakX, weakY);
    vec4 weakMask = texture2D(texture, weakTextureCoords);
    vec4 mask = texture2D(texture, textureCoords);
    gl_FragColor = mask * (1.0 - currentAlpha) + weakMask * currentAlpha;
}

三、抖动

抖动效果是对纹理进行轻微的放大缩小,然后进行纹素偏移,也是对纹理进行处理,Shake.fsh代码:

precision highp float;
varying vec2 textureCoords;
uniform sampler2D texture;

uniform float time;

void main()
{
    float duration = 0.7;
    float maxScale = 1.1;
    float textOffset = 0.02;
    
    float timeProgress = mod(time, duration) / duration;
    vec2 offsetCoorsd = vec2(textOffset, textOffset) * timeProgress;
    float currentScale = 1.0 + (maxScale -  1.0) * timeProgress;
    
    float weakX = 0.5 + (textureCoords.x - 0.5) / currentScale;
    float weakY = 0.5 + (textureCoords.y - 0.5) / currentScale;
    vec2 weakTextureCoords = vec2(weakX, weakY);
    
    vec4 maskR = texture2D(texture, weakTextureCoords + offsetCoorsd);
    vec4 maskB = texture2D(texture, weakTextureCoords - offsetCoorsd);
    vec4 mask = texture2D(texture, textureCoords);
    gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}

三、闪白

该效果是叠加白色图层 ,并且白色图层的透明度随着时间变化,需要对纹理进行操作。ShineWhite.fsh代码:

precision highp float;
varying vec2 textureCoords;
uniform sampler2D texture;

uniform float time;

const float PI = 3.1415926;

void main()
{
    float duration = 0.7;
    
    float timeProgress = mod(time, duration);
    vec4 whiteMask = vec4(1.0, 1.0, 1.0, 1.0);
    float currentAlpha = abs(sin((PI/duration) * timeProgress));

    vec4 mask = texture2D(texture, textureCoords);
    gl_FragColor = mask * (1.0 - currentAlpha) + whiteMask * currentAlpha;
}

四、毛刺效果

我们先来介绍下毛刺效果的具体思路:
让每一行纹素随机偏移 [-1, 1] 的距离。设想一下如果整个画面都偏移比较大的值,我们可能就看不出原图像样子。所以我们的逻辑是,设定一个阈值,⼩于这个阈值才进行偏移,超过这个阈值则乘上一个缩小系数。则最终呈现的效果是:绝大部分的行都会进行微⼩的偏移,只有少量的行会进行较大偏移。

Glitch.fsh代码:

precision highp float;
varying vec2 textureCoords;
uniform sampler2D texture;

uniform float time;
const float PI = 3.1415926;

float rand(float n) {
    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 timeProgress = mod(time, duration * 2.0);
    float amplitude = max(sin(timeProgress * (PI / duration)), 0.0);//sin([0, 2PI]):

    float jitter = rand(textureCoords.y) * 2.0 - 1.0; // -1~1
    bool needOffset = abs(jitter) < maxJitter * amplitude;
    
    float textureXOffset = 0.0;
    if (needOffset == true) {
        textureXOffset = jitter;
    } else {
        textureXOffset = jitter * amplitude * 0.006;
    }
    float textureX = textureCoords.x + textureXOffset;
    vec2 textCoords = vec2(textureX, textureCoords.y);
    
    
    vec4 mask = texture2D(texture, textCoords);
    vec4 maskR = texture2D(texture, textCoords + vec2(colorROffset * amplitude, 0.0));
    vec4 maskB = texture2D(texture, textCoords + vec2(colorBOffset * amplitude, 0.0));
    
    gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}
上一篇 下一篇

猜你喜欢

热点阅读