轉載請註明出處:ARKit從入門到精通(3)-ARKit自定義實現
-
在上一小節中ARKit從入門到精通(2)-ARKit工作原理及流程介紹,我們完整的介紹了ARKit的工作原理,那麼本小節我們就通過對ARKit工作原理的理解,手動的搭建一個ARKit虛擬增強現實環境
- 1.2-搭建ARKit工作環境
- 1.3-開啓AR掃描
- 1.4-點擊屏幕添加一個3D虛擬物體
- 1.5-效果展示
- 1.6-完整代碼及代碼下載地址
1.1-創建一個簡單的工程
- 1.上一小節中介紹過,
ARSCNView
是UIView
的子類的子類,所以從理論上來說,我們應用框架UIKit
是可以加載AR場景的
- 2.給界面添加一個按鈕開啓AR之旅,創建一個
ARSCNViewController:繼承於UIViewController
,點擊按鈕跳轉到自定義ARSCNViewController
1.2-搭建ARKit工作環境
-
一個完整的ARKit工作環境必須要搭建三個對象:
ARSCNView
(一旦創建,系統會幫我們創建一個場景Scene和相機),ARSession
(開啓AR和關閉AR都是靠它),ARSessionConfiguration
(少了會話追蹤配置,AR會話是無法獨立工作的) -
定義全局屬性
#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
- 懶加載(筆者個人習慣)ARKit環境
#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;
}
1.3-開啓AR掃描
- 我們只需要先將AR視圖添加到當前UIView中,然後開啓AR會話即可開始我們的AR之旅
***這裏需要特別注意的是,最好將開啓
ARSession的代碼放入viewDidAppear而不是
viewDidLoad中,這樣可以避免線程延遲的問題。開啓
ARSession的代碼可不可以放入
viewDidLoad中呢?答案是可以的,但是筆者不建議大家那麼做***
@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];
}
1.4-點擊屏幕添加一個3D虛擬物體
- 默認情況下,節點
SCNNode
的x/y/z位置是(0,0,0),也就是攝像頭所在的位置,每一個ARSession在啓動時,攝像頭的位置就是3D世界的原點,而且這個原點不再隨着攝像頭的移動而改變,是第一次就永久固定的想要讓飛機顯示在你想要的位置,就需要更加深入的研究ARKit框架,需要了解ARKit的座標系及API,筆者將會在下一小節慢慢介紹
pragma mark- 點擊屏幕添加飛機
-
(void)touchesBegan:(NSSet<UITouch *> )touches withEvent:(UIEvent )event
{
//1.使用場景加載scn文件(scn格式文件是一個基於3D建模的文件,使用3DMax軟件可以創建,這裏系統有一個默認的3D飛機)--------在右側我添加了許多3D模型,只需要替換文件名即可
SCNScene scene = [SCNScene sceneNamed:@"Models.scnassets/ship.scn"];
//2.獲取飛機節點(一個場景會有多個節點,此處我們只寫,飛機節點則默認是場景子節點的第一個)
//所有的場景有且只有一個根節點,其他所有節點都是根節點的子節點
SCNNode shipNode = scene.rootNode.childNodes[0];//3.將飛機節點添加到當前屏幕中
[self.arSCNView.scene.rootNode addChildNode:shipNode];
}
1.5-效果展示
- 在筆者Xcode左側已經導入了好幾個3D模型,只需要修改文件名既可以加載不同的3D模型,注意路徑區別
- 飛機
- 來張椅子坐一下吧
- 椅子比較大,我們需要適當調整一下位置
1.6-完整代碼及代碼下載地址
- 完整代碼
#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