【iOS】用Layer创建一个三维模型以及拖动
来源:互联网 发布:java中空格怎么表示 编辑:程序博客网 时间:2024/06/08 11:59
关于CALayer的介绍以及基本属性,在这篇博客中有交代:CoreAnimation —— CALayer
这篇博客讲述简单的通过对layer的transform属性的设置一个CATransform3D来进行自定义三维图形,甚至后续的处理。
通常简单的仿射变换我们也是通过对其的transform属性进行设置。不过这里设置的是一个3D变换类。如果线性代数很好的话,那应该能够理解内部具体做了如何的矩阵运算。
首先我子类化一个UIView对象,把图形的绘制在这个自定义View上进行。
接口方面
@property (nonatomic, assign, readonly) CGFloat side;@property (nonatomic, assign, readonly) BOOL autoAnimate;/** * 创建一个正方体对象 * * @param frame 位置 * @param side 边长 * @param animate 创建后是否自动旋转展示 * * @return 正方体对象视图 */+ (HRCube *)cube3DWithFrame:(CGRect)frame side:(CGFloat)side autoAnimate:(BOOL)animate;
工厂方法的实现就是快速实例化并设置属性
+ (HRCube *)cube3DWithFrame:(CGRect)frame side:(CGFloat)side autoAnimate:(BOOL)animate{ HRCube *cube3D = [[HRCube alloc] initWithFrame:frame]; cube3D.side = side; cube3D.autoAnimate = animate; return cube3D;}
类别中有两个内部成员
CALayer *_cubeLayer;//main layer
GLKMatrix4 _rotMatrix;
第一个是我们需要绘制正方体的layer。
第二个是在导入GLKit框架后,从中引入的一个矩阵变换类,我们在触摸屏幕拖动时,需要使用到这个类对正方体进行旋转处理。
初始化主layer
- (id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { _cubeLayer = [CALayer layer]; _cubeLayer.frame = self.bounds; _cubeLayer.contentsScale = [UIScreen mainScreen].scale; } return self;}
正式绘制正方体
- (void)setSide:(CGFloat)side{ _side = side; // NSLog(@"%@", NSStringFromCGRect(_cubeLayer.bounds)); //正 [self addCubeLayer:@[@0, @0, @(_side/2), @0, @0, @0, @0]]; //背 [self addCubeLayer:@[@0, @0, @(-_side/2), @(M_PI), @0, @0, @0]]; //左 [self addCubeLayer:@[@(-_side/2), @0, @0, @(-M_PI_2), @0, @1, @0]]; //右 [self addCubeLayer:@[@(_side/2), @0, @0, @(M_PI_2), @0, @1, @0]]; //上 [self addCubeLayer:@[@0, @(-_side/2), @0, @(-M_PI_2), @1, @0, @0]]; //下 [self addCubeLayer:@[@0, @(_side/2), @0, @(M_PI_2), @1, @0, @0]]; CATransform3D transform3D = CATransform3DIdentity; transform3D.m34 = -1.0/2000; _cubeLayer.sublayerTransform = transform3D; [self.layer addSublayer:_cubeLayer];}
这里的m34不是星体- -,3D变形矩阵的m34通常应该设置为-1/EYE_DISTANCE,这里设置为2000已经足够好。
addCubeLayer的实现
//添加sublayers- (void)addCubeLayer:(NSArray *)params{ CAGradientLayer *gradient = [CAGradientLayer layer]; gradient.contentsScale = [UIScreen mainScreen].scale; gradient.bounds = CGRectMake(0, 0, _side, _side); gradient.position = self.center; gradient.colors = @[(id)kGrayColor, (id)kBlackColor]; gradient.locations = @[@0, @1]; gradient.startPoint = CGPointMake(0, 0); gradient.endPoint = CGPointMake(0, 1); //抗锯齿 gradient.shouldRasterize = YES; CATransform3D trans3D = CATransform3DMakeTranslation([params[0] floatValue], [params[1] floatValue], [params[2] floatValue]); CATransform3D rotate3D = CATransform3DRotate(trans3D , [params[3] floatValue], [params[4] floatValue], [params[5] floatValue], [params[6] floatValue]); CATransform3D transform3D = rotate3D;// CATransform3D transform3D = CATransform3DRotate(trans3D, [params[3] floatValue], [params[4] floatValue], [params[5] floatValue], [params[6] floatValue]); gradient.transform = transform3D; [_cubeLayer addSublayer:gradient];}
这里为了更方便观察,使用的是渐变Layer,颜色为宏,可以自由修改。
注意给其抗锯齿设为了YES。通常我们还可以在整个项目的info.plist文件中设置该内容,不过设置会对整个项目的性能产生不好的影响,所以一般来说,需要的时候再设置也是一个不错的选择。
这样我们就简单的创建好了一个正方体,不过当前摆放很正,所以只能看到一个正方形平面,下面我们给他设置自动旋转后给他一个沿着坐标轴的角度偏转,再无限围着y轴转就OK了。
//添加自定义旋转展示动画- (void)addAnimation{ _cubeLayer.sublayerTransform = CATransform3DRotate(_cubeLayer.sublayerTransform, M_PI/9.0, 0.5, 0.5, 0.5); CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.rotation.y"]; animation.toValue = @(MAXFLOAT); animation.duration = MAXFLOAT; [_cubeLayer addAnimation:animation forKey:@"rotation"];}
这时运行程序我们就能看到一个旋转的三维正方体了
下面给其扩展一个拖动收拾旋转功能
首先给view增加一个拖动收拾,然后在Action中实现
#pragma mark - PanGesture- (void)panRotate:(UIPanGestureRecognizer *)ges{ static CGPoint start; if (ges.state == UIGestureRecognizerStateBegan) { start = [ges locationInView:self]; } else if (ges.state == UIGestureRecognizerStateChanged) { CATransform3D transform = _cubeLayer.sublayerTransform; _rotMatrix = GLKMatrix4MakeWithArray((void *)&transform); CGPoint loc = [ges locationInView:self]; CGPoint diff = CGPointMake(start.x-loc.x, start.y-loc.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); _cubeLayer.sublayerTransform = *((CATransform3D *)&_rotMatrix); start = loc; }}
经过对矩阵的实时处理后,我们可以使用拖动收拾来在视图中实时的调整3D正方体的旋转了。
Demo源码:
CSDN:点击打开链接
GitHub:Rannie / HRCube3D
喜欢的话可以去点个星:)
以上就是本篇博客全部内容,欢迎指正和交流。转载注明出处~
- 【iOS】用Layer创建一个三维模型以及拖动
- IOS显示三维模型
- 加载一个三维模型
- OpenInventor实现三维模型的拖动
- 创建一个三维数组
- 创建一个三维数组
- 创建一个三维球体
- iOS中View和layer的区别以及layer用法
- iOS 实现拖动一个view
- 创建layer时遇到的一个问题
- android使用layer-list创建一个边框
- c++中创建一个三维数组
- wpf中给一个三维模型设置多种材质效果
- unity鼠标拖动三维物体
- iOS核心动画之CALayer-layer的创建
- caffe finetuning时从源模型到目的模型:将一个layer的参数赋予到多个layer
- ios Scenekit三维开发以及外接SpriteKit二维界面开发
- cocos2d之,创建一个有背景颜色的layer
- Google Interview Preparation
- 设计模式之责任链(Chain of Responsibility)
- 代码覆盖率浅谈
- Eclipse使用技巧总结(三)
- 超级求爱程序--为我们的程序工作找乐子
- 【iOS】用Layer创建一个三维模型以及拖动
- Ibatis调用存储过程实现增删改以及分页查询
- 增加内核系统调用
- Leetcode: Single Number
- 13年12月校赛总结
- 抽象类和接口 引用整理。
- Android Service学习之本地服务
- arm寻址与简单指令
- 求坛子网友们提供一个性价比高的PCB 工厂,S5PV210 的金手指核心板要拿去批量生产。