代码之家  ›  专栏  ›  技术社区  ›  Kristopher Johnson

尝试在核心动画中使用透视转换失败

  •  4
  • Kristopher Johnson  · 技术社区  · 15 年前

    我正在尝试创建一个简单的iPhone应用程序,它显示一张下面有反射的图片,我想使用核心动画围绕X轴旋转图片。

    我首先使用“基于视图的应用程序”模板创建了一个新的iPhone应用程序。我添加了一个“picture.jpg”图像文件,然后将其添加到视图控制器:

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

    这个 几乎 作品。问题是主图像的旋转和反射没有完全同步。它非常接近完美,但图片底部和反射顶部的边缘相距几个像素。它们似乎有几度的不同。

    在屏幕的左侧,反射似乎位于图片的“前面”,在右侧,反射位于图片的后面。换言之,顶部图像的下角似乎被推向屏幕,而反射的上角则被拉向查看器。这是真的,无论是在看前方和后方的图像,因为他们旋转。

    如果我增加 zDistance 效果不太明显。如果我离开 transform.m34 两层均等于零,则图像和反射看起来完全同步。所以我不认为这个问题与时间同步问题有关。

    我怀疑我的透视图转换遗漏了一些东西,但我不知道如何确定出了什么问题。我想我基本上在做与 this related Stack Overflow question .

    有人能帮忙吗?

    2 回复  |  直到 14 年前
        1
  •  3
  •   Kristopher Johnson    14 年前

    我想我可能找到了我问题的答案。在我的原始代码中,我通过将反射放置在图片下面并应用翻转和透视来创建反射。正确的方法似乎是将反射放置在与图片相同的位置,应用平移和旋转变换将其放置到正确的位置,然后应用透视变换。

    在设置旋转动画时,需要将反射旋转到与图片动画相反的方向。

    所以,下面的代码是有效的:

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

    我不清楚为什么会这样。对我来说,将反射放置在与原始图像相同的位置,然后对其进行变换,可以将这两个图像置于相同的“变换空间”,这是很直观的,但如果有人能解释这背后的数学原理,我会很感激的。

    完整项目可在Github获得: https://github.com/kristopherjohnson/perspectivetest

        2
  •  1
  •   James Eichele Bernard Igiri    15 年前

    您可以使用 CAAnimationGroup 对象在同一时间空间上运行两个动画。这应该可以解决任何同步问题。

    编辑: 删除了愚蠢的代码。

    推荐文章