iOS视觉(十四) -- 分屏滤镜

2,642 阅读3分钟

一、滤镜原理

在一些小视频的app上, 经常会看到在进行相机捕捉的时候为当前画面添加了滤镜, 会让相机拍摄到的画面变的更有趣味性.

那么滤镜原理是如何实现的呢?

在前些文章中, 我们实现了用GLSL加载一张图片. 在自定义的片元着色器中是这样的:


precision highp float;//精度
varying lowp vec2 varyTextCoord;//纹理坐标
uniform sampler2D colorMap;//纹理数据

void main() {
    vec4 texture = texture2D(colorMap, varyTextCoord);//纹素
    gl_FragColor = texture;
}

将纹理数据与纹理坐标生成纹素, 再渲染到屏幕上. 如果此时对纹素进行一个干预的话,就会得到不一样的效果. 例如, 我需要把整个图片的红色通道降低一些, 那么我们在片元着色器纹素的上面就可以做一下手脚:

   	vec4 texture = texture2D(colorMap, varyTextCoord);
    texture.r *= 0.5;
    gl_FragColor = texture;

这样就对整个图片对红色通道数据进行了减半,得到的效果也会变的不一样.

我们都知道相机的画面原理实际上就是通过摄像头不断的捕捉当前画面的图像数据, 所以通过GLSL来对相机捕获到对每一帧图像数据进行一个干预处理, 得到不一的画面, 这就是经常看到的滤镜.

二、分屏滤镜的处理

在一些app上有一些滤镜会将当前的画面分成相同的两部分显示出来:

仔细琢磨一下原理, 其实会发现实现这个滤镜非常简单, 就是只显示某一部分的纹素. 当像素点的位置不在需要显示的位置的时候. 就把这个像素点的位置向下偏移一段距离

蓝色部分上我们需要分屏显示的部分, 绿色为我们需要进行处理的部分.

  1. 当像素点在上面绿色部分的时候, 由于像素点的位置不在需要显示的范围里, 所以上面部分的像素点我们调用的纹理数据是需要向下移动0.25
  2. 此时蓝色的上半部分与最上方的绿色部分一致, 所以蓝色上半部分读取的纹理数据也需要向下移动0.25
  3. 当像素点在下面绿色部分的时候, 由于像素点的位置不在需要显示的范围里, 所以下面部分的像素点我们调用的纹理数据是需要向上移动0.25
  4. 此时蓝色的下半部分与最下方的绿色部分一致, 所以蓝色下半部分读取的纹理数据也需要向上移动0.25

综合所述: 当像素点在00.5范围的时候, 我们需要把y坐标全部下移0.25, 当像素点在0.51范围的时候,我们需要把y坐标全部上移0.25.

三、代码实现

precision highp float;//精度
varying lowp vec2 varyTextCoord;//纹理坐标
uniform sampler2D colorMap;//纹理数据

void main() {

    vec2 uv = varyTextCoord.xy;//获取纹理坐标的xy
    float y;//新的y坐标
    if (uv.y >= 0.0 && uv.y <= 0.5) {
        y = uv.y + 0.25;
    } else {
        y = uv.y - 0.25;
    }
    gl_FragColor = texture2D(colorMap, vec2(uv.x, y));//生成纹素后渲染
}

四、总结

其他还有很相似的滤镜, 例如: 三分屏、四分屏、九分屏等. 知道原理之后其实就是需要对x y坐标进行一个重新的计算. 使纹理坐标对应的纹理数据是仅仅需要显示的那一部分. 由此可以想想一些马赛克处理方式, 也就是将每一个像素点以及它的四周一定范围内进行一个颜色模糊处理. 一些磨皮的滤镜也是将当前颜色的亮度进行一个提高. 这些将在后续继续学习.