OpenGL ES 分屏滤镜效果

1,224 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

之前的文章中,我们使用 GLSL 自定义着色器 来显示了一张图片,今天我们来实现一下 二分屏、三分屏、四分屏、六分屏和九分屏这些 简单的滤镜效果。

之前Demo的调整

之前我们基于 SMView 来做的默认着色器程序的加载, 现在我们封装出来一个方法:

/// 加载着色器程序
/// - **Parameter** shaderName: 着色器文件名称
- (**void**)loadShaderWithName:(NSString *)shaderName;

方法的实现就是将,我们之前加载显示图片的六步拿过来(将开始绘制方法中读取顶点着色程序、 片源着色程序的部分改为外部传参指定文件即可):

- (**void**)loadShaderWithName:(NSString *)shaderName {

    //1.设置图层
    [**self** setupLayer];

    //2.设置图形上下文
    [**self** setupContext];

    //3.清空缓存区
    [**self** deleteRenderAndFrameBuffer];

    //4.设置RenderBuffer
    [**self** setupRenderBuffer];

    //5.设置FrameBuffer
    [**self** setupFrameBuffer];
    
    //6.开始绘制
    [**self** renderLayerWithName:shaderName];
}

好的,准备工作做好,我们就开始先分析下二分屏的效果如何做出来。

二分屏

我们要实现将红框中的内容展示在上下两个黑框中;

image.png

  • 二分屏滤镜的显示内容我们要做到屏幕分为上下两个区域,也就是上图中的黑色框框分开的内容。
  • 黑色框框显示的内容是图片红色区域框选出来的图片内容

上半个屏幕 在显示纹理坐标时,x坐标是不变的,y坐标会增加0.25; 下班个屏幕 在显示纹理坐标时,x坐标童谣不变,y坐标则是减小0.25; 所以:

我们的片元着色器修改为:

precision highp float;
varying highp vec2 varyTextCoord;
uniform sampler2D colorMap;

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

三分屏

原理上和二分屏类似的效果 只不过是 按照 三分之一来 分配屏幕;

image.png

precision highp float;
varying highp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main()
{
    
    vec2 zb = varyTextCoord.xy;
    
    float fp = 1.0 / 3.0;
    
    if ( zb.y >= 0.0 && zb.y < fp ) {
        
        zb.y = zb.y + fp;
    }else if ( zb.y > 2.0/3.0 && zb.y <= 1.0 ) {
        
        zb.y = zb.y - fp;
    }
    
    gl_FragColor = texture2D(colorMap, zb);
}

四分屏

四分屏则会同时修改纹理坐标的x值和y值

image.png

  • 首先分析x值,从0 - 0.5 要映射为 0 - 1.0 才可以把整个图片原来的内容展示全,所以 需要 将 x * 2.0;
  • 第二, 从0.5 - 1.0 ,同样要映射为 0 - 1.0 , 所以 需要 进行 运算 (x - 0.5)* 2;
  • y值的变化 同 x值的变化;

所以片元着色器的代码为:


precision highp float;
varying highp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main()
{
    
    vec2 zb = varyTextCoord.xy;
    
    
    if ( zb.x >= 0.0 && zb.x < 0.5 ) {
        
        zb.x = zb.x * 2.0;
    }else if ( zb.x >= 0.5 && zb.x <= 1.0 ) {
        
        zb.x = (zb.x - 0.5) * 2.0;
    }
    
    if ( zb.y >= 0.0 && zb.y < 0.5 ) {
        
        zb.y = zb.y * 2.0;
    }else if ( zb.y >= 0.5 && zb.y <= 1.0 ) {
        
        zb.y = (zb.y - 0.5) * 2.0;
    }
    
    gl_FragColor = texture2D(colorMap, zb);
}

六分屏

六分屏我们要实现 将 红框中的内容,展示在 六个区域中;

通过观察,可以发现:

  • x坐标 在 1.0/3.0 - 2.0/3.0 之间是不需要做变化的;
  • 小于1.0/3.0 是 纹理坐标+1.0/3.0;
  • 大于2.0/3.0时,x坐标 - 1.0/3.0;
  • y坐标,在小于0.5时, y坐标+0.25;
  • 大于0.5时,y坐标 -0.25;

image.png

所以片元着色器的代码如下:

precision highp float;
varying highp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main()
{
    
    vec2 zb = varyTextCoord.xy;
    
    
    if ( zb.x >= 0.0 && zb.x < 1.0/3.0 ) {
        
        zb.x = zb.x + 1.0/ 3.0;
    }else if ( zb.x >= 1.0/3.0 && zb.x <= 2.0/3.0 ) {
        
        
    }else if ( zb.x >= 2.0/3.0 && zb.x <= 1.0 ) {
        zb.x = zb.x - 1.0/3.0;
    }
    
    if ( zb.y >= 0.0 && zb.y < 0.5 ) {
        
        zb.y = zb.y + 0.25;
    }else if ( zb.y >= 0.5 && zb.y <= 1.0 ) {
        
        zb.y = zb.y - 0.25;
    }
    
    gl_FragColor = texture2D(colorMap, zb);
}

九分屏

有了六分屏和四分屏的经验,我们的九分屏九比较简单了;先看下九分屏要实现的效果吧:

image.png

x 坐标和 y 坐标 的变化 都是要分 1。0/3.0 和 2.0/3.0 分割的三部分。 偏远着色器的代码为:


precision highp float;
varying highp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main()
{
    
    vec2 zb = varyTextCoord.xy;
    
    
    if ( zb.x >= 0.0 && zb.x < 1.0/3.0 ) {
        
        zb.x = zb.x * 3.0;
    }else if ( zb.x >= 1.0/3.0 && zb.x <= 2.0/3.0 ) {
        
        zb.x = (zb.x - 1.0/3.0) * 3.0;
    }else if ( zb.x >= 2.0/3.0 && zb.x <= 1.0 ) {
        zb.x = (zb.x - 2.0/3.0) * 3.0;
    }
    
    if ( zb.y >= 0.0 && zb.y < 1.0/3.0 ) {
        
        zb.y = zb.y * 3.0;
    }else if ( zb.y >= 1.0/3.0 && zb.y <= 2.0/3.0 ) {
        
        zb.y = (zb.y - 1.0/3.0) * 3.0;
    }else if ( zb.y >= 2.0/3.0 && zb.y <= 1.0 ) {
        zb.y = (zb.y - 2.0/3.0) * 3.0;
    }
    
    gl_FragColor = texture2D(colorMap, zb);
}

最后,我们看下整体的效果吧

OpenGL 滤镜.gif