美文网首页
OpenGL ES 分屏滤镜

OpenGL ES 分屏滤镜

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

    想要绘制滤镜首先我们需要清楚如何绘制纹理,如果不了解的可以参考 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中修改的,只需要处理纹理坐标即可。

    • 一分屏(正常绘制).fsh代码:
    precision highp float;
    varying vec2 textureCoords;
    uniform sampler2D texture;
    
    void main()
    {
        vec4 mask = texture2D(texture, textureCoords);
        gl_FragColor = vec4(mask.rgb, 1.0);
    }
    

    正常效果:


    • 二分屏.fsh代码:
    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

    二分屏效果:


    • 三分屏.fsh代码:
    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

    三分屏效果:
    • 四分屏.fsh代码:
    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
    四分屏效果:

    • 六分屏.fsh代码:
    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

    六分屏效果:
    • 九分屏.fsh代码:
    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

    九分屏效果:

    相关文章

      网友评论

          本文标题:OpenGL ES 分屏滤镜

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