GPUImage链式纹理的简单实现

链式 shader 的实现

实现链式 shader 的核心思路利 : 用帧缓冲对象,将帧缓冲对象生成的纹理单元最为下一个 shader 纹理的输入;
源码

帧缓冲的实现核心

/** 设置帧缓冲对象 */
-(void)setuptextureSize:(CGSize)size{
    glGenFramebuffers(1, &_frameBufferID);
    glActiveTexture(GL_TEXTURE1);
    glGenTextures(1, &_textureID);
    glBindTexture(GL_TEXTURE_2D, _textureID);
    
    // - 这里的 size 是需要渲染的填充的view 的size,而不是图片的 size
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferID);
    
    // - 帧缓冲对象
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D, _textureID, 0);
    
    /*
     解绑纹理,解绑才能重新绑定新的纹理单元;
 	 如果没有解绑操作, 那么帧缓冲的输出纹理单元就是GL_TEXTURE1, 但是如果作为一个帧缓冲的输出和另一个帧缓冲输入, 就会出现输入和输出是同一个纹理单元;(如下边的shaderCompiler2, frameBuffer1的输出纹理单元作为shaderCompiler2的输入单元是 GL_TEXTURE1, 经shaderCompiler2后的frameBuffer2的输出纹理单元也是GL_TEXTURE1, 这是不可以的哦)
     glActiveTexture() : 设置帧缓冲的输出纹理单元;
     glUniform1i() : 设置 shader 的纹理的输入; 输入和输出不能是同一个纹理单元;
     */
    glBindTexture(GL_TEXTURE_2D, 0);
}

- (GLuint)textureID{
    return _textureID;
}

- (GLuint)framebufferID{
    return _frameBufferID;
}

/** 激活帧缓冲 */
-(void)activityFrameBuffer{
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferID);
}

链式纹理的实现

// - 输入的纹理
-(void)setupInputTexture{
    GLuint texture;
    UIImage *image = [UIImage imageNamed:@"gyy.jpg"];
    size_t width = CGImageGetWidth(image.CGImage);
    size_t height = CGImageGetHeight(image.CGImage);
    _bufferSize = CGSizeMake(width, height);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    void *imageData = malloc( height * width * 4 );
    
    CGContextRef context = CGBitmapContextCreate(imageData,
                                                 width,
                                                 height,
                                                 8,
                                                 4 * width,
                                                 colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    
    CGColorSpaceRelease( colorSpace );
    CGContextClearRect( context, CGRectMake( 0, 0, width, height ) );
    CGContextTranslateCTM(context, 0, height);
    CGContextScaleCTM (context, 1.0,-1.0);
    CGContextDrawImage( context, CGRectMake( 0, 0, width, height ), image.CGImage );
    CGContextRelease(context);
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D,
                 0,
                 GL_RGBA,
                 (GLint)width,
                 (GLint)height,
                 0,
                 GL_RGBA,
                 GL_UNSIGNED_BYTE,
                 imageData);
    free(imageData);
}

// - 三个着色器程序 (原图纹理->shaderCompiler1->frameBuffe1, frameBuffe1->shaderCompiler2->frameBuffe2,  frameBuffe2->shaderCompiler3->渲染在屏幕上)
-(void)setupShader{
    self.shaderCompiler1 = [[QGShaderCompiler alloc]initWithvshaderFileName:@"VertextShader2" fshaderFileName:@"FragmentShader2_06"];
    _position1 = [self.shaderCompiler1 addAttribute:@"position"];
    _texture1 = [self.shaderCompiler1 addAttribute:@"textCoordinate"];
    _uni1 = [self.shaderCompiler1 addUniform:@"colorMap"];

    
    self.shaderCompiler2 = [[QGShaderCompiler alloc]initWithvshaderFileName:@"VertextShader2" fshaderFileName:@"FragmentShader2_04"];
    _position2 = [self.shaderCompiler2 addAttribute:@"position"];
    _texture2 = [self.shaderCompiler2 addAttribute:@"textCoordinate"];
    _uni2 = [self.shaderCompiler2 addUniform:@"colorMap"];


    self.shaderCompiler3 = [[QGShaderCompiler alloc]initWithvshaderFileName:@"VertextShader2" fshaderFileName:@"FragmentShader2_14"];
    _position3 = [self.shaderCompiler3 addAttribute:@"position"];
    _texture3 = [self.shaderCompiler3 addAttribute:@"textCoordinate"];
    _uni3 = [self.shaderCompiler3 addUniform:@"colorMap"];
}

// - 两个提供输出的帧缓冲对象
-(void)setupFrameBufferObj{
    self.frameBuffer1 = [[QGFrameBuffer alloc]initWithSize:self.frame.size];
    self.frameBuffer2 = [[QGFrameBuffer alloc]initWithSize:self.frame.size];
}

