实现链式 shader 的核心思路利 : 用帧缓冲对象,将帧缓冲对象生成的纹理单元最为下一个 shader 纹理的输入;
源码
/** 设置帧缓冲对象 */
-(void)setuptextureSize:(CGSize)size{
glGenFramebuffers(1, &_frameBufferID);
glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &_textureID);
glBindTexture(GL_TEXTURE_2D, _textureID);
// - 这里的 size 是需要渲染的填充的view 的size,而不是图片的 size
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferID);
// - 帧缓冲对象
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D, _textureID, 0);
/*
解绑纹理,解绑才能重新绑定新的纹理单元;
如果没有解绑操作, 那么帧缓冲的输出纹理单元就是GL_TEXTURE1, 但是如果作为一个帧缓冲的输出和另一个帧缓冲输入, 就会出现输入和输出是同一个纹理单元;(如下边的shaderCompiler2, frameBuffer1的输出纹理单元作为shaderCompiler2的输入单元是 GL_TEXTURE1, 经shaderCompiler2后的frameBuffer2的输出纹理单元也是GL_TEXTURE1, 这是不可以的哦)
glActiveTexture() : 设置帧缓冲的输出纹理单元;
glUniform1i() : 设置 shader 的纹理的输入; 输入和输出不能是同一个纹理单元;
*/
glBindTexture(GL_TEXTURE_2D, 0);
}
- (GLuint)textureID{
return _textureID;
}
- (GLuint)framebufferID{
return _frameBufferID;
}
/** 激活帧缓冲 */
-(void)activityFrameBuffer{
glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferID);
}
// - 输入的纹理
-(void)setupInputTexture{
GLuint texture;
UIImage *image = [UIImage imageNamed:@"gyy.jpg"];
size_t width = CGImageGetWidth(image.CGImage);
size_t height = CGImageGetHeight(image.CGImage);
_bufferSize = CGSizeMake(width, height);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageData = malloc( height * width * 4 );
CGContextRef context = CGBitmapContextCreate(imageData,
width,
height,
8,
4 * width,
colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease( colorSpace );
CGContextClearRect( context, CGRectMake( 0, 0, width, height ) );
CGContextTranslateCTM(context, 0, height);
CGContextScaleCTM (context, 1.0,-1.0);
CGContextDrawImage( context, CGRectMake( 0, 0, width, height ), image.CGImage );
CGContextRelease(context);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
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_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA,
(GLint)width,
(GLint)height,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
imageData);
free(imageData);
}
// - 三个着色器程序 (原图纹理->shaderCompiler1->frameBuffe1, frameBuffe1->shaderCompiler2->frameBuffe2, frameBuffe2->shaderCompiler3->渲染在屏幕上)
-(void)setupShader{
self.shaderCompiler1 = [[QGShaderCompiler alloc]initWithvshaderFileName:@"VertextShader2" fshaderFileName:@"FragmentShader2_06"];
_position1 = [self.shaderCompiler1 addAttribute:@"position"];
_texture1 = [self.shaderCompiler1 addAttribute:@"textCoordinate"];
_uni1 = [self.shaderCompiler1 addUniform:@"colorMap"];
self.shaderCompiler2 = [[QGShaderCompiler alloc]initWithvshaderFileName:@"VertextShader2" fshaderFileName:@"FragmentShader2_04"];
_position2 = [self.shaderCompiler2 addAttribute:@"position"];
_texture2 = [self.shaderCompiler2 addAttribute:@"textCoordinate"];
_uni2 = [self.shaderCompiler2 addUniform:@"colorMap"];
self.shaderCompiler3 = [[QGShaderCompiler alloc]initWithvshaderFileName:@"VertextShader2" fshaderFileName:@"FragmentShader2_14"];
_position3 = [self.shaderCompiler3 addAttribute:@"position"];
_texture3 = [self.shaderCompiler3 addAttribute:@"textCoordinate"];
_uni3 = [self.shaderCompiler3 addUniform:@"colorMap"];
}
// - 两个提供输出的帧缓冲对象
-(void)setupFrameBufferObj{
self.frameBuffer1 = [[QGFrameBuffer alloc]initWithSize:self.frame.size];
self.frameBuffer2 = [[QGFrameBuffer alloc]initWithSize:self.frame.size];
}
// - 原图纹理->shaderCompiler1->frameBuffe1
-(void)render1{
[self.shaderCompiler1 glUseProgram];
[self.frameBuffer1 activityFrameBuffer];
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
/*
已知源纹理的输出纹理单元为 GL_TEXTURE0;
下边的 glUniform1i(_uni1, 0) 是将 GL_TEXTURE0 作为 self.shaderCompiler1 的输入纹理,
QGFrameBuffer 中的 glActiveTexture(GL_TEXTURE1); 是将 GL_TEXTURE1, 作为帧缓冲纹理输出单元;
*/
glUniform1i(_uni1, 0);
GLfloat vertices[] = {
1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0,
-1.0, 1.0, 0.0};
GLfloat texturecoords[] ={
1.0, 1.0,
1.0, 0.0,
0.0, 1.0,
1.0, 0.0,
0.0, 0.0,
0.0, 1.0};
glVertexAttribPointer(_position1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, vertices);
glVertexAttribPointer(_texture1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, texturecoords);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
// - frameBuffe1->shaderCompiler2->frameBuffe2
-(void)render2{
[self.shaderCompiler2 glUseProgram];
[self.frameBuffer2 activityFrameBuffer];
glClearColor(0, 1, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
/*
前边已知self.frameBuffer1的输出纹理单元为 GL_TEXTURE1;
glActiveTexture(GL_TEXTURE2); 和 glBindTexture(GL_TEXTURE_2D, [self.frameBuffer1 textureID]); 是将 self.frameBuffer1的输出纹理单元从 GL_TEXTURE1 改为 GL_TEXTURE2;
glUniform1i(_uni2, 2) 是将 GL_TEXTURE2 作为 self.shaderCompiler2 的输入纹理;
QGFrameBuffer 中的 glActiveTexture(GL_TEXTURE1); 是将 GL_TEXTURE1, 作为帧缓冲纹理输出单元;
*/
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, [self.frameBuffer1 textureID]);
glUniform1i(_uni2, 2);
GLfloat vertices[] = {
1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0,
-1.0, 1.0, 0.0};
GLfloat texturecoords[] ={
1.0, 1.0,
1.0, 0.0,
0.0, 1.0,
1.0, 0.0,
0.0, 0.0,
0.0, 1.0};
glVertexAttribPointer(_position2, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, vertices);
glVertexAttribPointer(_texture2, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, texturecoords);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
// - frameBuffe2->shaderCompiler3->渲染在屏幕上
-(void)render3{
[self.shaderCompiler3 glUseProgram];
[self activityFrameBuffer];
glClearColor(0, 0, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
/*
前边已知self.frameBuffer2的输出纹理单元为 GL_TEXTURE1;
glActiveTexture(GL_TEXTURE2); 和 glBindTexture(GL_TEXTURE_2D, [self.frameBuffer1 textureID]); 是将 self.frameBuffer2的输出纹理单元从 GL_TEXTURE1 改为 GL_TEXTURE2;
glUniform1i(_uni2, 2) 是将 GL_TEXTURE2 作为 self.shaderCompiler3 的输入纹理;
帧缓冲纹理输出单元渲染到屏幕上;
*/
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, [self.frameBuffer2 textureID]);
glUniform1i(_uni3, 2);
GLfloat vertices[] = {
1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0,
-1.0, 1.0, 0.0};
GLfloat texturecoords[] ={
1.0, 1.0,
1.0, 0.0,
0.0, 1.0,
1.0, 0.0,
0.0, 0.0,
0.0, 1.0};
glVertexAttribPointer(_position3, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, vertices);
glVertexAttribPointer(_texture3, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, texturecoords);
glDrawArrays(GL_TRIANGLES, 0, 6);
[[QGEAGLContext sharedInstance] presentRenderbuffer];
}