Pregunta

Estoy intentando crear una aplicación simple para iPhone que muestre una imagen con un reflejo debajo y quiero rotar la imagen alrededor del eje X, usando Core Animation.

Comencé creando una nueva aplicación para iPhone usando la plantilla "Aplicación basada en vistas".Agregué un archivo de imagen "Picture.jpg" y luego agregué esto al controlador de 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"];
}

Este casi obras.El problema es que el giro de la imagen principal y el del reflejo no están perfectamente sincronizados.Es casi perfecto, pero los bordes de la parte inferior de la imagen y de la parte superior del reflejo están separados por unos pocos píxeles.Parecen diferir en algunos grados.

En el lado izquierdo de la pantalla, el reflejo parece estar "delante" de la imagen, y en el lado derecho, el reflejo está detrás de la imagen.En otras palabras, parece que las esquinas inferiores de la imagen superior son empujadas hacia la pantalla, mientras que las esquinas superiores del reflejo son atraídas hacia el espectador.Esto es cierto tanto cuando se mira el frente como el reverso de las imágenes mientras giran.

si aumento zDistance, el efecto es menos perceptible.Si elimino las transformaciones de perspectiva por completo dejando transform.m34 igual a cero para ambas capas, entonces la imagen y el reflejo parecen estar perfectamente sincronizados.Así que no creo que el problema esté relacionado con problemas de sincronización horaria.

Sospecho que a mis transformaciones de perspectiva les falta algo, pero no estoy seguro de cómo determinar qué está mal.Creo que básicamente estoy haciendo la misma transformación descrita en esta pregunta relacionada con Stack Overflow.

¿Alguien puede ayudar?

¿Fue útil?

Solución

Creo que puede haber encontrado una respuesta a mi pregunta. En mi código original, creé el reflejo colocándolo debajo de la imagen, y la aplicación de la tapa y la perspectiva. La forma correcta de hacerlo parece ser el reflejo de colocar en la misma posición que la imagen, aplicar traslación y rotación transforma para conseguir que el lugar correcto, y luego aplicar la transformación de perspectiva.

Cuando la animación de la rotación, es necesario girar el reflejo en la dirección opuesta de la animación de la imagen.

Por lo tanto, aquí está el código que funciona:

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

No estoy seguro exactamente por qué esto funciona. Tiene sentido intuitivo para mí que la colocación de la reflexión en la misma posición que el original y luego transformarlo de alguna manera pone las dos imágenes en el mismo "espacio de transformación", pero te agradecería que si alguien podría explicar las matemáticas detrás de esto.

El proyecto completo está disponible en GitHub: https://github.com/kristopherjohnson/perspectivetest

Otros consejos

Puedes usar un CAAnimationGroup objeto para ejecutar dos animaciones en el mismo espacio de tiempo.Eso debería solucionar cualquier problema de sincronización.

EDITAR: Se eliminó el código tonto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top