Marrying Core Animation with OpenGL ES

Edit: I suppose instead of the long explanation below I might also ask: Sending -setNeedsDisplay to an instance of CAEAGLLayer does not cause the layer to redraw (i.e., -drawInContext: is not called). Instead, I get this console message:

<GLLayer: 0x4d500b0>: calling -display has no effect.

Is there a way around this issue? Can I invoke -drawInContext: when -setNeedsDisplay is called? Long explanation below:

  • Getting default frame buffer id from GLKView/GLKit
  • OpenGL ES color picking on the iPhone
  • Dot Product and Luminance/ Findmyicone
  • Floating point textures in OpenGL ES 2.0 on iOS without clamping them to
  • OpenGL ES Shaders and 64-bit iPhone 5S
  • How do I apply proper perspective to this OpenGL ES texture?

  • I have an OpenGL scene that I would like to animate using Core Animation animations.

    Following the standard approach to animate custom properties in a CALayer, I created a subclass of CAEAGLLayer and defined a property sceneCenterPoint in it whose value should be animated. My layer also holds a reference to the OpenGL renderer:

    #import <UIKit/UIKit.h>
    #import <QuartzCore/QuartzCore.h>
    #import "ES2Renderer.h"
    @interface GLLayer : CAEAGLLayer
        ES2Renderer *renderer;
    @property (nonatomic, retain) ES2Renderer *renderer;
    @property (nonatomic, assign) CGPoint sceneCenterPoint;

    I then declare the property @dynamic to let CA create the accessors, override +needsDisplayForKey: and implement -drawInContext: to pass the current value of the sceneCenterPoint property to the renderer and ask it to render the scene:

    #import "GLLayer.h"
    @implementation GLLayer
    @synthesize renderer;
    @dynamic sceneCenterPoint;
    + (BOOL) needsDisplayForKey:(NSString *)key
        if ([key isEqualToString:@"sceneCenterPoint"]) {
            return YES;
        } else {
            return [super needsDisplayForKey:key];
    - (void) drawInContext:(CGContextRef)ctx
        self.renderer.centerPoint = self.sceneCenterPoint;
        [self.renderer render];

    (If you have access to the WWDC 2009 session videos, you can review this technique in session 303 (“Animated Drawing”)).

    Now, when I create an explicit animation for the layer on the keyPath @"sceneCenterPoint", Core Animation should calculate the interpolated values for the custom properties and call -drawInContext: for each step of the animation:

    - (IBAction)animateButtonTapped:(id)sender
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"sceneCenterPoint"];
        animation.duration = 1.0;
        animation.fromValue = [NSValue valueWithCGPoint:CGPointZero];
        animation.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0f, 1.0f)];
        [self.glView.layer addAnimation:animation forKey:nil];

    At least that is what would happen for a normal CALayer subclass. When I subclass CAEAGLLayer, I get this output on the console for each step of the animation:

    2010-12-21 13:59:22.180 CoreAnimationOpenGL[7496:207] <GLLayer: 0x4e0be20>: calling -display has no effect.
    2010-12-21 13:59:22.198 CoreAnimationOpenGL[7496:207] <GLLayer: 0x4e0be20>: calling -display has no effect.
    2010-12-21 13:59:22.216 CoreAnimationOpenGL[7496:207] <GLLayer: 0x4e0be20>: calling -display has no effect.
    2010-12-21 13:59:22.233 CoreAnimationOpenGL[7496:207] <GLLayer: 0x4e0be20>: calling -display has no effect.

    So it seems that, possibly for performance reasons, for OpenGL layers, -drawInContext: is not getting called because these layers do not use the standard -display method to draw themselves. Can anybody confirm that? Is there a way around it?

    Or can I not use the technique I laid out above? This would mean I would have to implement the animations manually in the OpenGL renderer (which is possible but not as elegant IMO).

    2 Solutions Collect From Internet About “Marrying Core Animation with OpenGL ES”

    Have you tried making a parent layer above the OpenGL layer and animating that instead?

    You can override display instead of drawInContext. During the animation, the animated value is in the presentation layer.

    - (void) display
        GLLayer* myPresentationLayer = (GLLayer*)[self presentationLayer];
        self.renderer.centerPoint = myPresentationLayer.sceneCenterPoint;
        [self.renderer render];

    At the end the presentation layer will have the model layer value, so you’ll need to set the final value on the model layer before starting the animation.