将核心动画与OpenGL ES相结合

11

编辑:我想,与其在下面做长篇解释,不如直接问:向CAEAGLLayer的实例发送-setNeedsDisplay并不会导致该图层重新绘制(即不会调用-drawInContext:)。相反,我会收到这条控制台消息:

<GLLayer: 0x4d500b0>: calling -display has no effect.
有没有方法可以解决这个问题?当调用-setNeedsDisplay时,我能否调用-drawInContext:来绘制图形呢?以下是详细说明:
我有一个OpenGL场景,我想使用Core Animation动画来进行动态效果。
按照在CALayer中动画自定义属性的标准方法,我创建了一个CAEAGLLayer子类,并在其中定义了一个名为sceneCenterPoint的属性,其值应该被动态地修改。我的层也持有对OpenGL渲染器的引用:
#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;

我接着声明属性@dynamic,让CA创建访问器,重写+needsDisplayForKey:方法,并实现-drawInContext:方法以将sceneCenterPoint属性的当前值传递给渲染器并要求它呈现场景:

#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];
}
...

(如果您可以访问WWDC 2009会议视频,则可以在303号会议("Animated Drawing")中查看此技术的详细信息)。

现在,当我为键路径 @"sceneCenterPoint" 上的层创建显式动画时,核心动画应计算自定义属性的插值并在每个动画步骤中调用-drawInContext:

- (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];
}

至少对于普通的CALayer子类来说是这样。当我子类化CAEAGLLayer时,在每个动画步骤中都会在控制台上输出以下内容:

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.
...
所以看起来可能是出于性能原因,对于OpenGL图层,-drawInContext:没有被调用,因为这些图层不使用标准的-display方法来绘制自己。有人可以确认吗?有没有办法解决呢?
或者我不能使用我上面提出的技术吗?这意味着我必须在OpenGL渲染器中手动实现动画(这是可能的,但在我看来不太优雅)。
2个回答

6

你可以覆盖display而不是drawInContext。在动画期间,动画值位于呈现层中。

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

在最后,演示层将拥有模型层的值,因此在启动动画之前,您需要在模型层设置最终值。

很好的建议,Jeff,谢谢。我尝试了一下,这种方法也行。就性能而言,它似乎与Dad的想法差不多。 - Ole Begemann

4
你尝试过在OpenGL层之上创建一个父层,并对其进行动画处理吗?

谢谢您的建议。我会尝试并回报结果。 - Ole Begemann
确实是这样的,非常感谢!性能似乎不如纯OpenGL解决方案,但我很快会写一篇关于具体细节的博客文章。 - Ole Begemann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接