// - 原图纹理->shaderCompiler1->frameBuffe1
-(void)render1{
    [self.shaderCompiler1 glUseProgram];
    [self.frameBuffer1 activityFrameBuffer];
    glClearColor(1, 0, 0, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);

    /*
     已知源纹理的输出纹理单元为 GL_TEXTURE0;
     下边的 glUniform1i(_uni1, 0) 是将 GL_TEXTURE0 作为 self.shaderCompiler1 的输入纹理,
     QGFrameBuffer 中的 glActiveTexture(GL_TEXTURE1); 是将 GL_TEXTURE1, 作为帧缓冲纹理输出单元;
     */
    glUniform1i(_uni1, 0);
    
    GLfloat vertices[] = {
        1.0, 1.0, 0.0,
        1.0, -1.0, 0.0,
        -1.0, 1.0, 0.0,
        
        1.0, -1.0, 0.0,
        -1.0, -1.0, 0.0,
        -1.0, 1.0, 0.0};
    
    GLfloat texturecoords[] ={
        1.0, 1.0,
        1.0, 0.0,
        0.0, 1.0,
        1.0, 0.0,
        0.0, 0.0,
        0.0, 1.0};
    
    glVertexAttribPointer(_position1, 3, GL_FLOAT, GL_FALSE,  sizeof(GLfloat) * 3, vertices);
    glVertexAttribPointer(_texture1, 2, GL_FLOAT, GL_FALSE,  sizeof(GLfloat) * 2, texturecoords);
    glDrawArrays(GL_TRIANGLES, 0, 6);
}

// - frameBuffe1->shaderCompiler2->frameBuffe2
-(void)render2{
    [self.shaderCompiler2 glUseProgram];
    [self.frameBuffer2 activityFrameBuffer];

    glClearColor(0, 1, 0, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);
    
    /*
     前边已知self.frameBuffer1的输出纹理单元为 GL_TEXTURE1;
     glActiveTexture(GL_TEXTURE2); 和 glBindTexture(GL_TEXTURE_2D, [self.frameBuffer1 textureID]); 是将 self.frameBuffer1的输出纹理单元从 GL_TEXTURE1 改为 GL_TEXTURE2;
     glUniform1i(_uni2, 2) 是将 GL_TEXTURE2 作为 self.shaderCompiler2 的输入纹理;
     QGFrameBuffer 中的 glActiveTexture(GL_TEXTURE1); 是将 GL_TEXTURE1, 作为帧缓冲纹理输出单元;
     */
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, [self.frameBuffer1 textureID]);
    glUniform1i(_uni2, 2);
    
    GLfloat vertices[] = {
        1.0, 1.0, 0.0,
        1.0, -1.0, 0.0,
        -1.0, 1.0, 0.0,
        
        1.0, -1.0, 0.0,
        -1.0, -1.0, 0.0,
        -1.0, 1.0, 0.0};
    
    GLfloat texturecoords[] ={
        1.0, 1.0,
        1.0, 0.0,
        0.0, 1.0,
        1.0, 0.0,
        0.0, 0.0,
        0.0, 1.0};
    
    glVertexAttribPointer(_position2, 3, GL_FLOAT, GL_FALSE,  sizeof(GLfloat) * 3, vertices);
    glVertexAttribPointer(_texture2, 2, GL_FLOAT, GL_FALSE,  sizeof(GLfloat) * 2, texturecoords);
    glDrawArrays(GL_TRIANGLES, 0, 6);

}

// - frameBuffe2->shaderCompiler3->渲染在屏幕上
-(void)render3{
    [self.shaderCompiler3 glUseProgram];
    [self activityFrameBuffer];
    glClearColor(0, 0, 1, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);
    
    /*
     前边已知self.frameBuffer2的输出纹理单元为 GL_TEXTURE1;
     glActiveTexture(GL_TEXTURE2); 和 glBindTexture(GL_TEXTURE_2D, [self.frameBuffer1 textureID]); 是将 self.frameBuffer2的输出纹理单元从 GL_TEXTURE1 改为 GL_TEXTURE2;
     glUniform1i(_uni2, 2) 是将 GL_TEXTURE2 作为 self.shaderCompiler3 的输入纹理;
     帧缓冲纹理输出单元渲染到屏幕上;
     */
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, [self.frameBuffer2 textureID]);
    glUniform1i(_uni3, 2);


    GLfloat vertices[] = {
        1.0, 1.0, 0.0,
        1.0, -1.0, 0.0,
        -1.0, 1.0, 0.0,
        
        1.0, -1.0, 0.0,
        -1.0, -1.0, 0.0,
        -1.0, 1.0, 0.0};
    
    GLfloat texturecoords[] ={
        1.0, 1.0,
        1.0, 0.0,
        0.0, 1.0,
        1.0, 0.0,
        0.0, 0.0,
        0.0, 1.0};
    

    glVertexAttribPointer(_position3, 3, GL_FLOAT, GL_FALSE,  sizeof(GLfloat) * 3, vertices);
    glVertexAttribPointer(_texture3, 2, GL_FLOAT, GL_FALSE,  sizeof(GLfloat) * 2, texturecoords);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    [[QGEAGLContext sharedInstance] presentRenderbuffer];
}

你可能感兴趣的:(#,GPUImage,源码解读,#,OpenGLES,基础知识)