2010-12-21 17 views
11

Editar: supongo en lugar de la larga explicación a continuación También podría preguntar: Envío de -setNeedsDisplay a una instancia de CAEAGLLayer no causa la capa para volver a dibujar (es decir, -drawInContext: no se llama). En su lugar, me sale este mensaje de la consola:Casarse Core Animation con OpenGL ES

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

¿Hay alguna forma de evitar este problema? ¿Puedo invocar -drawInContext: cuando se llama al -setNeedsDisplay? Larga explicación a continuación:


tengo una escena OpenGL que me gustaría para animar el uso de animaciones Core Animation.

Siguiendo el enfoque estándar para animar propiedades personalizadas en un CALayer, creé una subclase de CAEAGLLayer y definí una propiedad sceneCenterPoint en ella cuyo valor debe ser animado. Mi capa también contiene una referencia al procesador 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; 

continuación, declaro la propiedad @dynamic dejar CA crear los descriptores de acceso, anular +needsDisplayForKey: e implementar -drawInContext: para pasar el valor actual de la propiedad sceneCenterPoint al procesador y pedir que acabe con la escena:

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

(Si usted tiene acceso a los vídeos de las sesiones de la WWDC 2009, puede revisar esta técnica en la sesión 303 ("dibujo animado")).

Ahora, cuando se crea una animación explícita para la capa en la keyPath @"sceneCenterPoint", Core Animation debe calcular los valores interpolados de las propiedades personalizadas y llame -drawInContext: para cada paso de la animación:

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

Al menos eso es lo que sucedería para una subclase CALayer normal. Cuando subclase CAEAGLLayer, consigo esta salida en la consola para cada paso de la animación:

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. 
... 

Así que parece que, posiblemente por razones de rendimiento, para las capas de OpenGL, -drawInContext: no está recibiendo llamadas porque estas capas no usan el método estándar -display para dibujarse. ¿Alguien puede confirmar eso? ¿Hay alguna forma de evitarlo?

¿O no puedo usar la técnica que expuse arriba? Esto significaría que tendría que implementar las animaciones manualmente en el renderizador OpenGL (que es posible pero no tan elegante como IMO).

Respuesta

4

¿Ha intentado hacer una capa primaria sobre la capa OpenGL y animando eso en su lugar?

+0

Gracias por la sugerencia. Lo probaré e informaré. –

+0

¡De hecho funciona de esa manera, muchas gracias! El rendimiento no parece ser tan bueno como una solución pura de OpenGL, pero pronto escribiré una publicación en el blog sobre los detalles. –

6

Puede anular display en lugar de drawInContext. Durante la animación, el valor animado está en la capa de presentación.

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

Al final de la capa de presentación tendrá el valor capa del modelo, por lo que tendrá que establecer el valor final de la capa del modelo antes de iniciar la animación.

+0

Una gran sugerencia, Jeff, gracias. Lo probé y este enfoque también funciona. En cuanto a rendimiento, parece estar en el mismo estadio que la idea de papá. –

Cuestiones relacionadas