android技术

OpenGL ES 案例11:分屏滤镜

2020-08-09  本文已影响0人  Style_月月

OpenGL + OpenGL ES +Metal 系列文章汇总
本文案例代码有OC及Swift版本,详情见文末链接

本案例的目的是理解如何用GLSL实现分屏(2/3/4/6/9)滤镜

案例的效果图如下


分屏-效果图.gif

准备工作

自定义着色器

完成无分屏滤镜的着色器代码

attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;

void main(){
    gl_Position = Position;
    TextureCoordsVarying = TextureCoords;
}

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

void main(){
    vec4 mask = texture2D(Texture, TextureCoordsVarying);
    gl_FragColor = vec4(mask.rgb, 1.0);
}

视图控制器类

在实现分屏滤镜之前,首先要呈现一个最原始的图片,即无滤镜效果的图片,大致流程如下


视图控制器整体流程

主要分为3部分

setupFilterBar函数

主要是添加自定义的滤镜滚动条,利用collectionView实现底部自定义滚动视图,这部分内容不多做说明,如果有疑问,可以参考文末完整demo

filterInit函数

主要是实现无分屏滤镜效果时的图片显示,实现流程如下


filterInit函数流程

根据图示,分为以下几部分

以上几部分的代码,在之前的OpenGL ES案例中均有涉及,这里这不展开说明了,详情可以参考文末完整代码

分屏滤镜实现

分屏滤镜的实现主要还是分屏算法,而分屏算法主要是在片元着色器中main函数中完成的,所以切换不同分屏效果主要需要改动以下几部分内容

下面分别说明下不同分屏效果的分屏算法的实现

二分屏

这里的二分屏是上下分别显示图片中间的一半,其算法如图所示


二分屏原理

当实现二分屏滤镜时,图片纹理坐标的x值是没有任何变化的,主要是y值变化

片元着色器中main函数的分屏算法代码如下

void main(){
    vec2 uv = TextureCoordsVarying.xy;
    float y;
    if (uv.y >= 0.0 && uv.y <= 0.5) {
        y = uv.y + 0.25;
    }else{
        y = uv.y - 0.25;
    }
    
    gl_FragColor = texture2D(Texture, vec2(uv.x, y));
}

三分屏

三分屏的显示是屏幕三等分,分别显示图片中部分三分之一图片,其实现原理如下


三分屏原理

当实现三分屏滤镜时,图片纹理坐标的x值是没有任何变化的,主要是y值变化

片元着色器中main函数的分屏算法代码如下

void main(){
    
    vec2 uv = TextureCoordsVarying.xy;
    if (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;
    }
    
    gl_FragColor = texture2D(Texture, uv);
}

四分屏

四分屏的显示是屏幕四等分,分别显示缩小的纹理图片,其实现原理如下


四分屏原理

纹理图片与屏幕的映射既可以是一致的坐标,也可以映射到缩小的坐标,如上图所示。

当实现四分屏时,纹理坐标x、y均需要变化,且屏幕坐标需要与纹理坐标一一映射,例如(x,y)取值(0.5,0.5)需要映射到纹理坐标(1,1)时,x、y均需要乘以2,即0.5 * 2 = 1,变化规则如下:

片元着色器中main函数的分屏算法代码如下

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

六分屏

六分屏是二分屏的演变,其实现原理如下


六分屏原理

当实现六分屏时,纹理坐标x、y均需要变化,其变化规则如下:

片元着色器中main函数的分屏算法代码如下

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

九分屏

九分屏是4分屏的演变,其实现原理如下


九分屏原理

当实现九分屏时,纹理坐标x、y均需要变化,其变化规则如下:

片元着色器中main函数的分屏算法代码如下

void main(){
    
    vec2 uv = TextureCoordsVarying.xy;
    
    if (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;
    }
    
    if (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;
    }
    
    gl_FragColor = texture2D(Texture, uv);
}

完整的代码见Github - 13_分屏滤镜OC、13分屏滤镜_Swift

上一篇下一篇

猜你喜欢

热点阅读