GPUImageTwoInputFilter是一个可以同时有两个输入的filter,可以做混合,滤镜等特效。类图如下:
![](https://img.haomeiwen.com/i5994163/66b366f974e6ec03.png)
由图可见,GPUImageTwoInputFilter继承自GPUImageFilter, 它本身有一个secondInputFramebuffer, 加上它的父类GPUImageFilter的firstInputFramebuffer,一共有两个输入的Framebuffer,如
GPUImageTwoInputFilter* twoInputFilter;
[filter1 twoInputFilter atTextureLocation:0];
[filter2 twoInputFilter atTextureLocation:1];
后,会将filter1和filter2的outputframebuffer,赋给twoInputFilter的firstInputFramebuffer和secondInputFramebuffer,如下图:
![](https://img.haomeiwen.com/i5994163/84cb4d97b31cf13d.png)
我们再看下GPUImageTwoInputFilter的newFrameReadyAtTime函数的实现:
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
{
//以防重复渲染
if (hasReceivedFirstFrame && hasReceivedSecondFrame) {
return;
}
BOOL updatedMovieFrameOppositeStillImage = NO;
//根据textureIndex判断是第一个还是第二个framebuffer到来
if (textureIndex == 0) {
hasReceivedFirstFrame = YES;
firstFrameTime = frameTime;
if (secondFrameCheckDisabled) {
hasReceivedSecondFrame = YES;
}
if (!CMTIME_IS_INDEFINITE(frameTime)) {
if CMTIME_IS_INDEFINITE(secondFrameTime) {
updatedMovieFrameOppositeStillImage = YES;
}
}
}
else {
hasReceivedSecondFrame = YES;
secondFrameTime = frameTime;
if (firstFrameCheckDisabled) {
hasReceivedFirstFrame = YES;
}
if (!CMTIME_IS_INDEFINITE(frameTime)) {
if CMTIME_IS_INDEFINITE(firstFrameTime) {
updatedMovieFrameOppositeStillImage = YES;
}
}
}
// || (hasReceivedFirstFrame && secondFrameCheckDisabled) || (hasReceivedSecondFrame && firstFrameCheckDisabled)
if ((hasReceivedFirstFrame && hasReceivedSecondFrame) || updatedMovieFrameOppositeStillImage) //当两个intputFramebuffer都到来时
{
CMTime passOnFrameTime = (!CMTIME_IS_INDEFINITE(firstFrameTime)) ? firstFrameTime : secondFrameTime;
//内部会调用GPUImageTwoInputFilter或它子类的renderToTextureWithVertices
[super newFrameReadyAtTime:passOnFrameTime atIndex:0]; // Bugfix when trying to record: always use time from first input (unless indefinite, in which case use the second input)
hasReceivedFirstFrame = NO;
hasReceivedSecondFrame = NO;
}
}
在看下renderToTextureWithVertices的实现,
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
{
if (self.preventRendering)
{
[firstInputFramebuffer unlock];
[secondInputFramebuffer unlock];
return;
}
[GPUImageContext setActiveShaderProgram:filterProgram];
//创建outputFramebuffer
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
[outputFramebuffer activateFramebuffer];
if (usingNextFrameForImageCapture)
{
[outputFramebuffer lock];
}
[self setUniformsForProgramAtIndex:0];
glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
glClear(GL_COLOR_BUFFER_BIT);
//绑定firstInputFramebuffer的纹理到纹理单元2上
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
glUniform1i(filterInputTextureUniform, 2); //对应片元着色器的inputImageTexture采样器,把它设为2
//绑定secondInputFramebuffer的纹理到纹理单元3上
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, [secondInputFramebuffer texture]);
glUniform1i(filterInputTextureUniform2, 3); //对应片元着色器的inputImageTexture2采样器,把它设为3
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
glVertexAttribPointer(filterSecondTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:inputRotation2]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); //渲染
[firstInputFramebuffer unlock];
[secondInputFramebuffer unlock];
if (usingNextFrameForImageCapture)
{
dispatch_semaphore_signal(imageCaptureSemaphore);
}
}
代码挺简单,不再赘述。
GPUImageTwoPassFilter相当于把两个filter串联起来,它的类图如下:
![](https://img.haomeiwen.com/i5994163/cba9117a59f4cfb1.png)
它内部的套路如下图:
![](https://img.haomeiwen.com/i5994163/be747c48a6ac3aa5.png)
它的renderToTextureWithVertices源码如下:
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
{
if (self.preventRendering)
{
[firstInputFramebuffer unlock];
return;
}
[GPUImageContext setActiveShaderProgram:filterProgram];
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
[outputFramebuffer activateFramebuffer];
[self setUniformsForProgramAtIndex:0];
glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
glUniform1i(filterInputTextureUniform, 2);
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
[firstInputFramebuffer unlock];
firstInputFramebuffer = nil;
// Run the second stage of the two-pass filter
secondOutputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
[secondOutputFramebuffer activateFramebuffer];
[GPUImageContext setActiveShaderProgram:secondFilterProgram];
if (usingNextFrameForImageCapture)
{
[secondOutputFramebuffer lock];
}
[self setUniformsForProgramAtIndex:1];
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, [outputFramebuffer texture]);
glVertexAttribPointer(secondFilterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:kGPUImageNoRotation]);
glUniform1i(secondFilterInputTextureUniform, 3);
glVertexAttribPointer(secondFilterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
[outputFramebuffer unlock];
outputFramebuffer = nil;
if (usingNextFrameForImageCapture)
{
dispatch_semaphore_signal(imageCaptureSemaphore);
}
}
代码挺简单,不再赘述。
网友评论