iOS开发之OpenGL ES(五) —— 分屏滤镜详解

前言

这篇文章是为了让大家了解在小视频或美图等软件中,如何利用OpenGL ES实现分屏滤镜,并理解实现的原理。

二分屏滤镜实现

首先看一下下图中的左边原图的纹理坐标。在纹理坐标系中,原点是在左下角。有关纹理坐标系可以参考纹理坐标解析

原图

下图是我们需要实现的效果:


二分屏

实现思路是这样的: 判断纹理的Y坐标,在 (0.0,0.5)和(0.5,1.0)坐标范围内填充为(0.25, 0.75)的纹理坐标区间,如下图所示,其实我们在二分屏中使用的是(0.25,0.75)这个区间内的纹理坐标。

为什么要使用(0.25,0.75)这个区间的纹理呢?
我这里是按一般情况来考虑的,也可以使用(0.15,0.65)这种的范围,根据自己的需求定吧,如果要使用(0.15,0.65),在计算的时候(0,0.5)区间内y坐标就要加上0.15,(0.5,1.0)区间内y坐标就要减去0.35。

GLSL实现代码如下,我这里加了注释,但是运行的时候最好删除中文注释,不然有可能会报错。

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

void main(void){
    vec2 uv = TextureCoordsVarying.xy;
    //判断坐标范围
    if(uv.y >= 0.0 && uv.y <= 0.5){
        //(0.0,0.5)->(0.5, 0.75)
        uv.y = uv.y + 0.25;
    }else{
        // (0.5,1.0)->(0.5, 0.75)
        uv.y = uv.y - 0.25;
    }
    vec4 mask = texture2D(Texture,uv);
    gl_FragColor = vec4(mask.rgb,1.0);
}

三分屏滤镜实现

需要实现的效果如下


实现思路:
和上面的二分屏类似,我们要填充的y坐标的纹理区间是(1.0/3.0,2.0/3.0),所以在(0,1.0/3.0)区间内的纹理坐标要加上1.0/3.0,在(1.0/3.0,2.0/3.0)区间内的纹理坐标不需要修改,在(2.0/3.0,1)区间内的纹理坐标要减去1.0/3.0.

GLSL代码如下:

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

void main(void){
    vec2 uv = TextureCoordsVarying.xy;
    if(uv.y >= 0.0 && uv.y <= 1.0/3.0){
        uv.y = uv.y + 1.0 / 3.0;
    }else if(uv.y >= 2.0 / 3.0){
        uv.y = uv.y - 1.0/ 3.0 ;
    }
    vec4 mask = texture2D(Texture,uv);
    gl_FragColor = vec4(mask.rgb,1.0);
}

四分屏滤镜实现

需要实现的效果如下:


实现思路: 可以看到我们缩放了图片,图片的宽度和高度都变成了原来的一半。那么怎么缩放呢?
先从Y坐标来看,分成了两个区间(0,0.5)和(0.5,1),要填充的纹理区间是(0,1),所以当uv.y <= 0.5 时,uv.y * 2 就表示区间(0,1),uv.y >= 0.5时, (uv.y - 0.5) * 2 表示区间(0,1)
同理,X坐标要填充的纹理区间也是(0,1),计算方式和计算y坐标一样。

GLSL代码如下:

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

void main(void){
    vec2 uv = TextureCoordsVarying.xy;
    if(uv.y <= 0.5){
        uv.y = uv.y * 2.0;
    }else{
        uv.y = (uv.y - 0.5) * 2.0 ;
    }
    if(uv.x <= 0.5){
        uv.x = uv.x * 2.0;
    }else{
        uv.x = (uv.x - 0.5) * 2.0 ;
    }
    
    gl_FragColor = texture2D(Texture,uv);
}

九分屏滤镜实现

需要实现的效果如下:


实现思路: 其实这个和上面的四分屏实现思路是一样的,只不过这里是把图片缩小了1/3。
同理,从Y坐标来看,分为三个区间,(0,3/1 ), (3/1, 2/3), (3/2 , 1)

  • uv.y <= 1.0/3.0时, uv.y = uv.y * 3
  • uv.y 在1.0/3.0到2.0/3.0之间时, uv.y = (uv.y - 1.0/3.0) * 3
  • uv.y >= 2.0/3.0时, uv.y = (uv.y - 2.0/3.0) * 3

GLSL代码如下:

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

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

总结

以上就是使用OpenGL ES实现的几种常见的分屏滤镜效果,理解后可自行实现不同的分屏效果,比如六分屏,横向三分屏等。

Demo地址: 分屏滤镜处理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。