我正在尝试创建一个简单的iPhone应用程序,显示下面有反射的图片,我想使用Core Animation围绕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中描述的相同转换。
有人可以帮忙吗?
答案 0 :(得分:3)
我想我可能已经找到了我的问题的答案。在我的原始代码中,我通过将其放置在图片下方并应用翻转和透视来创建反射。正确的做法似乎是将反射放置在与图片相同的位置,应用平移和旋转变换以使其到达正确的位置,然后应用透视变换。
在设置旋转动画时,需要在图片动画的相反方向旋转反射。
所以,这里的代码有效:
- (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"];
}
我不确定为什么会这样。对我来说直观的意义在于,将反射放置在与原始位置相同的位置,然后以某种方式将其转换为相同的“转换空间”,但如果有人可以解释这背后的数学,我会很感激。 / p>
完整项目可在GitHub上找到:https://github.com/kristopherjohnson/perspectivetest
答案 1 :(得分:1)
您可以使用CAAnimationGroup
对象在同一时间空间上运行两个动画。这应该解决任何同步问题。
编辑: 删除了愚蠢的代码。