需求:通過 layer 層,實現透視效果。
參考地址:http://geeklu.com/2012/07/ios-3d-perspective/,http://blog.sina.com.cn/s/blog_71715bf801019ut9.html
先看一下原始界面:
經過 rotate 之後:
- (void)viewDidLoad
{
[superviewDidLoad];
CATransform3D rotate = CATransform3DMakeRotation(M_PI/3, 1, 0, 0);
_imageView.layer.transform = rotate;
}
可以看到,iOS 自帶的方法中,是通過做正交投影做的 rotate。
通過下面的方法,可以實現透視投影的效果:
CATransform3D CATransform3DMakePerspective(CGPoint center, float disZ)
{
CATransform3D transToCenter = CATransform3DMakeTranslation(-center.x, -center.y, 0);
CATransform3D transBack = CATransform3DMakeTranslation(center.x, center.y, 0);
CATransform3D scale = CATransform3DIdentity;
scale.m34 = -1.0f/disZ;
return CATransform3DConcat(CATransform3DConcat(transToCenter, scale), transBack);
}
CATransform3D CATransform3DPerspect(CATransform3D t, CGPoint center, float disZ)
{
return CATransform3DConcat(t, CATransform3DMakePerspective(center, disZ));
}
CATransform3DPerspect 的作用:(摘自 http://blog.sina.com.cn/s/blog_71715bf801019ut9.html)
這個函數的實現原理要參考計算機圖形學的3D變換部分。接口的含義,center指的是相機的位置,相機的位置是相對於要進行變換的CALayer的來說的,原點是CALayer的anchorPoint在整個CALayer的位置,例如CALayer的大小是(100, 200), anchorPoint值爲(0.5, 0.5),此時anchorPoint在整個CALayer中的位置就是(50, 100),正中心的位置。傳入透視變換的相機位置爲(0, 0),那麼相機所在的位置相對於CALayer就是(50, 100)。如果希望相機在左上角,則需要傳入(-50, -100)。disZ表示的是相機離z=0平面(也可以理解爲屏幕)的距離。
CATransform3DPerspect 的使用:
- (void)viewDidLoad
{
[superviewDidLoad];
CATransform3D rotate = CATransform3DMakeRotation(M_PI/3, 1, 0, 0);
_imageView.layer.transform = CATransform3DPerspect(rotate, CGPointMake(0, 0), 200);
}
效果圖:
現在上面的方法實現了透視效果,接着還需要解決另外兩個問題:
- 如何以視圖的最下方的邊爲軸旋轉
- 透視效果不要那麼明顯
先來看一下如何設置透視效果的強弱
參考:http://geeklu.com/2012/07/ios-3d-perspective
http://blog.sina.com.cn/s/blog_620bf89501011fl8.html
http://blog.sina.com.cn/s/blog_620bf89501011g7n.html
由上面的信息可知,將 z 值設置大一些,這透視效果就相對弱一些,如將 z 設置爲 1000
- (void)viewDidLoad
{
[superviewDidLoad];
CATransform3D rotate = CATransform3DMakeRotation(M_PI/3, 1, 0, 0);
_imageView.layer.transform = CATransform3DPerspect(rotate, CGPointMake(0, 0), 1000);
}
效果圖如下
要實現繞固定邊旋轉,只需要調整 layer 的 anchorPoint 就行了
- (void)viewDidLoad
{
[superviewDidLoad];
CALayer *layer = [_imageView layer];
CGPoint oldAnchorPoint = layer.anchorPoint;
[layer setAnchorPoint:CGPointMake(0.5, 1.0)];
[layer setPosition:CGPointMake(layer.position.x + layer.bounds.size.width * (layer.anchorPoint.x - oldAnchorPoint.x), layer.position.y + layer.bounds.size.height * (layer.anchorPoint.y - oldAnchorPoint.y))];
CATransform3D rotate = CATransform3DMakeRotation(M_PI/3, 1, 0, 0);
_imageView.layer.transform = CATransform3DPerspect(rotate, CGPointMake(0, 0), 1000);
}
下面再把 disZ 設置爲 100,看看效果
上圖中的圖片繞着底邊旋轉了 60 度,按照勾股定理,上面的邊應該是靠在綠色的邊上的,但爲什麼差這麼多呢?看一下下面這張圖:
由於我移動了 anchorPoint,如上圖,現在的觀察點在 eye1 上面。以 yz 面上的點爲例,在 eye2 處,紅色矩形在 xy 面上的投影爲 A 點,這也就是爲什麼旋轉之後,矩形在綠色線條下面的原因了。ok,現在把 eye1 往上移動到視圖中心即可。
- (void)viewDidLoad
{
[superviewDidLoad];
CALayer *layer = [_imageView layer];
CGPoint oldAnchorPoint = layer.anchorPoint;
[layer setAnchorPoint:CGPointMake(0.5, 1)];
[layer setPosition:CGPointMake(layer.position.x + layer.bounds.size.width * (layer.anchorPoint.x - oldAnchorPoint.x), layer.position.y + layer.bounds.size.height * (layer.anchorPoint.y - oldAnchorPoint.y))];
CATransform3D rotate = CATransform3DMakeRotation(M_PI/180.0*60.0, 1, 0, 0);
_imageView.layer.transform = CATransform3DPerspect(rotate, CGPointMake(0, -90), 100);
}