Domanda

Sto cercando di creare un semplice applicazione per iPhone che consente di visualizzare una foto con una riflessione di sotto, e voglio per ruotare l'immagine attorno all'asse X, utilizzando Core Animation.

Ho iniziato con la creazione di una nuova applicazione per iPhone utilizzando il modello "View-based Application". Ho aggiunto un file di immagine "Picture.jpg", e poi ho aggiunto questo al controller della vista:

- (void)awakeFromNib {
    CGFloat zDistance = 1500.0f;

    // Create perspective transformation
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = 1.0f / -zDistance;

    // Create perspective transform for reflected layer
    CATransform3D reflectedTransform = CATransform3DMakeRotation(M_PI, 1.0f, 0.0f, 0.0f);
    reflectedTransform.m34 = 1.0f / -zDistance;

    // Create spinning picture
    CALayer *spinningLayer = [CALayer layer];
    spinningLayer.frame = CGRectMake(60.0f, 60.0f, 200.0f, 300.0f);
    spinningLayer.contents = (id)[UIImage imageNamed:@"Picture.jpg"].CGImage;
    spinningLayer.transform = transform;    

    // Create reflection of spinning picture
    CALayer *reflectionLayer = [CALayer layer];
    reflectionLayer.frame = CGRectMake(60.0f, 360.0f, 200.0f, 300.0f);
    reflectionLayer.contents = (id)[UIImage imageNamed:@"Picture.jpg"].CGImage;
    reflectionLayer.opacity = 0.4f;
    reflectionLayer.transform = reflectedTransform;

    // Add layers to the root layer
    [self.view.layer addSublayer:spinningLayer];
    [self.view.layer insertSublayer:reflectionLayer below:spinningLayer];

    // Spin the layers
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
    anim.fromValue = [NSNumber numberWithFloat:0.0f];
    anim.toValue = [NSNumber numberWithFloat:(2 * M_PI)];
    anim.duration = 3.0f;
    anim.repeatCount = 1e100f;
    [spinningLayer addAnimation:anim forKey:@"anim"];
    [reflectionLayer addAnimation:anim forKey:@"anim"];
}

Questo quasi funziona. Il problema è che la rotazione del quadro principale e della riflessione non sono perfettamente sincronizzati. E 'molto vicino a perfetto, ma i bordi della parte inferiore del quadro e della parte superiore della riflessione sono alcuni pixel a parte. Essi sembrano differire di qualche grado.

Sul lato sinistro dello schermo, la riflessione sembra essere "avanti" del quadro, e sul lato destro, la riflessione è dietro l'immagine. In altre parole, sembra che gli angoli inferiori dell'immagine superiore sono spinti verso lo schermo, mentre gli angoli superiori della riflessione sono tirati verso lo spettatore. Questo è vero sia quando si guarda la parte anteriore e nella parte posteriore delle immagini come filano.

Se io aumento zDistance, l'effetto è meno evidente. Se Elimino le trasformazioni prospettiche del tutto lasciando transform.m34 uguale a zero per entrambi gli strati, l'immagine e l'aspetto di riflessione per essere perfettamente sincronizzate. Quindi non credo che il problema è legato a questioni di tempo di sincronizzazione.

Ho il sospetto che le mie trasformazioni prospettiche manca qualcosa, ma non sono sicuro di come determinare ciò che è sbagliato. Penso che sto praticamente facendo la stessa trasformazione descritta in questo relative Stack Overflow domanda .

Può aiutare qualcuno?

È stato utile?

Soluzione

Credo di aver trovato una risposta alla mia domanda. Nel mio codice originale, ho creato il riflesso ponendolo sotto l'immagine, e applicando il flip e prospettiva. Il modo giusto per farlo sembra essere quello di collocare la riflessione nella stessa posizione come l'immagine, applicare traslazione e rotazione trasforma per farlo al posto giusto, e quindi applicare la trasformazione prospettica.

Quando animare la rotazione, è necessario girare la riflessione nella direzione opposta dell'animazione del quadro.

Quindi, ecco il codice che funziona:

- (void)awakeFromNib {
    CGFloat zDistance = 1500.0f;

    // Create perspective transformation
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = 1.0f / -zDistance;

    // Create perspective transform for reflected layer
    CATransform3D reflectedTransform = CATransform3DMakeTranslation(0.0f, 300.0f, 0.0f);
    reflectedTransform = CATransform3DRotate(reflectedTransform, M_PI, 1.0f, 0.0f, 0.0f);
    reflectedTransform.m34 = 1.0f / -zDistance;

    // Create spinning picture
    CALayer *spinningLayer = [CALayer layer];
    spinningLayer.frame = CGRectMake(60.0f, 60.0f, 200.0f, 300.0f);
    spinningLayer.contents = (id)[UIImage imageNamed:@"Picture.jpg"].CGImage;
    spinningLayer.transform = transform;    

    // Create reflection of spinning picture
    CALayer *reflectionLayer = [CALayer layer];
    reflectionLayer.frame = CGRectMake(60.0f, 60.0f, 200.0f, 300.0f);
    reflectionLayer.contents = (id)[UIImage imageNamed:@"Picture.jpg"].CGImage;
    reflectionLayer.opacity = 0.4f;
    reflectionLayer.transform = reflectedTransform;

    // Add layers to the root layer
    [self.view.layer addSublayer:spinningLayer];
    [self.view.layer insertSublayer:reflectionLayer below:spinningLayer];

    // Spin the layers
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
    anim.fromValue = [NSNumber numberWithFloat:0.0f];
    anim.toValue = [NSNumber numberWithFloat:(2 * M_PI)];
    anim.duration = 3.0f;
    anim.repeatCount = 1e100f;
    [spinningLayer addAnimation:anim forKey:@"anim"];

    CABasicAnimation *reflectAnim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
    reflectAnim.fromValue = [NSNumber numberWithFloat:0.0f];
    reflectAnim.toValue = [NSNumber numberWithFloat:(-2 * M_PI)];
    reflectAnim.duration = 3.0f;
    reflectAnim.repeatCount = 1e100f;
    [reflectionLayer addAnimation:reflectAnim forKey:@"reflectAnim"];
}

Non so esattamente il motivo per cui questo funziona. Ha senso intuitivo per me che l'inserimento del riflesso nella stessa posizione come l'originale e poi trasformarlo in qualche modo mette le due immagini nello stesso "spazio trasformazione", ma sarei grato se qualcuno potrebbe spiegare la matematica alla base di questo.

Il progetto completo è disponibile presso GitHub: https://github.com/kristopherjohnson/perspectivetest

Altri suggerimenti

È possibile utilizzare un CAAnimationGroup oggetto eseguire due animazioni sullo stesso spazio tempo. Questo dovrebbe prendersi cura di eventuali problemi di sincronizzazione.

EDIT:. codice sciocco rimosso

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top