Редактировать: Полагаю, вместо длинного объяснения, приведенного ниже, я также могу спросить: отправка -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
средству визуализации и попросить его отрендерить сцену: 1027 *
#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).