Marrying Core Animation with OpenGL ES
Posted
by
Ole Begemann
on Stack Overflow
See other posts from Stack Overflow
or by Ole Begemann
Published on 2010-12-21T15:13:29Z
Indexed on
2010/12/27
1:53 UTC
Read the original article
Hit count: 783
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:
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).
© Stack Overflow or respective owner