前言

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

二分屏滤镜实现

首先看一下下图中的左边原图的纹理坐标。在纹理坐标系中,原点是在左下角。
image.png
下图是我们需要实现的效果:
image.png
实现思路是这样的: 判断纹理的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。

image.png

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

  1. precision highp float;
  2. uniform sampler2D Texture;
  3. varying vec2 TextureCoordsVarying;
  4. void main(void){
  5. vec2 uv = TextureCoordsVarying.xy;
  6. //判断坐标范围
  7. if(uv.y >= 0.0 && uv.y <= 0.5){
  8. //(0.0,0.5)->(0.5, 0.75)
  9. uv.y = uv.y + 0.25;
  10. }else{
  11. // (0.5,1.0)->(0.5, 0.75)
  12. uv.y = uv.y - 0.25;
  13. }
  14. vec4 mask = texture2D(Texture,uv);
  15. gl_FragColor = vec4(mask.rgb,1.0);
  16. }

三分屏滤镜实现

需要实现的效果如下

image.png

实现思路:
和上面的二分屏类似,我们要填充的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.
image.png

GLSL代码如下:

  1. precision highp float;
  2. uniform sampler2D Texture;
  3. varying vec2 TextureCoordsVarying;
  4. void main(void){
  5. vec2 uv = TextureCoordsVarying.xy;
  6. if(uv.y >= 0.0 && uv.y <= 1.0/3.0){
  7. uv.y = uv.y + 1.0 / 3.0;
  8. }else if(uv.y >= 2.0 / 3.0){
  9. uv.y = uv.y - 1.0/ 3.0 ;
  10. }
  11. vec4 mask = texture2D(Texture,uv);
  12. gl_FragColor = vec4(mask.rgb,1.0);
  13. }

四分屏滤镜实现

需要实现的效果如下:
image.png

实现思路:
可以看到我们缩放了图片,图片的宽度和高度都变成了原来的一半。那么怎么缩放呢?
先从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坐标一样。
image.png

GLSL代码如下:

  1. precision highp float;
  2. uniform sampler2D Texture;
  3. varying vec2 TextureCoordsVarying;
  4. void main(void){
  5. vec2 uv = TextureCoordsVarying.xy;
  6. if(uv.y <= 0.5){
  7. uv.y = uv.y * 2.0;
  8. }else{
  9. uv.y = (uv.y - 0.5) * 2.0 ;
  10. }
  11. if(uv.x <= 0.5){
  12. uv.x = uv.x * 2.0;
  13. }else{
  14. uv.x = (uv.x - 0.5) * 2.0 ;
  15. }
  16. gl_FragColor = texture2D(Texture,uv);
  17. }

九分屏滤镜实现

需要实现的效果如下:

image.png
实现思路: 其实这个和上面的四分屏实现思路是一样的,只不过这里是把图片缩小了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代码如下:

  1. precision highp float;
  2. uniform sampler2D Texture;
  3. varying vec2 TextureCoordsVarying;
  4. void main(void){
  5. vec2 uv = TextureCoordsVarying.xy;
  6. if(uv.y >= 0.0 && uv.y <= 1.0/3.0){
  7. uv.y = uv.y * 3.0;
  8. }else if(uv.y > 2.0 /3.0){
  9. uv.y = (uv.y - 2.0 / 3.0) * 3.0 ;
  10. }else{
  11. uv.y = (uv.y - 1.0 / 3.0) * 3.0 ;
  12. }
  13. if(uv.x >= 0.0 && uv.x <= 1.0/3.0){
  14. uv.x = uv.x * 3.0;
  15. }else if(uv.x > 2.0 /3.0){
  16. uv.x = (uv.x - 2.0 / 3.0) * 3.0 ;
  17. }else{
  18. uv.x = (uv.x - 1.0 / 3.0) * 3.0 ;
  19. }
  20. gl_FragColor = texture2D(Texture,uv);
  21. }

总结

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