OpenGL ES1 perspective with depth buffer fails. Clearing the colour is fine.
Hello. I'm trying to set up the projection matrix for 3D graphics. Easy enough in normal OpenGL programming but not here for some reason.
I've taken the default OpenGL template and I removed the ES2 code and transferred parts of the ES1 renderer class to the EAGLView class and that worked fine. Everything broke after trying to use the depth buffer. Clearing the colour works okay but the square wont render when using a viewing frustrum.
Here's the current EAGLView class. The code gives a red screen and no square:
Code:
//
// EAGLView.m
// iPhone Monkey Curling
//
// Created by Matthew Mitchell on 18/08/2010.
// Copyright __MyCompanyName__ 2010. All rights reserved.
//
#import "EAGLView.h"
@implementation EAGLView
@synthesize animating;
@dynamic animationFrameInterval;
// You must implement this method
+ (Class) layerClass{
return [CAEAGLLayer class];
}
//The EAGL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
- (id) initWithCoder:(NSCoder*) coder{
if ((self = [super initWithCoder:coder]))
{
// Get the layer
CAEAGLLayer *eaglLayer = (CAEAGLLayer *) self.layer;
eaglLayer.opaque = TRUE;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
animating = FALSE;
displayLinkSupported = FALSE;
displayLink = nil;
animationTimer = nil;
// A system version of 3.1 or greater is required to use CADisplayLink. The NSTimer
// class is used as fallback when it isn't available.
NSString *reqSysVer = @"3.1";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
displayLinkSupported = TRUE;
}
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!context || ![EAGLContext setCurrentContext:context])
{
[self release];
return nil;
}
// Create default framebuffer object.
glGenFramebuffersOES(1, &defaultFramebuffer);
glGenRenderbuffersOES(1, &colourRenderbuffer);
glGenRenderbuffersOES(1, &depthRenderbuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colourRenderbuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colourRenderbuffer);
//Initialisation code for the game's graphics and to develop the scene
//glEnable(GL_CULL_FACE);
//glCullFace(GL_FRONT);
glMatrixMode(GL_MODELVIEW); //Select The Modelview Matrix
glLoadIdentity();
glEnable(GL_DEPTH_TEST); //Enables Depth Testing
glClearColor(1, 0, 0, 1);
return self;
}
- (void) drawView:(id) sender{
static const GLfloat squareVertices[] = {
5, 5,5,
-5, 5,5,
5, -5,5,
-5, -5,5,
};
static const GLubyte squarecolours[] = {
0,0,200,255,
40,90,250,255,
0,0,200,255,
50,100,230,255,
};
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glVertexPointer(3, GL_FLOAT, 0, squareVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, squarecolours);
glEnableClientState(GL_COLOR_ARRAY);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
- (void) layoutSubviews{
// Allocate colour buffer backing based on the current layer size
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colourRenderbuffer);
[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);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
//Setup projection matrix
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double xmax = 0.04142135624 * ((float) backingWidth)/backingHeight;
glFrustumf(-xmax, xmax, -0.04142135624, 0.04142135624, 0.1, 2000); //The ymax and min have been precalculated
//Re-bind colour buffer for rendering
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colourRenderbuffer);
//Check framebuffer
if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
{
NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) );
}
[self drawView:nil];
}
- (void) startAnimation{
if (!animating)
{
if (displayLinkSupported)
{
// CADisplayLink is API new to iPhone SDK 3.1. Compiling against earlier versions will result in a warning, but can be dismissed
// if the system version runtime check for CADisplayLink exists in -initWithCoder:. The runtime check ensures this code will
// not be called in system versions earlier than 3.1.
displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(drawView:) ];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
else
animationTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval) 0.03333333333 target:self selector:@selector(drawView:) userInfo:nil repeats:TRUE];
animating = TRUE;
}
}
- (void) stopAnimation{
if (animating)
{
if (displayLinkSupported)
{
[displayLink invalidate];
displayLink = nil;
}
else
{
[animationTimer invalidate];
animationTimer = nil;
}
animating = FALSE;
}
}
- (void) dealloc{
// Tear down GL
if (defaultFramebuffer)
{
glDeleteFramebuffersOES(1, &defaultFramebuffer);
defaultFramebuffer = 0;
}
if (colourRenderbuffer)
{
glDeleteRenderbuffersOES(1, &colourRenderbuffer);
colourRenderbuffer = 0;
}
if (depthRenderbuffer)
{
glDeleteRenderbuffersOES(1, &depthRenderbuffer);
depthRenderbuffer = 0;
}
// Tear down context
if ([EAGLContext currentContext] == context)
[EAGLContext setCurrentContext:nil];
[context release];
context = nil;
[super dealloc];
}
@end
i don't have this code in "layoutSubviews" i have it in "resizeFromLayer" and those two lines are swapped in my code. if you think about it, you need your storage before you attach it! i don't know if this will solve all your problems, but it should help.
Thank you for the reply. I have noticed and changed that myself but I still can't get it working.
I have changed quite a bit since. I will update my code on the first post and change the information to reflect the current situation.
I didn't want to use ES2 which is why I moved all the rendering code into the EAGLView class because the rendering classes aren't needed if I'm just to have one ES version.
Remember, the code worked when I moved the code into the EAGLView class, it s just the depth which is the problem at the moment.
Thank you for the reply. I have noticed and changed that myself but I still can't get it working.
I have changed quite a bit since. I will update my code on the first post and change the information to reflect the current situation.
I didn't want to use ES2 which is why I moved all the rendering code into the EAGLView class because the rendering classes aren't needed if I'm just to have one ES version.
Remember, the code worked when I moved the code into the EAGLView class, it s just the depth which is the problem at the moment.
Thank you again.
i don't use es 2.0, just 1.1. and i take the part out of the template which tries to instantiate an es 2.0 renderer and just make the 1.1 renderer. i know that gives a whole nother stack frame and like 30+ cycles per frame as well as a small, annoying, permanent little memory hole on the heap (which may eventually cause fragmentation, but hasn't yet caused me any problems), but i think it's just easier and i'm too lazy to write my own gl context allocator template from scratch. and you're right, it should work, but to me, the lack of solid documentation makes me feel like it's black magic. so...i try to stay out of its way as much as possible. maybe if apple was better at documenting things like this, it would be significantly less painful. to be fair, i've seen (but can't remember where now) where people DO write up their own gl context templates from scratch for the iphone. i've never done it myself, and have definitely shied away from it on all platforms (i've used GLUT almost exclusively for desktop platforms), but it might be considered a requisite skill for any graphics programmer.
oh, btw, 16-bit depth is cheesey beyond all reason: you'll get floating point round off error based artifacts like crazy if you stick with that. 24-bit isn't MUCH better, but it IS available and will still cut down your fp round-off artifacts by a significant amount. i use it exclusively on the iphone. you might consider the same once you get your buffer working.
sorry i wasn't much help. you may find that the problem is really elsewhere anyway.
Well the problem must be with the code I posted somewhere. I just can't figure it out.
I will look into the 24 bot depth buffer, thank you.
The most annoying thing, is there are no full (All code required) examples anywhere.
Edit: Also, I recommend using Cocoa for OpenGL programming over GLUT, especially if you only want to programme for OSX anyway. Cocoa is quite easy, especially if you are used to Objective-C for iphone. It's powerful and fast. It should be considering it's an operating system API but it's also high-level and rather easy.