iOS实现透视效果

需求:通过 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实现透视效果_第1张图片

可以看到,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);
}

效果图:

iOS实现透视效果_第2张图片

现在上面的方法实现了透视效果,接着还需要解决另外两个问题:

  • 如何以视图的最下方的边为轴旋转
  • 透视效果不要那么明显

先来看一下如何设置透视效果的强弱

参考: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

iOS实现透视效果_第3张图片

由上面的信息可知,将 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 度,按照勾股定理,上面的边应该是靠在绿色的边上的,但为什么差这么多呢?看一下下面这张图:

iOS实现透视效果_第4张图片

由于我移动了 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);
}

iOS实现透视效果_第5张图片


转载自:http://fred.easymorse.com/?p=1400

你可能感兴趣的:(ios,CAlayer)