OpenGL ES之滤镜处理(1)_分屏滤镜

2020-08-11  本文已影响0人  _涼城

初始化工程完成正常的纹理加载

着色器部分

顶点着色器

因为滤镜主要是对纹理进行处理。因此,顶点着色器代码不用变更。

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

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

普通纹理加载的片元着色器

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

void main (void) {

    vec4 mask = texture2D(Texture, TextureCoordsVarying);
    gl_FragColor = vec4(mask.rgb, 1.0);
}
OpenGL ES 部分
初始化滤镜工具栏

用collectionView实现即可。

滤镜处理初始化

初始化上下文

self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:_context];

初始化顶点数据

  //3.初始化顶点(0,1,2,3)的顶点坐标以及纹理坐标
  self.vertices = malloc(sizeof(SenceVertex) * 4);
  self.vertices[0] = (SenceVertex){{-1, 1, 0}, {0, 1}};
  self.vertices[1] = (SenceVertex){{-1, -1, 0}, {0, 0}};
  self.vertices[2] = (SenceVertex){{1, 1, 0}, {1, 1}};
  self.vertices[3] = (SenceVertex){{1, -1, 0}, {1, 0}};

初始化并绑定渲染图层

  1. 初始化

    CAEAGLLayer *layer = [[CAEAGLLayer alloc] init];
    layer.frame = CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.width);
    layer.contentsScale = [UIScreen mainScreen].scale;
    [self.view.layer addSublayer:layer];
    
  2. 绑定渲染缓冲区及帧缓冲区

    //1.渲染缓存区,帧缓存区对象
      GLuint renderBuffer;
      GLuint frameBuffer;
    
      //2.获取帧渲染缓存区名称,绑定渲染缓存区以及将渲染缓存区与layer建立连接
      glGenRenderbuffers(1, &renderBuffer);
      glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
      [self.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];
    
      //3.获取帧缓存区名称,绑定帧缓存区以及将渲染缓存区附着到帧缓存区上
      glGenFramebuffers(1, &frameBuffer);
      glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                                GL_COLOR_ATTACHMENT0,
                                GL_RENDERBUFFER,
                                renderBuffer);
    

加载纹理


绑定顶点缓冲区

glViewport(0, 0, self.drawableWidth, self.drawableHeight);
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(SenceVertex) * 4, self.vertices, GL_STATIC_DRAW);

初始化着色器程序

  1. 实现着色器的编译

    //编译shader代码
    - (GLuint)compileShaderWithName:(NSString *)name type:(GLenum)shaderType {
    
        //1.获取shader 路径
        NSString *shaderPath = [[NSBundle mainBundle] pathForResource:name ofType:shaderType == GL_VERTEX_SHADER ? @"vsh" : @"fsh"];
        NSError *error;
        NSString *shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
        if (!shaderString) {
            NSAssert(NO, @"读取shader失败");
            exit(1);
        }
    
        //2. 创建shader->根据shaderType
        GLuint shader = glCreateShader(shaderType);
    
        //3.获取shader source
        const char *shaderStringUTF8 = [shaderString UTF8String];
        int shaderStringLength = (int)[shaderString length];
        glShaderSource(shader, 1, &shaderStringUTF8, &shaderStringLength);
    
        //4.编译shader
        glCompileShader(shader);
    
        //5.查看编译是否成功
        GLint compileSuccess;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compileSuccess);
        if (compileSuccess == GL_FALSE) {
            GLchar messages[256];
            glGetShaderInfoLog(shader, sizeof(messages), 0, &messages[0]);
            NSString *messageString = [NSString stringWithUTF8String:messages];
            NSAssert(NO, @"shader编译失败:%@", messageString);
            exit(1);
        }
        //6.返回shader
        return shader;
    }
    
  2. 实现链接程序

    #pragma mark -shader compile and link
    //link Program
    - (GLuint)programWithShaderName:(NSString *)shaderName {
        //1. 编译顶点着色器/片元着色器
        GLuint vertexShader = [self compileShaderWithName:shaderName type:GL_VERTEX_SHADER];
        GLuint fragmentShader = [self compileShaderWithName:shaderName type:GL_FRAGMENT_SHADER];
    
        //2. 将顶点/片元附着到program
        GLuint program = glCreateProgram();
        glAttachShader(program, vertexShader);
        glAttachShader(program, fragmentShader);
    
        //3.linkProgram
        glLinkProgram(program);
    
        //4.检查是否link成功
        GLint linkSuccess;
        glGetProgramiv(program, GL_LINK_STATUS, &linkSuccess);
        if (linkSuccess == GL_FALSE) {
            GLchar messages[256];
            glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]);
            NSString *messageString = [NSString stringWithUTF8String:messages];
            NSAssert(NO, @"program链接失败:%@", messageString);
            exit(1);
        }
        //5.返回program
        return program;
    }
    
    
  3. 加载程序并处理数据通道

    // 初始化着色器程序
    - (void)setupShaderProgramWithName:(NSString *)name {
        //1. 获取着色器program
        GLuint program = [self programWithShaderName:name];
    
        //2. use Program
        glUseProgram(program);
    
        //3. 获取Position,Texture,TextureCoords 的索引位置
        GLuint positionSlot = glGetAttribLocation(program, "Position");
        GLuint textureSlot = glGetUniformLocation(program, "Texture");
        GLuint textureCoordsSlot = glGetAttribLocation(program, "TextureCoords");
    
        //4.激活纹理,绑定纹理ID
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, self.textureID);
    
        //5.纹理sample
        glUniform1i(textureSlot, 0);
    
        //6.打开positionSlot 属性并且传递数据到positionSlot中(顶点坐标)
        glEnableVertexAttribArray(positionSlot);
        glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(SenceVertex), NULL + offsetof(SenceVertex, positionCoord));
    
        //7.打开textureCoordsSlot 属性并传递数据到textureCoordsSlot(纹理坐标)
        glEnableVertexAttribArray(textureCoordsSlot);
        glVertexAttribPointer(textureCoordsSlot, 2, GL_FLOAT, GL_FALSE, sizeof(SenceVertex), NULL + offsetof(SenceVertex, textureCoord));
    
        //8.保存program,界面销毁则释放
        self.program = program;
    }
    

通过处理片元着色器代码完成滤镜处理

二分屏滤镜
原理

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

片元着色器代码
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

void main (void) {
    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;
    }
    vec4 mask = texture2D(Texture, vec2(uv.x,y));
    gl_FragColor = vec4(mask.rgb, 1.0);
}

三分屏滤镜
原理

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

片元着色器代码
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

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


四分屏滤镜
原理

当实现四分屏时,纹理坐标x、y均需要变化,且屏幕坐标需要与纹理坐标一一映射。

片元着色器代码
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

void main (void) {
    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;
    } 

    vec4 mask = texture2D(Texture, uv);
    gl_FragColor = vec4(mask.rgb, 1.0);
}

六分屏滤镜
原理

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

片元着色器代码
precision highp float;
uniform sampler2D Texture;
varying highp vec2 TextureCoordsVarying;

void main (void) {
    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);

}

九分屏滤镜
原理

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

片元着色器代码
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

void main (void) {
    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 - 1.0 / 3.0) * 3.0;
    }else{
        uv.x = (uv.x - 2.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 - 1.0 / 3.0) * 3.0;
    }else{
        uv.y = (uv.y - 2.0 / 3.0) * 3.0;
    }

    vec4 mask = texture2D(Texture, uv);
    gl_FragColor = vec4(mask.rgb, 1.0);
}

上一篇下一篇

猜你喜欢

热点阅读