OpenGL ES 分屏滤镜

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

想要绘制滤镜首先我们需要清楚如何绘制纹理,如果不了解的可以参考 OpenGL ES 纹理绘制
这篇文章中绘制的图片是倒立的,我们需要将图片反转过来。方法很多,这里就简单介绍一种常用的方法,反转坐标系:

CGContextRef contextRef = CGBitmapContextCreate(imageData, width, height, 8, width * 4, colorRGBSpaceRef, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGRect rect = CGRectMake(0, 0, width, height);

CGContextTranslateCTM(contextRef, rect.origin.x, rect.origin.y);
CGContextTranslateCTM(contextRef, 0, rect.size.height);
CGContextScaleCTM(contextRef, 1.0, -1.0);
CGContextTranslateCTM(contextRef, -rect.origin.x, -rect.origin.y);

0、先将图片contextRef先移动到它的位置坐标rect.origin.xrect.origin.y
1、将图片contextRef沿Y轴方向移动图片的高度的距离height
2、沿Y轴缩放-1.0,这时图片已经翻转过来了,只是位置不对。
3、将图片contextRef恢复到原来的位置坐标rect.origin.xrect.origin.y

下面我们开始讲解下滤镜的处理。

一、分屏滤镜

我们这里做了一分屏、二分屏、三分屏、四分屏、六分屏、九分屏的效果,当然一分屏其实就是正常的绘制。
这里分屏效果的代码全部都是在片元着色程序.fsh中修改的,只需要处理纹理坐标即可。

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

void main()
{
    vec4 mask = texture2D(texture, textureCoords);
    gl_FragColor = vec4(mask.rgb, 1.0);
}

正常效果:


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

void main()
{
    vec2 uv = textureCoords.xy;
    if (uv.y <= 0.5 && uv.y >= 0.0) {
        uv.y += 0.25;
    } else {
        uv.y -= 0.25;
    }
    gl_FragColor = texture2D(texture, uv);
}

这里将纹理坐标在Y方向上分成了两个区域:[0.0, 0.5][0.5, 1.0]

这里我们要求尽可能取图片中间位置的纹理。所以为了将屏幕铺满,就需要取在Y方向上[0.25, 0.75]之间的位置。

所以,在[0.0, 0.5] 区域时,Y方向上需要加上0.25。在[0.5, 1.0] 区域时,Y方向上需要减去0.25

二分屏效果:


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

void main()
{
    vec2 uv = textureCoords.xy;
    float detal = 1.0/3.0;
    if (uv.y <= detal && uv.y >= 0.0) {
        uv.y += detal;
    } else if (uv.y > detal * 2.0) {
        uv.y -= detal;
    }
    gl_FragColor = texture2D(texture, uv);
}

三分屏将纹理坐标在Y方向上分成了三个区域:[0.0, 1.0/3.0][1.0/3.0, 2.0/3.0][2.0/3.0, 1.0]

这里同样要求尽可能取图片中间位置的纹理。所以为了将屏幕铺满,就需要取在Y方向上[1.0/3.0, 2.0/3.0]之间的位置。

所以,在[0.0, 1.0/3.0] 区域时,Y方向上需要加上1.0/3.0。在[1.0/3.0, 2.0/3.0]正好对应上中间的纹理,所以不用修改。在[2.0/3.0, 1.0] 区域时,Y方向上需要减去1.0/3.0

三分屏效果:
precision highp float;
varying vec2 textureCoords;
uniform sampler2D texture;

void main()
{
    vec2 uv = textureCoords.xy;
    float detal = 0.5;
    if (uv.x <= detal && uv.x >= 0.0) {
        uv.x *= 2.0;
    } else if (uv.x > detal) {
        uv.x = (uv.x - detal) * 2.0;
    }
    
    if (uv.y <= detal && uv.y >= 0.0) {
        uv.y *= 2.0;
    } else if (uv.y > detal) {
        uv.y = (uv.y - detal) * 2.0;
    }
    gl_FragColor = texture2D(texture, uv);
}

四分屏需要将纹理坐标分成四个区域:
Y方向[0.0, 0.5][0.5, 1.0]
X方向[0.0, 0.5][0.5, 1.0]
两两结合构成四个区域。

这里要求每个区域都展示完整的图片。

所以无论X、Y,范围在[0.0, 0.5]时坐标都需要乘以2.0
范围在[0.5, 1.0] 时,坐标都需要减去先0.5再乘以2.0
四分屏效果:

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

void main()
{
    vec2 uv = textureCoords.xy;
    float detal = 1.0/3.0;
    if (uv.x <= detal && uv.x >= 0.0) {
        uv.x += detal;
    } else if (uv.x >= detal * 2.0) {
        uv.x -= detal;
    }

    if (uv.y <= 0.5 && uv.y >= 0.0) {
        uv.y += 0.25;
    } else {
        uv.y -= 0.25;
    }
    gl_FragColor = texture2D(texture, uv);
}

六分屏将纹理坐标分成六个区域:
X方向[0.0, 1.0/3.0][1.0/3.0, 2.0/3.0][2.0/3.0, 1.0]
Y方向[0.0, 0.5][0.5, 1.0]
两两结合构成六个区域。

这里同样要求尽可能取图片中间位置的纹理。所以为了将屏幕铺满,就需要取在X方向上[1.0/3.0, 2.0/3.0]之间的位置。在Y方向上取[0.25, 0.75]之间的位置。

所以
X方向上:[0.0, 1.0/3.0] 区域时,X方向上需要加上1.0/3.0。在[1.0/3.0, 2.0/3.0]正好对应上中间的纹理,所以不用修改。在[2.0/3.0, 1.0] 区域时,X方向上需要减去1.0/3.0
Y方向上:[0.0, 0.5] 区域时,Y方向上需要加上0.25。在[0.5, 1.0] 区域时,Y方向上需要减去0.25

六分屏效果:
precision highp float;
varying vec2 textureCoords;
uniform sampler2D texture;

void main()
{
    vec2 uv = textureCoords.xy;
    float detal = 1.0/3.0;
    if (uv.x <= detal && uv.x >= 0.0) {
        uv.x *= 3.0;
    } else if (uv.x > detal && uv.x < detal * 2.0) {
        uv.x = (uv.x - detal) * 3.0;
    } else {
        uv.x = (uv.x - detal * 2.0) * 3.0;
    }
    
    if (uv.y <= detal && uv.y >= 0.0) {
        uv.y *= 3.0;
    } else if (uv.y > detal && uv.y < detal * 2.0) {
        uv.y = (uv.y - detal) * 3.0;
    } else {
        uv.y = (uv.y - detal * 2.0) * 3.0;
    }
    gl_FragColor = texture2D(texture, uv);
}

九分屏需要将纹理坐标分成九个区域:
Y方向[0.0, 1.0/3.0][1.0/3.0, 2.0/3.0][2.0/3.0, 1.0]
X方向[0.0, 1.0/3.0][1.0/3.0, 2.0/3.0][2.0/3.0, 1.0]
两两结合构成九个区域。

这里要求每个区域都展示完整的图片。

所以无论X、Y
范围在[0.0, 1.0/3.0]时坐标需要乘以3.0
范围在[1.0/3.0, 2.0/3.0]时,坐标需要先减去1.0/3.0再乘以3.0
范围在[2.0/3.0, 1.0]时,坐标需要先减去2.0/3.0再乘以3.0

九分屏效果:
上一篇下一篇

猜你喜欢

热点阅读