一、背景
GPUImage的官方地址:https://github.com/BradLarson/GPUImage
官方給出的自定義濾鏡的方法是讓開發(fā)者自己寫fragmentShader實(shí)現(xiàn)特效,但是粒子效果需要更多的頂點(diǎn),這顯然需要另一種方式來實(shí)現(xiàn),完全自己定義的vertexShader和fragmentShader
二、GPUImage自定義filter
在自定義filter的時候需要弄清楚GPUImage的規(guī)則,以及在編寫著色器語言時的一些限制。
1、創(chuàng)建一個WYFilter繼承自GPUImageFilter
2、頂點(diǎn)著色器要有position、inputTextureCoordinate這兩個輸入變量,片元著色器要有textureCoordinate、 inputImageTexture 這兩個變量。[注:GPUImage內(nèi)部的頂點(diǎn)坐標(biāo)和紋理坐標(biāo)還有紋理就是以這個名稱進(jìn)行傳值的]
3、重寫initializeAttributes增加自己的attribute屬性
- (void)initializeAttributes {
[super initializeAttributes];
[filterProgram addAttribute:@"flag"];
}
4、重寫initWithVertexShaderString:fragmentShaderString:,在該方法中調(diào)用runSynchronouslyOnVideoProcessingQueue獲取內(nèi)建變量的位置索引
- (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);
}
注意點(diǎn):
1、當(dāng)我們使用了glEnable的函數(shù)之后記得在調(diào)用glDrawArrays之后調(diào)用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的坐標(biāo)系的y軸跟Opengl坐標(biāo)系的y軸是相反的
3、GPUImage中紋理加載方式,盡量使用GLKTextureLoader加載,否則可能在部分系統(tǒng)的手機(jī)上出現(xiàn)圖片紋理模糊的情況,需要#import <GLKit/GLKit.h>
- (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;
}