GPUImage(一):视频采集GPUImageVideoCamera介绍了GPUImage视频采集类
GPUImage(二):视频滤镜GPUImageFilter基础篇介绍了GPUImage滤镜的一些简单用法和片段着色器的基本使用。
本篇继续探索GPUImageFilter类的具体实现,相对于基础篇较为抽象。
GPUImageFilter3个主要职责
- 初始化OpenGL ES环境,编译、链接顶点着色器和片元着色器;
- 缓存顶点、纹理坐标数据,传送图像数据到GPU;
- 绘制图元到特定的帧缓存;
GPUImageFilter .m
文件开头定义了一个顶点着色器kGPUImageVertexShaderString和一个直通片元着色器kGPUImagePassthroughFragmentShaderString,用于初始化一个标准的GPUImageFilter,会被重写。
初始化方法:
1. -(id)init;//调用2
2. -(id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString;//调用4,是上文GPUImageSaturationFilter调用的方法
3. -(id)initWithFragmentShaderFromFile:(NSString *)fragmentShaderFilename;//从文件找查找`.fsh`文件并调用2
4. -(id)initWithVertexShaderFromString:(NSString *)vertexShaderString fragmentShaderFromString:(NSString *)fragmentShaderString;//**最终都会调用这个方法**
在4初始化方法中,调用在父类GPUImageOutput中定义的方法
void runSynchronouslyOnVideoProcessingQueue(void (^block)(void))
做一系列操作:
runSynchronouslyOnVideoProcessingQueue(^{
[GPUImageContext useImageProcessingContext];//得到上下环境
filterProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:vertexShaderString fragmentShaderString:fragmentShaderString];//openGL源程序
if (!filterProgram.initialized){
[self initializeAttributes]; //初始化shader属性,调用了初始化shader属性的方法
if (![filterProgram link]) {
NSString *progLog = [filterProgram programLog];//源程序调试log
NSLog(@"Program link log: %@", progLog);
NSString *fragLog = [filterProgram fragmentShaderLog];//片段着色器调试log
NSLog(@"Fragment shader compile log: %@", fragLog);
NSString *vertLog = [filterProgram vertexShaderLog];//顶点着色器调试log
NSLog(@"Vertex shader compile log: %@", vertLog);
filterProgram = nil;
NSAssert(NO, @"Filter shader link failed");
}
}
filterPositionAttribute = [filterProgram attributeIndex:@"position"];//得到顶点属性
filterTextureCoordinateAttribute = [filterProgram attributeIndex:@"inputTextureCoordinate"];//得到纹理属性
filterInputTextureUniform = [filterProgram uniformIndex:@"inputImageTexture"]; // This does assume a name of "inputImageTexture" for the fragment shader //得到纹理常量
[GPUImageContext setActiveShaderProgram:filterProgram];//运行源程序
glEnableVertexAttribArray(filterPositionAttribute); //开启顶点坐标数组
glEnableVertexAttribArray(filterTextureCoordinateAttribute); //开启纹理坐标数组
});
其中,glEnableVertexAttribArray
函数:把顶点属性位置值作为它的参数,启用在着色器中找到的属性位置
静态图片处理Still image processing:
重写父类两个静态图片处理方法(这一块讲解有待丰富)
- (void)useNextFrameForImageCapture;//代表着输出的结果会被用于获取图像,所以在绘制之前要加锁GPUImage详细解析
- (CGImageRef)newCGImageFromCurrentlyProcessedOutput;
最为核心的部分:渲染方法
+ (const GLfloat *)textureCoordinatesForRotation:(GPUImageRotationMode)rotationMode;
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
- (void)informTargetsAboutNewFrameAtTime:(CMTime)frameTime;
- (CGSize)outputFrameSize;//上边这个方法调用
这几个方法的作用分别是:
- 获取纹理坐标
- 渲染纹理
- 通知自己的下游targets,并将自己的输出设置为targets的输入纹理
其中,第二个方法最为核心,展开来讲
两个GPUImageFramebuffer对象:
firstInputFramebuffer:输入纹理。先加锁,输入纹理使用完毕后解锁。在调用这个解锁之前必须确定之前已经调用加锁,否则会报错。
outputFramebuffer:输出纹理,
glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
绑定输入纹理
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
绑定顶点和纹理坐标并绘制图元
这几个方法都是被GPUImageInput代理方法调用的,都在- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
中完成调用。
输入参数
目测大概有近20个输入参数方法,这些函数是设置GLSL里面的变量,就不一一说了。
GPUImageInput代理方法
GPUImageInput代理定义在GPUImageContext中,后续再说。
开篇说,GPUImageFilter的第三个职责是绘制图元到特定的帧缓存,帧缓存是什么,下文说。