iOS CALayer和3D (2): 支持触摸旋转的3D正方体_移动开发_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > 移动开发 > iOS CALayer和3D (2): 支持触摸旋转的3D正方体

iOS CALayer和3D (2): 支持触摸旋转的3D正方体

 2013/11/28 23:30:24  _Mgen  博客园  我要评论(0)
  • 摘要:接上文:iOSCALayer和3D(1):定义一个简单的旋转3D立方体在上篇文章中,我们使用CALayer创建了一个可以旋转的正方体,在这篇文章中,我们为程序加入触摸事件,使这个正方体可以在用户触摸下进行任意方向的旋转:这里需要解决的问题是:CALayer的Transform实际上是对自身坐标系的Transform,但是我们需要旋转的方向和角度都是相对当前屏幕的坐标系,所以我们需要把针对当前屏幕坐标系的Transform转换成CALayer内部已经被变换坐标系的Transform
  • 标签:iOS

接上文:iOS CALayer和3D (1): 定义一个简单的旋转3D立方体

在上篇文章中,我们使用CALayer创建了一个可以旋转的正方体,在这篇文章中,我们为程序加入触摸事件,使这个正方体可以在用户触摸下进行任意方向的旋转:

屏幕快照 2013-11-28 下午7.24.02

这里需要解决的问题是:CALayer的Transform实际上是对自身坐标系的Transform,但是我们需要旋转的方向和角度都是相对当前屏幕的坐标系,所以我们需要把针对当前屏幕坐标系的Transform转换成CALayer内部已经被变换坐标系的Transform。这会涉及到一些数学矩阵上的转换。因为3D变换是通过矩阵来实现的。

 

具体变换可以参考一篇非常棒的文章:How To Rotate a 3D Object Using Touches with OpenGL

虽然上面的文章使用的是OpenGL,但是由于3D变换都是用的矩阵,所以iOS中Core Animation的CATransform3D类型和GLKit中的GLKMatrix4类型也是通用的。所以我们可以通过OpenGL提供的矩阵变换方法来完成CALayer中任意方向触摸旋转的要求。

因此,首先引用GLKit.framework:

屏幕快照 2013-11-28 下午7.29.38

接着,加入GLKMath.h,因为只需要数学相关的矩阵变化函数,所以其实只需要GLKMath.h头文件

#import <GLKit/GLKMath.h>

 

在上篇文章实现的代码基础上,删除后面的动画和添加_rootLayer时做的3D变换,仅仅设置CATransform3D的m34,然后设置_rootLayer的subLayerTransform属性,最后把_rootLayer加入到界面中:

//Layer3D变换

CATransform3D transform = CATransform3DIdentity;

transform.m34 = -1.0 / 700;

//设置CALayersublayerTransform

_rootLayer.sublayerTransform = transform;

//添加Layer

[self.view.layer addSublayer:_rootLayer];

这样,一个没有经过任何其他变换的静止正方体会显示在界面上。

然后,在UIViewController中改写UIResponder的touchesMoved方法。完成任意方向的旋转操作。

首先,需要把CATransform3D转换成GLKMatrix4,本以为可以直接转换,但是运行后出现BAD_ACCESS,所以使用GLKMatrix4MakeWithArray方法进行转换,需要把CATransform3D的指针传进去。接着使用上面文章中的方法,计算出屏幕触摸的变化并同时对GLKMatrix4进行相应的变换。最后,再把GLKMatrix4转换成CATransform3D结构体,并再次设置_rootLayer的sublayerTransform属性。

如下代码:

//改写UIViewControllertouchesMoved方法(UIViewController继承也自UIResponder

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

{

    //CATransform3D转换成GLKMatrix4

    //直接用指针转换的话会BAD_ACCESS,所以使用GLKMatrix4MakeWithArray方法

    CATransform3D caTransform3d = _rootLayer.sublayerTransform;

    GLKMatrix4 _rotMatrix = GLKMatrix4MakeWithArray((void*)&caTransform3d);

   

    //--- 来自http://www.raywenderlich.com/12667的代码 ---

    UITouch * touch = [touches anyObject];

    CGPoint location = [touch locationInView:self.view];

    CGPoint lastLoc = [touch previousLocationInView:self.view];

    CGPoint diff = CGPointMake(lastLoc.x - location.x, lastLoc.y - location.y);

   

    //把原来的-1改成1,因为坐标系的Y轴是反转的

    float rotX = 1 * GLKMathDegreesToRadians(diff.y / 2.0);

    float rotY = -1 * GLKMathDegreesToRadians(diff.x / 2.0);

   

    bool isInvertible;

    GLKVector3 xAxis = GLKMatrix4MultiplyVector3(GLKMatrix4Invert(_rotMatrix, &isInvertible),

                                                 GLKVector3Make(1, 0, 0));

    _rotMatrix = GLKMatrix4Rotate(_rotMatrix, rotX, xAxis.x, xAxis.y, xAxis.z);

    GLKVector3 yAxis = GLKMatrix4MultiplyVector3(GLKMatrix4Invert(_rotMatrix, &isInvertible),

                                                 GLKVector3Make(0, 1, 0));

    _rotMatrix = GLKMatrix4Rotate(_rotMatrix, rotY, yAxis.x, yAxis.y, yAxis.z);

    //---

   

    //GLKMatrix4转换成CATransform3D,并设置CALayersublayerTransform

    _rootLayer.sublayerTransform = *((CATransform3D*)&_rotMatrix);

}

再次运行程序,OK。

上一篇: Android RenderScript入门(1) 下一篇: 没有下一篇了!
发表评论
用户名: 匿名