SCNView如何灵活使用DAE文件
2017-01-23 17:15
260 查看
上一篇文章讲述了如何切换相机位置的问题,今天在之前的基础上讲述下自定义移动,手动转动以及点击模型中的子模型等操作。 直接讲述代码以及流程问题。首先我们需要将DAE文件拖到xcode中,还是放到scene.scnassets文件夹中。同时导入的还有iamges资源文件。
加载dae文件之前就有介绍,这里直接上代码。
//声明中间的3D背景view self.sceneView = [[QFscnView alloc]init]; _sceneView.passthroughViews = @[self.backBtn]; _sceneView.backgroundColor = QFClearColor; [self.baseImage addSubview:_sceneView]; _sceneView.sd_layout.leftSpaceToView(self.baseImage,0).topSpaceToView(self.baseImage,0).rightSpaceToView(self.baseImage,0).bottomSpaceToView(self.baseImage,0); //声明3D场景 self.scenePlace = [SCNScene sceneNamed:@"scene.scnassets/beijing_zhanting.DAE"];
我们导入的DAE文件在Xcode中是很强大的,强大到跟3D制作软件几乎相同。我们可以添加灯光,摄像头,修改三维的local坐标。不过我们正常使用的是世界坐标,即world。
在DAE文件中我们可以直接拉出一个摄像头,可以设置摄像头的深度,广度,角度。以及范围等。等设置好这个摄像头就可以保存下来,切换其它文件再次进入dae文件看到摄像头的效果。
我这里“设计”同事给我的DAE文件X\Y\Z轴是跟常规的不一样的,不过这样没有什么大的影响,因为我们有摄像头嘛。只不过我们输出的时候就会显示出摄像头的坐标是不同的。
//获取摄像机 self.originCamera = [_scenePlace.rootNode childNodeWithName:@"origin_camera" recursively:YES];
接着上面,我们给视图添加手势。
//单击手势 UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; NSMutableArray *gestureRecognizers = [NSMutableArray array]; [gestureRecognizers addObject:tapGesture]; [gestureRecognizers addObjectsFromArray:_sceneView.gestureRecognizers]; _sceneView.gestureRecognizers = gestureRecognizers; //添加双击手势 UITapGestureRecognizer *doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(doubleTap:)]; [doubleTapGestureRecognizer setNumberOfTapsRequired:2]; [_sceneView addGestureRecognizer:doubleTapGestureRecognizer]; // 移动手势 UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panView:)]; [_sceneView addGestureRecognizer:panGestureRecognizer];
最后就是各个手势涉及的代码了,第一个是双击恢复原状的手势代码。
-(void)doubleTap:(UIGestureRecognizer*)gesture { //恢复至原值 _lastMovePointY = 0; _currentAngle = 0; _nowScaleDegree=1.0; //获取转动屏幕后的角度 SCNNode *rootNode = [_scenePlace.rootNode childNodeWithName:@"Box006" recursively:YES]; rootNode.transform = SCNMatrix4MakeRotation(_currentAngle, 0, 0, 1); //相机先切回到初始状态 NSString *filePath = [[NSBundle mainBundle]pathForResource:@"model_info" ofType:@"plist"]; NSArray *originArr = [NSArray arrayWithContentsOfFile:filePath]; NSDictionary *resultDic; for (NSDictionary *originDic in originArr) { NSString *localName = originDic[@"model_dds"]; if ([localName isEqualToString:@"origin_camera"]) { resultDic = originDic[@"model_origin"]; continue; } } _camera_postionX = [resultDic[@"pointX"] floatValue]; _camera_postionY = [resultDic[@"pointY"] floatValue]; _camera_postionZ = [resultDic[@"pointZ"] floatValue]; _camera_rotationX = [resultDic[@"rotationX"] floatValue]; _camera_rotationY = [resultDic[@"rotationY"] floatValue]; _camera_rotationZ = [resultDic[@"rotationZ"] floatValue]; _camera_rotationW = [resultDic[@"rotationW"] floatValue]; _originCamera.position = SCNVector3Make(_camera_postionX, _camera_postionY, _camera_postionZ); _originCamera.rotation = SCNVector4Make(_camera_rotationX, _camera_rotationY, _camera_rotationZ, _camera_rotationW); }
然后是移动模型,我这里是写的让他竖直方向上移动,以及横向转动的代码。之所以不说成是绕Y轴上下移动和转动,是因为我这里X\Y\Z轴是不一样的,所以才会在代码上设置移动和转动的时候不同的是X\Y\Z,其他都是一样的,在用的时候你可以根据自己的需求,多试几次就找到了。
//处理拖拉手势 - (void) panView:(UIPanGestureRecognizer *)panGestureRecognizer { //刚接触界面的时候从本地文件取出位置,如果已经挪动过,则需要在当前基础上挪动 if (panGestureRecognizer.state == UIGestureRecognizerStateBegan && _camera_postionY ==0) { //获取相机 NSString *filePath = [[NSBundle mainBundle]pathForResource:@"model_info" ofType:@"plist"]; NSArray *originArr = [NSArray arrayWithContentsOfFile:filePath]; NSDictionary *resultDic; for (NSDictionary *originDic in originArr) { NSString *localName = originDic[@"model_dds"]; if ([localName isEqualToString:@"origin_camera"]) { resultDic = originDic[@"model_origin"]; continue; } } _camera_postionX = [resultDic[@"pointX"] floatValue]; _camera_postionY = [resultDic[@"pointY"] floatValue]; _camera_postionZ = [resultDic[@"pointZ"] floatValue]; _camera_rotationX = [resultDic[@"rotationX"] floatValue]; _camera_rotationY = [resultDic[@"rotationY"] floatValue]; _camera_rotationZ = [resultDic[@"rotationZ"] floatValue]; _camera_rotationW = [resultDic[@"rotationW"] floatValue]; } //获取拖拽的位置 UIPanGestureRecognizer *panGesture = panGestureRecognizer; CGPoint transformPoint = [panGesture velocityInView:_sceneView]; _lastMovePointX += transformPoint.x; CGFloat onceMoveY = transformPoint.y; _lastMovePointY += onceMoveY; //修改相机位置 _camera_postionZ += onceMoveY; _originCamera.position = SCNVector3Make(_camera_postionX, _camera_postionY, _camera_postionZ); _originCamera.rotation = SCNVector4Make(_camera_rotationX, _camera_rotationY, _camera_rotationZ, _camera_rotationW); //获取转动屏幕后的角度 SCNNode *rootNode = [_scenePlace.rootNode childNodeWithName:@"Box006" recursively:YES]; CGFloat newAngle = (transformPoint.x * (CGFloat)(M_PI / 180.0) )/50; newAngle += _currentAngle; rootNode.transform = SCNMatrix4MakeRotation(newAngle, 0, 0, 1); //转动过程中设置变化的角度 if (panGestureRecognizer.state == UIGestureRecognizerStateEnded || panGestureRecognizer.state == UIGestureRecognizerStateChanged) { _currentAngle = newAngle; } }
最后一个是单击模型将相机切换到单击的模型附近,可以近距离查看单个区域的模型。这也是我没有写缩放手势的原因。
- (void) handleTap:(UIGestureRecognizer*)gestureRecognize { //查找出点击的节点 CGPoint hitPoint = [gestureRecognize locationInView:_sceneView]; NSArray *hitResults = [_sceneView hitTest:hitPoint options:nil]; // check that we clicked on at least one object if([hitResults count] > 0){ // retrieved the first clicked object SCNHitTestResult *result = [hitResults objectAtIndex:0]; //获取点击的material(贴图) SCNMaterial *material = result.node.geometry.firstMaterial; //打印出点击的material名字 NSString *materialName =[NSString stringWithFormat:@"%@",material.name]; NSLog(@"current model:%@",materialName); //获取模型名字 SCNNode *clickNode = result.node; _selectNodeName = clickNode.name; if ([_selectNodeName hasPrefix:@"T"]) { NSString *filePath = [[NSBundle mainBundle]pathForResource:@"model_info" ofType:@"plist"]; NSArray *originArr = [NSArray arrayWithContentsOfFile:filePath]; NSDictionary *resultDic; for (NSDictionary *originDic in originArr) { NSString *localName = originDic[@"model_dds"]; if ([localName isEqualToString:_selectNodeName]) { resultDic = originDic[@"model_origin"]; continue; } } _camera_postionX = [resultDic[@"pointX"] floatValue]; _camera_postionY = [resultDic[@"pointY"] floatValue]; _camera_postionZ = [resultDic[@"pointZ"] floatValue]; _camera_rotationX = [resultDic[@"rotationX"] floatValue]; _camera_rotationY = [resultDic[@"rotationY"] floatValue]; _camera_rotationZ = [resultDic[@"rotationZ"] floatValue]; _camera_rotationW = [resultDic[@"rotationW"] floatValue]; _originCamera.position = SCNVector3Make(_camera_postionX, _camera_postionY, _camera_postionZ); _originCamera.rotation = SCNVector4Make(_camera_rotationX, _camera_rotationY, _camera_rotationZ, _camera_rotationW); } else if ([_selectNodeName hasPrefix:@"J"]) { [self requestSeatDetailInfoWithSeatId:_selectNodeName]; [self.baseImage addSubview:self.infoView]; } }
上面就是简单的介绍了下自定义的手动拖拽屏幕使模型绕固定轴转动,移动整个模型在某一个轴向上移动,单击模型切换摄像头的效果。最后,我们的自定义方法是不可以使用_sceneView.allowsCameraControl = YES;这句话的,因为使用这句话就是让模型毫无限制,这样就会打乱我们的摄像头的设定,我这里没有缩放效果也有这个原因。如果谁有更好的方案,希望可以多多交流。
相关文章推荐
- 使用xib文件和自定义类来实现自定义View(如何利用xib封装一个View)
- [web.config]如何灵活使用配置文件
- iOS开发的一些小技术:让UIImage有缩放功能、控制log的输出、xcode修改文件注释、随机数的使用、在UIImageView 中旋转图像、在Quartz中如何设置旋转点、创建.plist文件并存储
- [dotnetCore2.0]学习笔记之二: ASP.NET Core中,如何灵活使用静态文件和加载自定义配置
- 如何制作和使用帮助文件
- 如何使用C#压缩文件及注意的问题!
- 对应诺言,写了篇文章,“如何使用Serialization 进行文件存储/读取数据 (上)”, 请大家评评。
- 如何使用C#压缩文件及注意的问题!
- 如何在linux下使用c语言操作临时文件
- 如何使用.NET配置文件(二)
- 如何解决烦人的VS.NET2003编译时“无法将程序集复制到文件,另一个程序正在使用,进程无法访问”的问题?
- 如何在DataTable中灵活使用Select方法
- 如何在不增加swap分区的情况下使用swap文件来增加swap?
- 如何使用Java POI生成Excel表文件
- 如何在VB6.0中创建和使用文本资源文件
- 解决一个如何使用库文件的难题
- 请求帮助:如何解决烦人的VS.NET2003编译时“无法将程序集复制到文件,另一个程序正在使用,进程无法访问”的问题?
- 如何使用asp.net中的控件将一个图片文件从一个目录传到另外一个目录下?
- 如何使用SQL 2000的DTS自动从FTP服务器下载文件
- 如何有效的使用C#读取文件