一、背景
GPUImage的官方地址:https://github.com/BradLarson/GPUImage
官方给出的自定义滤镜的方法是让开发者自己写fragmentShader
实现特效,但是粒子效果需要更多的顶点,这显然需要另一种方式来实现,完全自己定义的vertexShader
和fragmentShader
二、GPUImage自定义filter
在自定义filter的时候需要弄清楚GPUImage的规则,以及在编写着色器语言时的一些限制。
1、创建一个WYFilter
继承自GPUImageFilter
2、顶点着色器要有position
、inputTextureCoordinate
这两个输入变量,片元着色器要有textureCoordinate
、 inputImageTexture
这两个变量。[注: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;
}