上一篇文章讲述了如何切换相机位置的问题,今天在之前的基础上讲述下自定义移动,手动转动以及点击模型中的子模型等操作。
直接讲述代码以及流程问题。首先我们需要将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;这句话的,因为使用这句话就是让模型毫无限制,这样就会打乱我们的摄像头的设定,我这里没有缩放效果也有这个原因。如果谁有更好的方案,希望可以多多交流。