Render to texture in OpenGL ES 2.0 with iOS - ios

I'm having a hard time trying to setup a render to texture environment in OpenGL ES 2.0.
What I need is a main FrameBuffer that is presented to screen and a secondary FrameBuffer that is connected to a Texture. This texture is then used in the main FrameBuffer.
I first initialize the main FrameBuffer with this code:
-(void)initializeBuffers{
//Build the main FrameBuffer
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
//Build the color Buffer
glGenRenderbuffers(1, &colorBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
//setup the color buffer with the EAGLLayer (it automatically defines width and height of the buffer)
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:EAGLLayer];
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &bufferWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &bufferHeight);
//Attach the colorbuffer to the framebuffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);
//Check the Framebuffer status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
NSAssert(status == GL_FRAMEBUFFER_COMPLETE, ERROR_FRAMEBUFFER_FAIL);
}
Then I call a function to initialise the Secondary Buffer
-(void)setupRenderToTexture{
glGenTextures(1, &gridTextureID);
glBindTexture(GL_TEXTURE_2D, gridTextureID);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bufferWidth, bufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glGenRenderbuffers(1, &textureColorBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, textureColorBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, bufferWidth, bufferHeight);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glGenFramebuffers(1, &textureFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, textureFrameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gridTextureID, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, textureColorBuffer);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
if(status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(#"failed to make complete framebuffer object %x", status);
}else{
NSLog(#"Buffer ok");
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
At this point, when it is time to draw, I call a function called render that calls the function renderToTexture:
- (void)render:(CADisplayLink*)displaylink{
[self renderToTexture];
glBindBuffer(GL_FRAMEBUFFER, frameBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
glClearColor(0.0, 1.0, 0.0, 1.0);
glViewport(0, 0, bufferWidth, bufferHeight);
glClear(GL_COLOR_BUFFER_BIT);
for(GLNode *node in sceneNodes){
[node draw]; //Draw some triangles...
}
[context presentRenderbuffer:GL_RENDERBUFFER];
}
Here the renderToTexture function:
-(void)renderToTexture{
glBindFramebuffer(GL_FRAMEBUFFER, textureFrameBuffer);
glClearColor(1.0, 0.0, 0.0, 1.0);
glViewport(0, 0, bufferWidth, bufferHeight);
glClear(GL_COLOR_BUFFER_BIT);
//Render something to texture
}
If I use only the code related with the main buffer (so the functions initializeBuffers and render) the content of the main FrameBuffer is correctly displayed at screen. If I try to use the functions related with render to texture (setupRenderToTexture and renderToTexture) the main Framebuffer is no longer drawn at screen.
I wonder if this configuration has something wrong and what can I do to correct this behaviour.

Related

OpenGL ES - Colors are different with or without FBO

I'm currently drawing objects (images, rectangles) on iPhone with OpenGL ES 2.0.
There are two modes :
A) Without FBO :
Draw objects
Render to screen
B) With FBO
Bind FBO
Draw objects
Render FBO to screen
And the scene draw order is :
Draw background with red (or black) color (1, 0, 0, 1) with glClearColor
Draw texture with transparency color (1, 1, 1, 0.5)
Here are the results (left without FBO, right with FBO) :
1) Image without transparency : both are same
2) Transparency set to 0.5, red background : both different
3) Transparency set to 0.5, black background : right same as 1) Without transparency
Here's how I create the FBO :
GLint maxRenderBufferSize;
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxRenderBufferSize);
GLuint textureWidth = (GLuint)self.size.width;
GLuint textureHeight = (GLuint)self.size.height;
if(maxRenderBufferSize <= (GLint)textureWidth || maxRenderBufferSize <= (GLint)textureHeight)
#throw [NSException exceptionWithName:TAG
reason:#"FBO cannot allocate that much space"
userInfo:nil];
glGenFramebuffers(1, &fbo);
glGenRenderbuffers(1, &fboBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &fboTexture);
glBindTexture(GL_TEXTURE_2D, fboTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(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);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTexture, 0);
glBindRenderbuffer(GL_RENDERBUFFER, fboBuffer);
GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
#throw [NSException exceptionWithName:TAG
reason:#"Failed to initialize fbo"
userInfo:nil];
Here's my fragment shader :
gl_FragColor = (v_Color * texture2D(u_Texture, v_TexCoordinate));
Found the problem, this line was the problem in my render-FBO-to-window function :
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
I just removed it because I don't need alpha blending in this step.

Xcode OpenGL ES: Framebuffer is not complete

I am trying to render an image to a texture in OpenGL ES to implement off-screen Sobel filter. Following this link http://www.songho.ca/opengl/gl_fbo.html, I create a resulting texture named sobelTexture and a render frame buffer named depthBuffer, then respectively attach them to GL_COLOR_ATTACHMENT0 and GL_DEPTH_ATTACHMENT of a newly created frame buffer. The code is shown in bellow.
// Create a texture associated with the frame buffer to render image into
GLuint sobelTexture;
glGenTextures(1, &sobelTexture);
glBindTexture(GL_TEXTURE_2D, sobelTexture);
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, width, height, 0, GL_RGBA, GL_FLOAT, 0);
glBindTexture(GL_TEXTURE_2D, 0);
GLuint depthBuffer;
glGenRenderbuffers(1, &depthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// Create frame buffer
GLuint frameBuffer;
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sobelTexture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
However, when I check the frame buffer status using the bellow code, it returns what is different from GL_FRAMEBUFFER_COMPLETE.
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
NSLog(#"! ERROR: frame buffer is not completed\n");
exit(1);
}
Moreover, If I change the data type GL_FLOAT in glTexImage2D() function to GL_UNSIGNED_BYTE, the frame buffer will be marked as complete. But I cannot use it because, in my fragment shader, the output color components are of float type.
How could I fix this problem?
Thanks in advance for any help.

Minimal configuration for rendering to texture on iOS

My code:
// setup framebuffer
glGenFramebuffers(1, &_internalFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, _internalFramebuffer);
// reference texture
glGenTextures(1, &_referenceRectifiedTexture);
glBindTexture(GL_TEXTURE_2D, _referenceRectifiedTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _referenceRectifiedTexture, 0);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
// check status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(#"failed to make complete framebuffer object %x", status);
return NO;
}
It never passes the status check. Do I need to do something else, in addition to binding the framebuffer and the texture?

