I'm creating a 3D OpenGL ES view on the iPhone and want to set up a depth buffer, so I can use it. I'm calling glEnable(GL_DEPTH_TEST) and such, but because I haven't set up the z-buffer, it does nothing.
I'm looking for an equivalent call to
glutInitDisplayMode(GLUT_DEPTH)
Any help would be most welcome. Thanks!
As you suspect, you've no depth buffer. You'll need to attach a depth buffer to your frame buffer in whatever UIView subclass you've created that uses a CAEAGLLayer as its layer.
Supposing you're working with Apple's OpenGL ES Xcode template, the relevant UIView subclass is EAGLView. There's a method in there, createFramebuffer, that is responsible for creating the frame buffer. Initially it'll say:
- (void)createFramebuffer
{
if (context && !defaultFramebuffer)
{
[EAGLContext setCurrentContext:context];
// Create default framebuffer object.
glGenFramebuffers(1, &defaultFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
// Create color render buffer and allocate backing store.
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &framebufferWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &framebufferHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
NSLog(#"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
}
}
What that does is generates and binds a frame buffer, then it generates and binds a colour render buffer, gifts the colour buffer the inherent storage that comes with a CAEAGLLayer, grabs the frame dimensions for later and attaches the colour buffer to the render buffer.
You need also to create and attach a depth buffer. Which should be as simple as (with a suitable instance variable added for depthRenderbuffer; typing directly in here):
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, framebufferWidth, framebufferHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
Which does what it looks like it does — generates and binds a render buffer, allocates it storage to be a 16bit depth buffer of the same dimensions as the colour buffer and then attaches it to the frame buffer.
So, in total (untested):
- (void)createFramebuffer
{
if (context && !defaultFramebuffer)
{
[EAGLContext setCurrentContext:context];
// Create default framebuffer object.
glGenFramebuffers(1, &defaultFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
// Create color render buffer and allocate backing store.
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &framebufferWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &framebufferHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
// Create depth render buffer and allocate backing store.
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, framebufferWidth, framebufferHeight);
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));
}
}
Related
I am attempting to render to a texture in ios with multisampling enabled and then use that texture in my final output. Is this possible?
So far I have only gotten black textures or aliased images. The code I am using is:
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
//glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, width, height);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA4, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
//glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, self.view.bounds.size.height);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
if(status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(#"failed to make complete framebuffer object %x", status);
}
// Render my scene
glBindFramebuffer( GL_FRAMEBUFFER, framebuffer );
glViewport(0,0,width,height);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// Draw scene
// Then bind default framebuffer
glBindFramebuffer( GL_FRAMEBUFFER, 1 );
// Draw other things
// Now resolve the multisampling and draw texture
glResolveMultisampleFramebufferAPPLE();
glUseTexture( GL_TEXTURE_2D, texture );
// Draw with texture
This code does not work. It fails if I make the depth render buffer multisampled. If I just use a normal fbo for the depth then it works, but produces an aliased image.
Anyone know where I am going wrong?
Thanks!
Yes! I found what I was doing wrong. I wrongly thought that I could have the following:
Framebuffer
Multisampled colour render buffer attached to a texture
Multisampled depth buffer
But you cannot do this. D: You have to have the following:
Multisampled framebuffer:
Multisampled colour render buffer (Not attached to a texture)
Multisampled depth render buffer
Normal framebuffer:
Colour render buffer attached to a texture. This is what will be written to by glResolveMultisampleFramebufferAPPLE() and what we will use to render the result.
No depth buffer.
I.e. you have to copy the results of the multisampled render to a whole new framebuffer.
Some code:
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glGenFramebuffers(1, &resolved_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, resolved_framebuffer);
glGenRenderbuffers(1, &resolvedColorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, resolvedColorRenderbuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
if(status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(#"failed to make complete framebuffer object %x", status);
}
// Render my scene
glBindFramebuffer( GL_FRAMEBUFFER, framebuffer );
glViewport(0,0,width,height);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// Draw scene
// Then bind default framebuffer
glBindFramebuffer( GL_FRAMEBUFFER, 1 );
// Draw other things
// Now resolve the multisampling into the other fbo
glBindFramebuffer( GL_READ_FRAMEBUFFER_APPLE, framebuffer );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER_APPLE, resolved_framebuffer );
glResolveMultisampleFramebufferAPPLE();
glBindTexture( GL_TEXTURE_2D, texture );
// Draw with texture
Thanks Goz, you got me in the right direction!
I assume you've been working from the sample on this page?
Remove the glFramebufferTexture2D call as this may be causing the multisample render buffer to detach and hence you are have a multisampled back buffer and a single sampled render buffer. Furthermore, creating a single sampled depth buffer wil solve your issues as it will not be paired with theat single sampled render buffer.
Edit: When do you get the error? On the one creating the render buffer? If so you may be best off trying it exactly as in the link I posted (which I assume you are working for).
ie.
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, width, height);
now i'm working on opengl to show a view.
My intension is to update opengl view in real-time, if i change the vertices data, the view also changed. But no luck that there is a bug in Xcode.
It is known as createFramebuffer NG for backingWidth/backingHeight is 0 when layout opengl view in the 2nd time.
1.I also tried put createFramebuffer in drawview, also NG.
2.when glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES, i also tried to creat framebuffer again, but also NG.
Other guy also found this:OpenGL-ES, iPhone and intermittent error: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES (0x8CD6)
Anybody else encounter this problem? How did you deal with it?
Thank you in advance!
- (BOOL)createFramebuffer {
NSLog(#"createFramebuffer");
//******************************************************
//Create the framebuffer and renderbuffer object
//******************************************************
glGenFramebuffersOES(1, &viewFramebuffer);
glGenRenderbuffersOES(1, &viewRenderbuffer);
//*******************************************************************
//Bind the framebuffer and renderbuffer object to the pipeline
//*******************************************************************
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
//******************************************************
//Allocate storage
//******************************************************
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
//******************************************************
//Attach renderbuffer object to framebuffer object
//******************************************************
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
NSLog(#" backing size = (%d, %d)", backingWidth, backingHeight);
if (USE_DEPTH_BUFFER) {
glGenRenderbuffersOES(1, &depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
}
if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
NSLog(#"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
return NO;
}
return YES;
}
I got a work-around way, but cost more memory, init the opengl view again when the vertices data was changed.
Anybody else has good approach?
I followed a tutorial using depth buffer in opengl es 1.1. But I use opengl es 2.0. The implemented code results in an error: Failed to make complete framebuffer object 8cd6.
See implemented code below:
(void)createFramebuffer
{
if (context && !defaultFramebuffer)
{
[EAGLContext setCurrentContext:context];
// Create default framebuffer object.
glGenFramebuffers(1, &defaultFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
// Create color render buffer and allocate backing store.
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
// Create depth render buffer
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &framebufferWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &framebufferHeight);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, framebufferWidth, framebufferHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
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));
}
}
Regards
Niclas
The problem is that you’re twice binding storage to your Depth renderbuffer, and never to your Color renderbuffer. The -renderbufferStorage:fromDrawable: message to your EAGLContext binds a storage to the currently bound renderbuffer, which in your case is the Depth renderbuffer. Following, you’re binding storage to it again using the glRenderbufferStorage call.
The solution is to bind the Color renderbuffer prior to sending the storage message, so that the storage gets bounds to that. That is, insert a line glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); directly above the message, after you create your Depth renderbuffer. It should work, I was able to reproduce your error and subsequently solve it in this way.
NB. Always make sure the correct buffers are bound. You can check using glGetIntegerv() for the binding, and glGetRenderbufferParameteriv() for additional parameters.
I'm writing an iPhone application which uses UIView with a CAEAGLayer as its layer. Everything is fine and working apart from 1 small problem: sometimes it crashes with EXC_BAD_ACCESS and the following stack trace:
[EAGLView draw]
glDrawArrays_Exec
PrepareToDraw
DrawFramebufferMakeResident
AttachmentMakeResident
TextureMakeResident
memmove
it crashes on the line:
glVertexPointer(3, GL_FLOAT, 0, vertexCoordinates);
glTexCoordPointer(2, GL_FLOAT, 0, textureCoordinates);
glBindTexture(GL_TEXTURE_2D, textures[kActiveSideLeft]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, totalPoints); //<--Crash here
Application will only crash during interface rotation change (that also happens to be the only case when the view frame changes). It doesn't crash often; most of the time it takes 3-5 minutes of rotating device to reproduce this problem.
I believe I'm making a mistake which is related to CAEAGLLayer initialization / frame change since that's where it crashes (I believe).
So here are the init and layout subviews methods:
Init:
...
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = TRUE;
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!context || ![EAGLContext setCurrentContext:context])
{
[self release];
return nil;
}
glGenFramebuffersOES(1, &defaultFramebuffer);
glGenRenderbuffersOES(1, &colorRenderbuffer);
glGenRenderbuffersOES(1, &depthRenderbuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
...
On set frame I only set GL_MODELVIEW and GL_POJECTION matrixes, so I guess nothing bad can happen there.
LayoutSubviews:
- (void)layoutSubviews
{
[EAGLContext setCurrentContext:context];
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
NSAssert1(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) == GL_FRAMEBUFFER_COMPLETE_OES, #"Failed to make complete framebuffer object: %X", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
}
Draw method itself looks like:
if ([EAGLContext currentContext] != context) {
[EAGLContext setCurrentContext:context];
}
glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
glViewport(0, 0, backingWidth, backingHeight);
...//drawing different triangle strips here
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
I'd appreciate any comments on the listed code or suggestions about how can I find out the cause of this bug.
I'd be suspicious of the totalPoints variable being passed to drawArrays, or maybe your values for vertexCorrdinates or textureCoordinates, if those arrays aren't static. Your crash implies that you're walking off the end of memory while drawing the arrays. I'm less suspicious of your GL setup and more concerned about your memory management, and what you're drawing that's different during the rotation.
(Also, FWIW, I don't think you should be calling RenderBufferStorage every time you bind the render buffer(s). You should only need to do that once when you create them. That said, I'm not sure that you shouldn't actually destroy the buffers when you change their size and just recreate them from scratch.)
I need stencil buffer on 3GS to render planar shadow, and polygon
offset won't work prefect, still has z-fighting problem. So I use
stencil buffer to make the shadow correct, it works on win32 gles2
emulator, but not on iPhone. After I added a post effect to the whole
scene. The stencil buffer won't work even on win32 gles2 emulator.
And I tried to attach a stencil buffer to FBO, buf the screen turns to
black. Here's my code,
glGenRenderbuffers(1, &dbo); // depth buffer
glBindRenderbuffer(GL_RENDERBUFFER, dbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES,
widthGL, heightGL);
glGenRenderbuffers(1, &sbo); // stencil buffer
glBindRenderbuffer(GL_RENDERBUFFER, sbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, widthGL,
heightGL);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tex, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, dbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, sbo); // this make the whole screen black.
The eglContext is created with STENCIL_SIZE=8, it works without a RTT.
I tried to change the RenderbufferStorage for both depth buffer and
stencil buffer, but none of them works.
Is there anything I have missed? Does the stencil buffer pack with
depth buffer? (I cannot find things like GL_DEPTH24_STENCIL8 ...)
In OpenGL ES 2.0 on iOS, you have to create a combined depth and stencil renderbuffer using GL_DEPTH24_STENCIL8_OES, and then attach it to the bound framebuffer as both GL_DEPTH_ATTACHMENT and GL_STENCIL_ATTACHMENT.
glGenRenderbuffers(1, &depthStencilRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthStencilRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilRenderbuffer);
Just a note, if you are using GLKView, it is as simple as
view.drawableStencilFormat = GLKViewDrawableStencilFormat8;
where view is: GLKView*