问题 将核心动画与OpenGL ES结合在一起


编辑: 我想我可能也会问:发送,而不是下面的长篇解释 -setNeedsDisplay 到一个实例 CAEAGLLayer 不会导致图层重绘(即 -drawInContext: 不叫)。相反,我得到这个控制台消息:

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

有没有解决这个问题的方法?我可以调用吗? -drawInContext: 什么时候 -setNeedsDisplay 叫做?下面详细解释:


我有一个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(“动画制图”)中查看此技术)。

现在,当我在keyPath上为图层创建显式动画时 @"sceneCenterPoint",Core Animation应计算自定义属性和调用的插值 -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渲染器中手动实现动画(这是可能的,但不是优雅的IMO)。


6955
2017-12-21 15:13


起源



答案:


您是否尝试在OpenGL图层上方创建父图层并为其设置动画?


4
2017-12-27 01:48



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


答案:


您是否尝试在OpenGL图层上方创建父图层并为其设置动画?


4
2017-12-27 01:48



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


你可以覆盖 display 代替 drawInContext。在动画期间,动画值位于表示层中。

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

最后,表示层将具有模型图层值,因此您需要在开始动画之前在模型图层上设置最终值。


6
2018-01-05 21:49



很好的建议,杰夫,谢谢。我试了一下,这种方法也有效。在性能方面,它似乎和爸爸的想法一样。 - Ole Begemann