ARKit
ARKit框架工作流程可以参考下图:
1.ARSCNView加载场景SCNScene
2.SCNScene启动相机ARCamera开始捕捉场景
3.捕捉场景后ARSCNView开始将场景数据交给Session
4.Session通过管理ARSessionConfiguration实现场景的追踪并且返回一个ARFrame
5.给ARSCNView的scene添加一个子节点(3D物体模型)
ARSessionConfiguration捕捉相机3D位置的意义就在于能够在添加3D物体模型的时候计算出3D物体模型相对于相机的真实的矩阵位置
在3D坐标系统中,有一个世界坐标系和一个本地坐标系。类似于UIView的Frame和Bounds的区别,这种坐标之间的转换可以说是ARKit中最难的部分
import "ARSCNViewViewController.h"
//3D游戏框架
import <SceneKit/SceneKit.h>
//ARKit框架
import <ARKit/ARKit.h>
@interface ARSCNViewViewController ()
//AR视图:展示3D界面
@property(nonatomic,strong)ARSCNView *arSCNView;
//AR会话,负责管理相机追踪配置及3D相机坐标
@property(nonatomic,strong)ARSession *arSession;
//会话追踪配置:负责追踪相机的运动
@property(nonatomic,strong)ARSessionConfiguration *arSessionConfiguration;
//飞机3D模型(本小节加载多个模型)
@property(nonatomic,strong)SCNNode *planeNode;
@end
@implementation ARSCNViewViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-
(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];//1.将AR视图添加到当前视图
[self.view addSubview:self.arSCNView];
//2.开启AR会话(此时相机开始工作)
[self.arSession runWithConfiguration:self.arSessionConfiguration];
}
pragma mark- 点击屏幕添加飞机
-
(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//1.使用场景加载scn文件(scn格式文件是一个基于3D建模的文件,使用3DMax软件可以创建,这里系统有一个默认的3D飞机)--------在右侧我添加了许多3D模型,只需要替换文件名即可
SCNScene *scene = [SCNScene sceneNamed:@"Models.scnassets/chair/chair.scn"];
//2.获取飞机节点(一个场景会有多个节点,此处我们只写,飞机节点则默认是场景子节点的第一个)
//所有的场景有且只有一个根节点,其他所有节点都是根节点的子节点
SCNNode *shipNode = scene.rootNode.childNodes[0];//椅子比较大,可以可以调整Z轴的位置让它离摄像头远一点,,然后再往下一点(椅子太高我们坐不上去)就可以看得全局一点
shipNode.position = SCNVector3Make(0, -1, -1);//x/y/z/坐标相对于世界原点,也就是相机位置//3.将飞机节点添加到当前屏幕中
[self.arSCNView.scene.rootNode addChildNode:shipNode];
}
pragma mark -搭建ARKit环境
//懒加载会话追踪配置
-
(ARSessionConfiguration *)arSessionConfiguration
{
if (_arSessionConfiguration != nil) {
return _arSessionConfiguration;
}//1.创建世界追踪会话配置(使用ARWorldTrackingSessionConfiguration效果更加好),需要A9芯片支持
ARWorldTrackingSessionConfiguration *configuration = [[ARWorldTrackingSessionConfiguration alloc] init];
//2.设置追踪方向(追踪平面,后面会用到)
configuration.planeDetection = ARPlaneDetectionHorizontal;
_arSessionConfiguration = configuration;
//3.自适应灯光(相机从暗到强光快速过渡效果会平缓一些)
_arSessionConfiguration.lightEstimationEnabled = YES;return _arSessionConfiguration;
}
//懒加载拍摄会话
- (ARSession *)arSession
{
if(_arSession != nil)
{
return _arSession;
}
//1.创建会话
_arSession = [[ARSession alloc] init];
//2返回会话
return _arSession;
}
//创建AR视图
-
(ARSCNView *)arSCNView
{
if (_arSCNView != nil) {
return _arSCNView;
}
//1.创建AR视图
_arSCNView = [[ARSCNView alloc] initWithFrame:self.view.bounds];
//2.设置视图会话
_arSCNView.session = self.arSession;
//3.自动刷新灯光(3D游戏用到,此处可忽略)
_arSCNView.automaticallyUpdatesLighting = YES;return _arSCNView;
} -
(void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end