OpenGL ES 2.0 rendering to multiple textures

I am building an iPad app using OpenGL ES 2.0. What I need to do is render to multiple textures and then render all the textures to view. I draw using GL_POINTS based on the user touch location. My code that I have now is:
Generate frame buffer, textures, and render buffer:
glGenFramebuffers(1, &viewFramebuffer);
glGenRenderbuffers(1, &viewRenderbuffer);
glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
glGenTextures(1, layers);
glBindTexture(GL_TEXTURE_2D, layers[0]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.bounds.size.width, self.bounds.size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, layers[0], 0);
Draw:
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
....
glDrawArrays(GL_POINTS, 0, (int)vertexCount);
glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];
The above works OK, however when I want to render to a new texture my application stops drawing any new content. I bind a new texture like this:
glGenTextures(1, &layers[1]);
glBindTexture(GL_TEXTURE_2D, layers[1]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.bounds.size.width, self.bounds.size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, layers[1], 0);
And then call the drawing method again. My code works when rendering to the first texture but when I try to generate a new texture to render to, the app stops drawing. Can anyone help out?
I got my code to work. I had several problems with my frameBuffers not generating correctly and my textures not binding accurately. Lesson learned - always check state of frameBuffer after generation! Here it is:
Setup frameBuffers:
// Generate textureFrameBuffer for handling drawing to textures
glGenFramebuffers(1, &textureFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, textureFrameBuffer);
// Generate renderBufferer for drawing to screen
glGenRenderbuffers(1, &viewRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(id<EAGLDrawable>)self.layer];
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
//Generate first texture and bind to textureFrameBuffer
glGenTextures(1, &layers[0]);
glBindTexture(GL_TEXTURE_2D, layers[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, backingWidth, backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, layers[0], 0);
//check if frameBuffer is OK
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE){
NSLog(#"failed to make complete framebuffer objects %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
return NO;
}
//Generate viewFrameBuffer for drawing to view
glGenFramebuffers(1, &viewFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, viewRenderbuffer);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
NSLog(#"failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
}
To draw to first texture:
glBindFramebuffer(GL_FRAMEBUFFER, textureFrameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, layers[0], 0);
....
glDrawArrays(GL_POINTS, 0, (int)vertexCount);
To generate and bind second texture:
glGenTextures(1, &layers[1]);
glBindFramebuffer(GL_FRAMEBUFFER, textureFrameBuffer);
glBindTexture(GL_TEXTURE_2D, layers[1]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, backingWidth, backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, layers[1], 0);
Draw to second texture:
glBindFramebuffer(GL_FRAMEBUFFER, textureFrameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, layers[1], 0);
....
glDrawArrays(GL_POINTS, 0, (int)vertexCount);
To draw all textures to screen:
// Bind view buffer
glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer);
//clear screen every frame
glClear(GL_COLOR_BUFFER_BIT);
//bind layer texture
for (int i=0; i<= layerCount; i++) {
glBindTexture(GL_TEXTURE_2D, layers [i]);
....
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
[context presentRenderbuffer:viewFramebuffer];

iOS Render to Texture: Why it is Clear

I'm trying to offscreen render using this post
http://www.idevgames.com/forums/thread-1785-post-54500.html#pid54500
First I init FBO.
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
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, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffersOES(1, &fbo);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, fbo);
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tex, 0);
GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
NSLog(#"failed to make complete framebuffer object %x", status);
exit(-1);
}
Then I draw to my texture
GLint oldFBO, oldViewPort[4];
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &oldFBO);
glGetIntegerv(GL_VIEWPORT, oldViewPort);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, listFrameBuffers[i]);
glViewport(0, 0, 512, 512);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw code here
glBindFramebufferOES(GL_FRAMEBUFFER_OES, oldFBO);
glViewport(oldViewPort[0], oldViewPort[1], oldViewPort[2], oldViewPort[3]);
And then each frame I draw it.
When I finish my frame calling glSwapBuffers texture attached to framebuffer becomes clear
(but when I draw to frame buffer each time after glSwapBuffers everything is ok).
So, the quest is completed.
I just changed draw code to this
GLint oldFBO, oldViewPort[4];
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &oldFBO);
glGetIntegerv(GL_VIEWPORT, oldViewPort);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, listFrameBuffers[i]);
glViewport(0, 0, 512, 512);
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // HERE
glDisable(GL_DEPTH_TEST); // AND HERE
// draw code here
glBindFramebufferOES(GL_FRAMEBUFFER_OES, oldFBO);
glViewport(oldViewPort[0], oldViewPort[1], oldViewPort[2], oldViewPort[3]);
and it works! :)

Resources