On-demand OpenGL ES rendering using GLKit

10,915

Solution 1

The approach I ended up using was to not bother with the GLKViewController, but just use GLKView directly under a UIViewController subclass.

Clearly, the GLKViewController is intended for use by people who need a consistent rendering loop for apps such as games. Without it, drawing to the GLKView is as simple as calling [glkView setNeedsDisplay]. Be sure to set enableSetNeedsDisplay to YES in order to enable this behaviour.

If you did still want to make use of a GLKViewController, you can disable the animation rendering loop in viewWillAppear like so:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];    // setPaused automatically set to NO in super's implementation

    [self setPaused:YES];
}

Also, set resumeOnDidBecomeActive to NO to prevent the view controller from resuming again automatically.

Using a plain UIViewController with a GLKView is perfectly acceptable however, and I have seen it recommended by an Apple engineer as an appropriate way to perform on-demand drawing.

Solution 2

I've just converted my code from using an EAGLContext manager I rolled myself to using the GLKit classes.

You suggest you might "..ignore the.. glkView:drawInRect: methods and just draw what [you] need, when I need it". This seems like a sensible option performance-wise; I assume (though haven't tried) if you simply don't specify a GLKViewDelegate or provide a subclassed GLKView with its drawInRect: defined then no animation loop rendering will occur. Have you attempted this?

The alternative would be to simply create some @property (assign, nonatomic) BOOL shouldUpdate; in your MyController : GLKViewController <GLKViewDelegate> class which will only update if there is something to do:

[self setDelegate:self]; // in init or awakeFromNib or other..

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    if ([self shouldUpdate]) { ...

I'm sure you get the idea, it's hardly complicated.

One thing worth mentioning: the official API docs state that viewDidLoad should be used in your GLKViewController for initial GL setup. I had issues with this; for some reason my glCreateShader calls always returned zero. This may have been due to my setting the EAGLContext post-initialisation; I couldn't pass it as an init parameter since I created the controller in Storyboard. However, there was nothing logically wrong with the code, so I offer this friendly warning in case you encounter similar issues. My solution is simply to have the following in my drawInRect:

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    if ([self initialGLSetupDone] == NO) {
        [self beforeFirstRender];
        [self setInitialGLSetupDone:YES];
    }
    // .. rest of render code goes here.
}

Obviously it's not ideal to have an IF in there unnecessarily, but it was an easy solution.

Let me know how it goes if you try updating to use GLKit.

Solution 3

After you have created GLKView, add this line:

glkView.enableSetNeedsDisplay = TRUE;

(Because of this, no one will redraw the view automatically)

When you want redraw, insert this line:

[glkView setNeedsDisplay];

... then drawInRect routine will be called only once.

Hope it helps.

Share:
10,915

Related videos on Youtube

Stuart
Author by

Stuart

Updated on June 04, 2022

Comments

  • Stuart
    Stuart almost 2 years

    I am looking into converting my OpenGL rendering code to take advantage of a few features of GLKit (namely the asynchronous texture loading and the automation provided by GLKView/Controller). However, it appears that the classes are designed mainly to accommodate people rendering using an animation loop, whereas I'm working with on-demand rendering. Additionally, some of the rendering is to a texture rather than the GLKView's framebuffer, so should I be looking to just subclass the GLKView and add additional FBOs?

    Is there a recommended approach for this type of setup? I would expect something along the lines of:

    • Set the view controller's preferredFramesPerSecond to 0, or just pause the frame updates?
    • Ignore the glkViewControllerUpdate or glkView:drawInRect: methods and just draw what I need, when I need it.
    • Use the view's setNeedsDisplay as with a normal UIView in order to display the frame (do I need to call bindDrawable given that I will be rendering to a texture as well?).

    Perhaps it's not worth the effort if this is not what the new API is designed for? I wish the documentation was a little more thorough than it is. Perhaps more samples will be provided when the API has 'matured' a little...

    Thanks

  • Stuart
    Stuart over 12 years
    -1. This is incorrect - setting enableSetNeedsDisplay to NO disables GLKView's setNeedsDisplay method. This property is automatically set to NO when using a GLKViewController, and so it is, in fact, required that you manually set it to YES when drawing in setNeedsDisplay "mode".
  • Stuart
    Stuart over 12 years
    With regards to the viewDidLoad issue, your EAGLContext must be set prior to creating your shaders, as you noticed yourself. There is no harm in doing this in viewDidLoad too, directly before you setup the rest of your GL code. Take a look at the 'OpenGL Game' template project in Xcode for a good example of how to perform this setup.
  • M-V
    M-V almost 12 years
    It would help if you could clarify in which methods enableSetNeedsDisplay and resumeOnDidBecomeActive need to be set as mentioned, since you did not put them in viewWillAppear(BOOL)animated. Thanks.
  • Stuart
    Stuart almost 12 years
    Set these properties when you create the view / view controller. For example, if you create your GLKViewController in code, perhaps set it on the line after your alloc/init. If you create it in interface builder, then implementing the -awakeFromNib method in your view controller might be a good place for it. In general, properties like this should be set after/as the object is created but before it is used.
  • Asela Liyanage
    Asela Liyanage over 10 years
    Do you have open source code available showing a sample of this? Thanks
  • Hari Honor
    Hari Honor over 10 years
    Thanks for the latch tip. Much easier than trying to manually draw the CAEAGLLayer or other workarounds.