Minimal configuration for rendering to texture on iOS - 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?

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.

Render to texture in OpenGL ES 2.0 with 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.

opengl iOS glkit color picking

Its about picking a 3d object using color-picking. I draw my mesh (update: Which resides in a static header file and is displayed fine to the screen in the same project) to a new offscreen framebuffer and then I use glReadPixels to identify if the user touched it.
Following the code from the project opengles_ch10_1 from the book "Learning OpenGLES for iOS" by Erik M.Buck, I wrote the following code which always prints to nslog the color 0,0,0 for the picked (by tapping) pixel.
My code is:
- (IBAction) tapGesture:(id)sender
{
if ([(UITapGestureRecognizer *)sender state] == UIGestureRecognizerStateEnded) {
CGPoint tapLocation = [(UITapGestureRecognizer *)sender locationInView:self.view];
int tt = [self findMeshByPoint:tapLocation];
//NSLog( #"tap value: %i", tt );
}
}
- (NSUInteger)findMeshByPoint:(CGPoint)point
{
//In openGL the y axis starts from the bottom of the screen
point.y = self.view.bounds.size.height - point.y;
GLKView *glView = (GLKView *)self.view;
NSAssert([glView isKindOfClass:[GLKView class]],
#"View controller's view is not a GLKView");
// Make the view's context current
[EAGLContext setCurrentContext:glView.context];
glBindVertexArrayOES(0);
// self.effect.constantColor = GLKVector4Make( 1.0f, //This should be meshId/255.0f
if(0 == _glVertexAttributeBufferID)
{
GLuint glName;
glGenBuffers(1, // STEP 1
&glName);
glBindBuffer(GL_ARRAY_BUFFER, // STEP 2
glName);
glBufferData( // STEP 3
GL_ARRAY_BUFFER, // Initialize buffer contents
sizeof(parparit51OBJVertices), parparit51OBJVertices,
GL_STATIC_DRAW); // Hint: cache in GPU memory
_glVertexAttributeBufferID = glName;
}
else
{
glBindBuffer(GL_ARRAY_BUFFER,
_glVertexAttributeBufferID);
}
//glEnableVertexAttribArray(TETerrainPositionAttrib);
glEnableVertexAttribArray( GLKVertexAttribPosition );
if(0 == _program)
{
[self loadShadersWithName:#"UtilityPickTerrainShader"];
[self buildFBO];
NSAssert(0 != _program,
#"prepareOpenGL failed to load shaders");
}
glUseProgram(_program);
// Pre-calculate the mvpMatrix
GLKMatrix4 modelViewProjectionMatrix2 =
GLKMatrix4Multiply(
self.effect.transform.projectionMatrix,
self.effect.transform.modelviewMatrix);
// Standard matrices
glUniformMatrix4fv(uniforms[UtilityPickTerrainMVPMatrix], 1, 0,
modelViewProjectionMatrix2.m);
// glUniform2fv(uniforms[UtilityPickTerrainDimensionFactors], 1,
// &_temp1 ); //self.factors.v); //I removed this from the shaders
glUniform1f(uniforms[UtilityPickTerrainModelIndex],
1.0f ); // self.modelIndex / 255.0f);
glBindFramebuffer(GL_FRAMEBUFFER, _pickFBO);
glViewport(0, 0, 512, 512);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 12 * sizeof(GLfloat), 0);
NSLog( #"******* 7" );
[self.effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, sizeof(parparit51OBJVertices) / sizeof(Vertex));
NSLog( #"******* 7.5" );
const GLfloat width = [glView drawableWidth];
const GLfloat height = [glView drawableHeight];
NSAssert(0 < width && 0 < height, #"Invalid drawble size");
// Get info for picked location
const GLKVector2 scaledProjectionPosition = {
point.x / width,
point.y / height
};
NSLog( #"******* 8" );
GLubyte pixelColor[4]; // Red, Green, Blue, Alpha color
GLint readLocationX = MIN((512 - 1),
(512 - 1) * scaledProjectionPosition.x);
GLint readLocationY = MIN((512 - 1),
(512 - 1) * scaledProjectionPosition.y);
glReadPixels(readLocationX,
readLocationY,
1,
1,
GL_RGBA,
GL_UNSIGNED_BYTE,
pixelColor);
NSLog(#"pixelColor[0]=%i, pixelColor[1]=%i, pixelColor[2]=%i", pixelColor[0], pixelColor[1], pixelColor[2] );
// Restore OpenGL state that pickTerrainEffect changed
glBindFramebuffer(GL_FRAMEBUFFER, 0); // default frame buffer
glViewport(0, 0, width, height); // full area of glView
return 0;
}
-(void) buildFBO
{
if ( 0 == _pickFBO )
{
GLuint colorTexture;
// Create a texture object to apply to model
glGenTextures(1, &colorTexture);
glBindTexture(GL_TEXTURE_2D, colorTexture);
// Set up filter and wrap modes for this texture object
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_MAG_FILTER,
GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
// Allocate a texture image we can render into
// Pass NULL for the data parameter since we don't need to
// load image data. We will be generating the image by
// rendering to this texture.
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA,
512,
512,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
NULL);
GLuint depthRenderbuffer;
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
512, 512);
glGenFramebuffers(1, &_pickFBO);
glBindFramebuffer(GL_FRAMEBUFFER, _pickFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, colorTexture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) !=
GL_FRAMEBUFFER_COMPLETE)
{
NSLog(#"failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
//+++tbd+++UtilityPickTerrainEffectDestroyFBO(fboName);
return;
}
//#ifdef DEBUG
// { // Report any errors
GLenum error = glGetError();
if(GL_NO_ERROR != error)
{
NSLog(#"GL Error: 0x%x", error);
}
// }
//#endif
}
}
Your error is that you are trying to access a Null Pointer -- you are almost certainly passing an array that you never actually initialized to your GLKEffect or giving it to OpenGL with a bufferData call, given that the error is occurring inside of prepareToDraw or glDrawArrays. There are several possible explanations for this that I can see, though I can't confirm any of them, since the relevant information is how you allocate the data that you are using either in perpareToDraw or in glDrawArrays.
The first is that "parparit51OBJVertices" might be allocated on the heap dynamically (are you calling malloc or the like? How do you specify the size of the array), in which case your calls to sizeof will be returning incorrect values (0 I think) which might lead to the EXEC_BAD_ACESS.
The other part of this that seems suspect is that you are calling glDrawArrays and passing in the number of vertices, but before that you bind a VBO for indices -- at best this is wasted work, since glDrawArrays will ignore the indices. Worse, if you are trying to draw an OBJ, as your variable name implies, then likely there is a considerable amount of geometry you aren't drawing at all, so even if you fix your EXEC_BAD_ACCESS problem you still will be getting bad results.
I had a BAD_ACCESS error.
I solved this by removing the code which handles the indices:
if(0 == _indexBufferID)
{
// Indices haven't been sent to GPU yet
// Create an element array buffer for mesh indices
glGenBuffers(1, &_indexBufferID);
NSAssert(0 != _indexBufferID,
#"Failed to generate element array buffer");
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
sizeof( parparit51OBJIndices ),
parparit51OBJIndices,
GL_STATIC_DRAW);
}
else
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferID);
}
Now I still need to understand why the code updated above always print 0,0,0 for any picked pixel.

-[EAGLContext renderbufferStorage:fromDrawable:] Failing the second time on?

I'm developing an iOS openGL ES application.
I'm doing the usual EAGLView / ES2Render stuff.
On startup, frambuffer creation succeeds, using the following code:
- (BOOL) createFramebuffers
{
[EAGLContext setCurrentContext:_mainContext];
// [ A ] On-screen
// 1. Framebuffer
glGenFramebuffers(1, &_mainFramebuffer);
bindFramebuffer(_mainFramebuffer);
// 2. Color buffer
glGenRenderbuffers(1, &_mainColorbuffer);
bindRenderbuffer(_mainColorbuffer);
// Adjust size to view's layer:
CAEAGLLayer* layer = (CAEAGLLayer*)[_view layer];
if (![_mainContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer]) {
// something went horribly wrong
NSLog(#"-[ES2Renderer createFramebuffers]: Failed to obtain renderbuffer storage from layer!");
return NO;
}
// Query new size:
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
// Attach to color:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _mainColorbuffer);
// 3. Depth buffer
glGenRenderbuffers(1, &_depthBuffer);
bindRenderbuffer(_depthBuffer);
if (_useStencilBuffer) {
// Depth + Stencil
// Allocate storage:
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight);
// Attach to depth:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer);
// Attach to stencil:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer);
}
else{
// Depth only
// Allocate storage:
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight);
// Attachto depth:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer);
}
// 4. Validate the set:
GLenum framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE) {
// Something went wrong!
NSLog(#"-[ES2Renderer createFramebuffers]: Failed to make complete framebuffer object: %#",
[self stringFromFramebufferStauts:framebufferStatus]);
return NO;
}
// [ B ] Off-screen (Render-to-texture)
// 1. Framebuffer
glGenFramebuffers(1, &_transFramebuffer);
bindFramebuffer(_transFramebuffer);
// 2. Depth buffer
glGenRenderbuffers(1, &_transDepthBuffer);
bindRenderbuffer(_transDepthBuffer);
if (_useStencilBuffer) {
// Allocate storage:
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight);
// Attach to depth:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _transDepthBuffer);
// Attach to stencil:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _transDepthBuffer);
}
else{
// Allocate storage
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight);
// Attach to depth:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _transDepthBuffer);
}
// 3. Textures (color buffers)
GLuint* texPtrs[2] = {&_transTexture1, &_transTexture2};
for (NSUInteger i=0; i < 2; i++) {
GLuint* texPtr = texPtrs[i];
// Create:
glGenTextures(1, texPtr);
// Bind:
bindTexture2D(*texPtr);
// Configure for pixel-aligned use:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Allocate storage:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _backingWidth, _backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
// Attach:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texPtr, 0);
framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
// Validate:
if ( framebufferStatus != GL_FRAMEBUFFER_COMPLETE) {
// Something went wrong!
NSLog(#"-[ES2Renderer createFramebuffers]: Failed to make complete framebuffer object: %#",
[self stringFromFramebufferStauts:framebufferStatus]);
return NO;
}
}
// Final State:
bindFramebuffer(_mainFramebuffer);
bindRenderbuffer(_mainColorbuffer);
bindTexture2D(0);
NSLog(#"-[ES2Renderer createFramebuffers] Succeeded.");
return YES;
}
Soon after, UIView's -layoutSubviews is called and I in turn execute -resizeFromLayer::
- (BOOL) resizeFromLayer:(CAEAGLLayer *)layer
{
// [ A ] On screen framebuffer
bindFramebuffer(_mainFramebuffer);
// 1. Resize color buffer
bindRenderbuffer(_mainColorbuffer);
if (![_mainContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer]) {
// Something went wrong
return NO; // <-- SECOND TIME ON, THIS HAPPENS
}
// Query new size:
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
// 2. Resize depth buffer
bindRenderbuffer(_depthBuffer);
if (_useStencilBuffer) {
// (Depth & Stencil)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight);
}
else{
// (Depth only)
glRenderbufferStorage(GL_FRAMEBUFFER, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight);
}
// ...Validate:
GLenum framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE) {
// Something went wrong!
NSLog(#"-[ES2Renderer resizeFromLayer:]: Failed to make complete framebuffer object: %#",
[self stringFromFramebufferStauts:glCheckFramebufferStatus(GL_FRAMEBUFFER)]);
return NO;
}
// [ B ] Off screen (render-to-terxture) framebuffer
bindFramebuffer(_transFramebuffer);
// 1. Resize depth buffer
bindRenderbuffer(_transDepthBuffer);
if (_useStencilBuffer) {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight);
}
else{
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight);
}
// 2. Resize textures
GLuint* texPtrs[2] = {&_transTexture1, &_transTexture2};
for (NSUInteger i=0; i < 2; i++) {
GLuint* texPtr = texPtrs[i];
// Bind:
bindTexture2D(*texPtr);
// Configure for pixel-aligned use:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Allocate storage:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _backingWidth, _backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
// Attach:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texPtr, 0);
// Validate:
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
// Something went wrong!
NSString* statusString = [self stringFromFramebufferStauts:glCheckFramebufferStatus(GL_FRAMEBUFFER)];
NSLog(#"-[ES2Renderer resizeFromLayer:]: Failed to make complete framebuffer object: %#", statusString);
return NO;
}
}
bindFramebuffer(_mainFramebuffer);
bindRenderbuffer(_mainColorbuffer);
// Pass new ortho projection to shaders
[self initializeModelViewMatrix];
[self initializeSpriteProgram];
// Set new viewport
glViewport(0, 0, _backingWidth, _backingHeight);
NSLog(#"-[ES2Renderer resizeFromLayer:]: Succeeded.");
return YES;
}
Nothing of what I'm doing is special. I have a separate framebuffer to render scene transitions, with two textures to attach to color, and depth.
The second time -renderbufferStorage:fromDrawable: is called (-layoutSubviews -> resizeFromLayer:), it invariably fails (returns NO); Calling glGetError() right before that results in no error, but calling it right after returns GL_INVALID_OPERATION.
If I ignore this and proceed, glGetRenderbufferParameteriv() still gets me the right width and height (640 and 1136, respectively, on an iPhone 5), but glCheckFramebufferStatus() will return GL_FRAMEBUFFER_UNSUPPORTED.
Alternatively, I skipped the above resizeFromLayer: and replaced it with this:
- (BOOL) resizeFromLayer:(CAEAGLLayer *)layer
{
[self destroyFramebuffers];
return [self createFramebuffers];
}
...but the same error persists (-renderStorage:fromDrawable: fails; this time inside -createFramebuffers).
For now, I just return YES (my app only supports portrait, so no screen size change actually ever happens), but I really want to fix it because one day I'll need to support landscape, etc...
Another possible reason is that the size of your layer is too large. In addition make sure you are using a new framebuffer and renderbuffer each time. And you have destroyed your old ones before creating new ones.
You can delete them like this
if let displayFramebuffer = self.displayFramebuffer {
var temporaryFramebuffer = displayFramebuffer
glDeleteFramebuffers(1, &temporaryFramebuffer)
self.displayFramebuffer = nil
}
if let displayRenderbuffer = self.displayRenderbuffer {
var temporaryRenderbuffer = displayRenderbuffer
glDeleteRenderbuffers(1, &temporaryRenderbuffer)
self.displayRenderbuffer = nil
}
One possible reason that renderbufferStorage:fromDrawable: is failing is that the _mainContext is not the current context at that time. Even though it may seem that no other context could have stolen the 'current' status, I recommend calling [EAGLContext setCurrentContext:_mainContext] before any gl or EAGL code that operates on objects associated with that context (e.g. at the beginning of the resizeFromLayer: method).
Josh Bernfeld's answer inspired me. I check the size of MyView and the bounds of it is CGRect.zero. And the same with the CAEAGLLayer.
For me, init MyView with a nonzero CGRect solved the problem.
Hope it works for you.

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