2010-12-21 7 views
11

Edit: ich statt der langen Erklärung annehmen, unter ich auch könnte fragen: -setNeedsDisplay auf eine Instanz CAEAGLLayer Senden der Schicht nicht dazu führt, neu zu zeichnen (das heißt, wird -drawInContext: nicht genannt). Stattdessen habe ich diese Konsole Meldung:Marrying Core Animation mit OpenGL ES

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

Gibt es eine Möglichkeit, um dieses Problem? Kann ich -drawInContext: aufrufen, wenn -setNeedsDisplay aufgerufen wird? Lange Erklärung unten:


Ich habe eine OpenGL-Szene, die ich mit Core Animation Animationen animieren möchte.

Nach dem Standardansatz, benutzerdefinierte Eigenschaften in einem CALayer zu animieren, habe ich eine Unterklasse von CAEAGLLayer erstellt und eine Eigenschaft sceneCenterPoint darin definiert, deren Wert animiert werden soll. Meine Schicht hält auch einen Verweis auf die 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; 

ich die Eigenschaft @dynamic dann erklären die Accessoren lassen CA erstellen, außer Kraft setzen +needsDisplayForKey: und implementieren -drawInContext: den aktuellen Wert der sceneCenterPoint Eigenschaft an den Renderer zu übergeben und sie bitten es um die Szene zu machen:

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

(Wenn Sie den Zugriff auf die WWDC 2009 Sitzungs Videos haben, können Sie diese Technik in Session 303 ("Animated Drawing") bewertet).

Nun, wenn ich eine explizite Animation für die Schicht auf dem @"sceneCenterPoint" keyPath erstellen, Core Animation soll die interpolierten Werte für die benutzerdefinierten Eigenschaften berechnen und -drawInContext: der Animation für jeden Schritt rufen:

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

Mindestens das würde für eine normale Unterklasse CALayer passieren. Wenn ich CAEAGLLayer Unterklasse, erhalte ich diese Ausgabe auf der Konsole für jeden Schritt der 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 scheint es, dass, möglicherweise aus Leistungsgründen für OpenGL Schichten wird -drawInContext: nicht, weil immer genannt Diese Ebenen verwenden nicht die Standardmethode -display, um sich selbst zu zeichnen. Kann das jemand bestätigen? Gibt es einen Weg dahin?

Oder kann ich nicht die Technik verwenden, die ich oben dargelegt habe? Das würde bedeuten, dass ich die Animationen manuell im OpenGL-Renderer implementieren müsste (was möglich ist, aber nicht als elegantes IMO).

Antwort

4

Haben Sie versucht, eine übergeordnete Ebene über der OpenGL-Ebene zu erstellen und diese stattdessen zu animieren?

+0

Danke für den Vorschlag. Ich werde es ausprobieren und melden. –

+0

Es funktioniert in der Tat, vielen Dank! Die Leistung scheint nicht so gut zu sein wie eine reine OpenGL-Lösung, aber ich werde bald einen Blogbeitrag über die Details schreiben. –

6

Sie können display anstelle von drawInContext überschreiben. Während der Animation befindet sich der animierte Wert in der Präsentationsebene.

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

Am Ende wird die Präsentationsschicht die Modellschicht Wert haben, so dass Sie vor dem Start der Animation den Endwert auf der Modellschicht einstellen müssen.

+0

Toller Vorschlag, Jeff, danke. Ich habe es ausprobiert und dieser Ansatz funktioniert auch. Leistungsmäßig scheint es im selben Stadion wie Dads Idee zu sein. –

Verwandte Themen