Question

Je suis en train de créer une application simple de l'iPhone qui affiche une image avec une réflexion en dessous, et je veux faire pivoter l'image autour de l'axe X, en utilisant Core Animation.

J'ai commencé par créer une nouvelle application iPhone en utilisant le modèle « Application à base de View- ». J'ai ajouté un fichier image « Picture.jpg », puis j'ai ajouté ceci au contrôleur de vue:

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

presque fonctionne. Le problème est que la rotation de l'image principale et de la réflexion ne sont pas parfaitement synchronisées. Il est très proche de la perfection, mais les bords du fond de l'image et du haut de la réflexion sont quelques pixels à part. Ils semblent différer de quelques degrés.

Sur le côté gauche de l'écran, la réflexion semble être « en avance » de l'image, et sur le côté droit, la réflexion est derrière l'image. En d'autres termes, il semble que les coins inférieurs de l'image du haut sont poussés vers l'écran, tandis que les coins supérieurs de la réflexion sont tirés vers le spectateur. Cela est vrai quand on regarde à l'avant et à l'arrière des images comme ils tournent.

Si j'augmente zDistance, l'effet est moins perceptible. Si j'élimine les transformations en perspective tout à fait en laissant transform.m34 égale à zéro pour les deux couches, l'image et l'apparence de réflexion pour être parfaitement synchronisés. Donc, je ne pense pas que le problème est lié à des problèmes de temps de synchronisation.

Je suppose que mes transformations en perspective manque quelque chose, mais je ne suis pas sûr de savoir comment déterminer ce qui est erroné. Je pense que je fais essentiellement la même transformation décrit dans cette pile liée Overflow question .

Quelqu'un peut-il aider?

Était-ce utile?

La solution

Je pense que je l'ai trouvé une réponse à ma question. Dans mon code d'origine, j'ai créé la réflexion en le plaçant sous l'image, et l'application de la bascule et la perspective. La bonne façon de le faire semble être de placer la réflexion à la même position que l'image, appliquer translation et de rotation transforme pour l'obtenir au bon endroit, et appliquer ensuite la transformation en perspective.

Lorsque vous animez le spin, il est nécessaire de tourner la réflexion dans le sens opposé de l'animation de l'image.

Alors, voici le code qui fonctionne:

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

Je ne sais pas exactement pourquoi cela fonctionne. Il est logique intuitive pour moi que placer la réflexion sur la même position que l'original et le transformant met en quelque sorte les deux images dans le même « espace de transformation », mais je vous en serais reconnaissant si quelqu'un pourrait expliquer les mathématiques derrière tout cela.

Le projet complet est disponible sur GitHub: https://github.com/kristopherjohnson/perspectivetest

Autres conseils

Vous pouvez utiliser un CAAnimationGroup objet d'exécuter deux animations sur le même espace de temps. Cela devrait prendre soin de tous les problèmes de synchronisation.

EDIT:. Code enlevé stupide

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top