iOS - SceneKit显示与交互3D建模(一)
最近公司要求在手机上显示3D模型,并且要获取点击的模型坐标,找了很多相关资料,发现有两种实现方式,一种是集成Unity3D,另一种是使用苹果提供的SceneKit;由于使用Unity3D太麻烦,于是选择使用SceneKit,而且这个是原生的,速度可想而知要比集成U3D后运行要来得快~
SceneKit建立在 OpenGL 的基础上,包含了如光照、模型、材质、摄像机等高级引擎特性。SceneKit实现的内容为节点层次结构树,也被称为场景图。一个场景由一个为场景世界定义一个坐标空间的根节点,以及其他的可视节点组成。SceneKit会在一个视图上展示场景,而这个场景在GPU上�进行有效地渲染每一帧之前,会处理场景�数据图和执行动画。
�接着来来了解下坐标吧,查阅苹果官方文档,可以看到如下这张图片,SceneKit使用的是右手坐标系,默认视图的方向是沿负Z轴方向的。可以简单的记住红色为x轴,绿色为y轴,蓝色为z轴。
坐标
初出茅庐
我们先来创建一个游戏工程
游戏工程Game Technology选择SceneKit
Paste_Image.png
项目的目录结构如下,比开发APP应用的项目多了一个scnassets文件夹,里面有一个scn后缀的文件,它是xcode能识别的�场景文件。它支持一种后缀为dae的模型文件,我们后续就会用到。
目录结构
运行后如图所示,真是有够炫的,图的下方显示的是当前渲染相关数据,方便我们开发者查看。
�Game Demo
初窥门径
代码从上至下的流程:
- 创建一个场景scene,场景本身并不可见,需要添加到sceneView的场景上
- 创建一个摄像机节点并设置摆放的位置,所处位置即视角所看的位置,可以联想到眼睛视角
- 创建灯光节点设置摆放的位置,灯光可以让需要呈现的物体变得更有质感。
- 获取飞机模型,其中的【recursively:YES】意思为是否在子节点中查询。
- 设置飞机模型绕着y轴旋转,使用的是SCNAction,用法也很简单。
- 获取SCNView,并设置scnView。
牛刀小试
那接下来我们自己也搞一个工程来试试吧
应用工程在Link Binary With Libraries中引入SceneKit库
引入SceneKit库
在ViewController中导入SceneKit
#import <SceneKit/SceneKit.h>
接下来在桌面上新建一个art文件夹,并加上后缀【.scnassets】,将我们的素材Menchi.dae放进里面,然后把art.scnassets拖进项目中,接下来代码献上
// �初始化一个场景
SCNScene *scene = [SCNScene sceneNamed:@"art.scnassets/Menchi.dae"];
// 取出场景中根结点的第一个结点(目录根结点也就一个子结点,就是我们素材中的Menchi)
SCNNode *node = scene.rootNode.childNodes.firstObject;
// 绕 y轴 一直旋转
SCNAction *action = [SCNAction repeatActionForever:[SCNAction rotateByX:0 y:1 z:0 duration:1]];
[node runAction:action];
// 素材放大5倍(由于我们素材的尺寸太小了)
node.transform = SCNMatrix4MakeScale(5, 5, 5);
// �创建一个摄像机并放入场景中
SCNNode *cameraNode = [SCNNode node];
cameraNode.camera = [SCNCamera camera];
[scene.rootNode addChildNode:cameraNode];
// �摆放摄像机位置
cameraNode.position = SCNVector3Make(0, 5, 15);
// 创建�灯光并放入场景中
SCNNode *lightNode = [SCNNode node];
lightNode.light = [SCNLight light];
lightNode.light.type = SCNLightTypeOmni;
lightNode.position = SCNVector3Make(0, 10, 10);
[scene.rootNode addChildNode:lightNode];
// create and add an ambient light to the scene
SCNNode *ambientLightNode = [SCNNode node];
ambientLightNode.light = [SCNLight light];
ambientLightNode.light.type = SCNLightTypeAmbient;
ambientLightNode.light.color = [UIColor darkGrayColor];
[scene.rootNode addChildNode:ambientLightNode];
// 创建一个用来展示场景的SCNView
SCNView *scnView = [[SCNView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:scnView];
// 设置场景
scnView.scene = scene;
// 设置背景
scnView.backgroundColor = [UIColor blackColor];
// 允许控制摄像机位置
scnView.allowsCameraControl = YES;
// 显示数据控制台
scnView.showsStatistics = YES;
好了,编辑运行。成功运行
小怪兽
** BUT **,在实际项目中往往需要我们从服务器上将模型下载下来再来显示,然而这种做法只能是事先把素材放入项目中才能正常显示,【注意:我说的是正常显示】,这是不符合我们的需求的。如果我们把素材从服务器上下载到沙盒里,程序再直接从沙盒读取和初始化场景会出现为nil的问题。