OpenGL ES之濾鏡處理(1)_分屏濾鏡

初始化工程完成正常的紋理加載

著色器部分

頂點著色器

因為濾鏡主要是對紋理進行處理。因此,頂點著色器代碼不用變更。

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實現(xiàn)即可。

濾鏡處理初始化

初始化上下文

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

初始化頂點數(shù)據(jù)

  //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. 綁定渲染緩沖區(qū)及幀緩沖區(qū)

    //1.渲染緩存區(qū),幀緩存區(qū)對象
      GLuint renderBuffer;
      GLuint frameBuffer;
    
      //2.獲取幀渲染緩存區(qū)名稱,綁定渲染緩存區(qū)以及將渲染緩存區(qū)與layer建立連接
      glGenRenderbuffers(1, &renderBuffer);
      glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
      [self.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];
    
      //3.獲取幀緩存區(qū)名稱,綁定幀緩存區(qū)以及將渲染緩存區(qū)附著到幀緩存區(qū)上
      glGenFramebuffers(1, &frameBuffer);
      glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                                GL_COLOR_ATTACHMENT0,
                                GL_RENDERBUFFER,
                                renderBuffer);
    

加載紋理


綁定頂點緩沖區(qū)

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. 實現(xiàn)著色器的編譯

    //編譯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. 創(chuàng)建shader->根據(jù)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. 實現(xiàn)鏈接程序

    #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. 加載程序并處理數(shù)據(jù)通道

    // 初始化著色器程序
    - (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 屬性并且傳遞數(shù)據(jù)到positionSlot中(頂點坐標)
        glEnableVertexAttribArray(positionSlot);
        glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(SenceVertex), NULL + offsetof(SenceVertex, positionCoord));
    
        //7.打開textureCoordsSlot 屬性并傳遞數(shù)據(jù)到textureCoordsSlot(紋理坐標)
        glEnableVertexAttribArray(textureCoordsSlot);
        glVertexAttribPointer(textureCoordsSlot, 2, GL_FLOAT, GL_FALSE, sizeof(SenceVertex), NULL + offsetof(SenceVertex, textureCoord));
    
        //8.保存program,界面銷毀則釋放
        self.program = program;
    }
    

通過處理片元著色器代碼完成濾鏡處理

二分屏濾鏡
原理

當實現(xiàn)二分屏濾鏡時,圖片紋理坐標的x值是沒有任何變化的,主要是y值變化

  • 當 y 在[0, 0.5]范圍時,屏幕的(0,0)坐標需要對應(yīng)圖片的(0,0.25),所以y = y+0.25
  • 當 y 在[0.5, 1]范圍時,屏幕的(0,0.5)坐標需要對應(yīng)圖片的(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);
}

三分屏濾鏡
原理

當實現(xiàn)三分屏濾鏡時,圖片紋理坐標的x值是沒有任何變化的,主要是y值變化

  • 當 y 在[0, 1/3]范圍時,屏幕的(0,0)坐標需要對應(yīng)圖片的(0,1/3),所以y = y+1/3
  • 當 y 在[1/3, 2/3]范圍時,屏幕的(0,1/3)坐標需要對應(yīng)圖片的(0,1/3),所以y 不變
  • 當 y 在[2/3, 1]范圍時,屏幕的(0,2/3)坐標需要對應(yīng)圖片的(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);
}


四分屏濾鏡
原理

當實現(xiàn)四分屏?xí)r,紋理坐標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);
}

六分屏濾鏡
原理

當實現(xiàn)六分屏?xí)r,紋理坐標x、y均需要變化,其變化規(guī)則如下:

  • 當 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);

}

九分屏濾鏡
原理

當實現(xiàn)九分屏?xí)r與四分屏類似,紋理坐標x、y均需要變化,其變化規(guī)則如下:

  • 當 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);
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容