Drawing with GLKit

14,554

Solution 1

I don't see anything in your setup code that loads your shaders - I presume you are doing this somewhere in your code?

In addition, in your setup code, you are creating your framebuffer. The GLKView does this for you - indeed you are telling the view to use a 24-bit depthbuffer in your viewDidLoad method:

GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;

So what your glkView:drawInRect: code above is doing is saying: "Bind my handmade framebuffer, and draw some stuff into it". The GLKView then automatically presents itself, but nothing has been drawn into it, you've only drawn into your handmade buffer. Unless you need additional framebuffer objects for tasks such as rendering to texture, then you don't need to concern yourself with framebuffer creation at all - let the GLKView do it automatically.

What you should be doing in your setupGL method (or anywhere you like in the setup) is creating your vertex array object(s) that remember the openGL state required to perform a draw. Then, in the glkView:drawInRect: method you should:

  1. Clear using glClear().
  2. Enable your program.
  3. Bind the vertex array object (or, if you didn't use a VAO, enable the appropriate vertex attrib pointers).
  4. Draw your data using glDrawArrays() or glDrawElements().

The GLKView automatically sets its context as current, and binds its framebuffer object before each draw cycle.

Perhaps try to think of GLKView more like a regular UIView. It handles most of the openGL code behind the scenes for you, leaving you to simply tell it what it needs to draw. It has its drawRect: code just like a regular UIView - with a regular UIView in drawRect: you just tell it what it should draw, for example using Core Graphics functions - you don't then tell it to present itself.

The GLKViewController is then best thought of as handling the mechanics of the rendering loop behind the scenes. You don't need to implement the timers, or even worry about pausing the animation on your application entering the background. You just need to override the update or glkViewControllerUpdate: method (depending on whether you're subclassing or delegating) to update the state of the openGL objects or view matrix.

Solution 2

I made a post about the way to set up a basic project template using GLKit. You can find it here:

Steve Zissou's Programming Blog

Share:
14,554

Related videos on Youtube

botptr
Author by

botptr

Updated on June 04, 2022

Comments

  • botptr
    botptr about 2 years

    I am trying to write a game using opengl, but I am having a lot of trouble with the new glkit classes and the default template from iOS.

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    
        if (!self.context) {
            NSLog(@"Failed to create ES context");
        }
    
        if(!renderer)
            renderer = [RenderManager sharedManager];
        tiles = [[TileSet alloc]init];
    
        GLKView *view = (GLKView *)self.view;
        view.context = self.context;
        view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    
        [self setupGL];
    }
    
    - (void)setupGL
    {
        int width = [[self view] bounds].size.width;
        int height = [[self view] bounds].size.height;
    
        [EAGLContext setCurrentContext:self.context];
    
        self.effect = [[GLKBaseEffect alloc] init];
        self.effect.light0.enabled = GL_TRUE;
        self.effect.light0.diffuseColor = GLKVector4Make(0.4f, 0.4f, 0.4f, 1.0f);
    
        //Configure Buffers
        glGenFramebuffers(1, &framebuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    
        glGenRenderbuffers(2, &colourRenderBuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, colourRenderBuffer);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, width, height);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colourRenderBuffer);
    
        glGenRenderbuffers(3, &depthRenderBuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderBuffer);
    
        //Confirm everything happened awesomely
        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
        if(status != GL_FRAMEBUFFER_COMPLETE) {
            NSLog(@"failed to make complete framebuffer object %x", status);
        }
    
        glEnable(GL_DEPTH_TEST);
    
        // Enable the OpenGL states we are going to be using when rendering
        glEnableClientState(GL_VERTEX_ARRAY);
    
    }
    
    - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
    {
        glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
    
    
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    
    
        float iva[] = {
            0.0,0.0,0.0,
            0.0,1.0,0.0,
            1.0,1.0,0.0,
            1.0,0.0,0.0,
        };
    
        glVertexPointer(3, GL_FLOAT, sizeof(float) * 3, iva);
    
        glDrawArrays(GL_POINTS, 0, 4);
    
    }
    @end
    

    With this the buffer clears(to a grey colour), but nothing from the vertex array renders. I have no idea what to do from here and due to the age of the technology there is not much information available on how to properly use glkit.

  • botptr
    botptr over 12 years
    I have seen and tried this before, but xcode refuses to compile. with the message. 'EAGLContext' for instance message does not declare a method with selector 'presentRenderbuffer:'
  • botptr
    botptr over 12 years
    Importing QuartzCore fixed my build issue, but I am still not managing to draw anything.
  • Stuart
    Stuart over 12 years
    In GLKit, the GLKView will automatically present itself and discard unneeded renderbuffers at the end of each rendering cycle. This is not the problem with the code. See my answer for details.
  • Brad Larson
    Brad Larson over 12 years
    This is incorrect. You still need to provide shaders if working with OpenGL ES 2.0 (used for the default OpenGL ES template) and a GLKView. Some default effects are available, but you have to set them up in GLKit using GLKBaseEffect and the like. None of that is present in the above code.
  • Sagar Ranglani
    Sagar Ranglani over 12 years
    Yes you are right in some sense, we'll setup these parameters using GLKit's GLKBaseEffect. My point here is that "You do not have to involve yourself writing the shaders explicitly if you wish to use basic pipeline.