四、GPUImage自定义滤镜

一、背景

GPUImage的官方地址:https://github.com/BradLarson/GPUImage
官方给出的自定义滤镜的方法是让开发者自己写fragmentShader实现特效,但是粒子效果需要更多的顶点,这显然需要另一种方式来实现,完全自己定义的vertexShaderfragmentShader

二、GPUImage自定义filter

在自定义filter的时候需要弄清楚GPUImage的规则,以及在编写着色器语言时的一些限制。
1、创建一个WYFilter继承自GPUImageFilter
2、顶点着色器要有positioninputTextureCoordinate这两个输入变量,片元着色器要有textureCoordinateinputImageTexture 这两个变量。[注:GPUImage内部的顶点坐标和纹理坐标还有纹理就是以这个名称进行传值的]
3、重写initializeAttributes增加自己的attribute属性

- (void)initializeAttributes {
    [super initializeAttributes];
    
    [filterProgram addAttribute:@"flag"];
}

4、重写initWithVertexShaderString:fragmentShaderString:,在该方法中调用runSynchronouslyOnVideoProcessingQueue获取内建变量的位置索引

- (id)initWithVertexShaderFromString:(NSString *)vertexShaderString fragmentShaderFromString:(NSString *)fragmentShaderString {
    if (!(self = [super initWithVertexShaderFromString:vertexShaderString fragmentShaderFromString:fragmentShaderString])) {
        return nil;
    }
    
    runSynchronouslyOnVideoProcessingQueue(^{
        _flagSlot = [filterProgram attributeIndex:@"flag"];
    });
    
    return self;
}

5、重写renderToTextureWithVertices:textureCoordinates:,在这个方法中画自己想要画的东西

- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates {
    
    [super renderToTextureWithVertices:vertices textureCoordinates:textureCoordinates];
    
    static GLfloat vertices2[] = {
        -0.25, 0.25,   1.0,  // 左上
        -0.25, -0.25,  1.0,  // 左下
        0.25, 0.25,    1.0,  // 右上
        0.25, -0.25,   1.0,  // 右下
    };
    
    const GLbyte *pointer2 = (const GLbyte*)vertices2;

    glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, pointer2);
    glVertexAttribPointer(_flagSlot, 1, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, pointer2 + sizeof(GLfloat) * 2);
    glEnableVertexAttribArray(_flagSlot);
    glDrawArrays(GL_POINTS, 0, 4);
    
    glDisableVertexAttribArray(_flagSlot);
}

注意点:
1、当我们使用了glEnable的函数之后记得在调用glDrawArrays之后调用glDisable
例:

glVertexAttribPointer(_flagSlot, 1, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, pointer2 + sizeof(GLfloat) * 2);
glEnableVertexAttribArray(_flagSlot);
glDrawArrays(GL_POINTS, 0, 4);
    
glDisableVertexAttribArray(_flagSlot);

2、GPUImage的坐标系的y轴跟Opengl坐标系的y轴是相反的
3、GPUImage中纹理加载方式,尽量使用GLKTextureLoader加载,否则可能在部分系统的手机上出现图片纹理模糊的情况,需要#import

- (int)loadTexture {
   
    CGImageRef imgRef = [UIImage imageNamed:@"white.png"].CGImage;
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:imgRef options:nil error:nil];
    _wyTexture = textureInfo.name;

    glActiveTexture(GL_TEXTURE3);
    glBindTexture(GL_TEXTURE_2D, _wyTexture);
    
    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_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    
    return textureInfo.width * 0.5;
}

你可能感兴趣的:(四、GPUImage自定义滤镜)