美文网首页
OpenGL ES之滤镜处理(1)_分屏滤镜

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

作者: _涼城 | 来源:发表于2020-08-11 18:35 被阅读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值变化

    • 当 y 在[0, 0.5]范围时,屏幕的(0,0)坐标需要对应图片的(0,0.25),所以y = y+0.25
    • 当 y 在[0.5, 1]范围时,屏幕的(0,0.5)坐标需要对应图片的(0,0.25),所以y = y-0.25
    片元着色器代码
    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值变化

    • 当 y 在[0, 1/3]范围时,屏幕的(0,0)坐标需要对应图片的(0,1/3),所以y = y+1/3
    • 当 y 在[1/3, 2/3]范围时,屏幕的(0,1/3)坐标需要对应图片的(0,1/3),所以y 不变
    • 当 y 在[2/3, 1]范围时,屏幕的(0,2/3)坐标需要对应图片的(0,1/3),所以y = y-1/3
    片元着色器代码
    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均需要变化,且屏幕坐标需要与纹理坐标一一映射。

    • 当 x 在[0, 0.5]范围时,x = x*2
    • 当 x在[0.5, 1]范围时,x = (x-0.5)*2
    • 当 y 在[0, 0.5]范围时,y = y*2
    • 当 y 在[0.5, 1]范围时,y = (y-0.5)*2
    片元着色器代码
    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均需要变化,其变化规则如下:

    • 当 x 在[0, 1/3]范围时,x = x+1/3
    • 当 x 在[1/3, 2/3]范围时,x 不变
    • 当 x 在[2/3, 1]范围时,x = x-1/3
    • 当 y 在[0, 0.5]范围时,y = y+0.25
    • 当 y 在[0.5, 1]范围时,y = y-0.25
    片元着色器代码
    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均需要变化,其变化规则如下:

    • 当 x 在[0, 1/3]范围时,x = x*3
    • 当 x 在[1/3, 2/3]范围时,x = (x-1/3)*3
    • 当 x 在[2/3, 1]范围时,x = (x-2/3)*3
    • 当 y 在[0, 1/3]范围时,y= y*3
    • 当 y 在[1/3, 2/3]范围时,y = (y-1/3)*3
    • 当 y 在[2/3, 1]范围时,y = (y-2/3)*3
    片元着色器代码
    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);
    }
    
    

    相关文章

      网友评论

          本文标题:OpenGL ES之滤镜处理(1)_分屏滤镜

          本文链接:https://www.haomeiwen.com/subject/zwiydktx.html