此文章為轉(zhuǎn)載文章:ARKit從入門(mén)到精通(3)-ARKit自定義實(shí)現(xiàn)
在上一小節(jié)中ARKit從入門(mén)到精通(2)-ARKit工作原理及流程介紹,我們完整的介紹了ARKit的工作原理,那么本小節(jié)我們就通過(guò)對(duì)ARKit工作原理的理解,手動(dòng)的搭建一個(gè)ARKit虛擬增強(qiáng)現(xiàn)實(shí)環(huán)境
1.1-創(chuàng)建一個(gè)簡(jiǎn)單的工程
1.1-創(chuàng)建一個(gè)簡(jiǎn)單的工程
1.上一小節(jié)中介紹過(guò),ARSCNView是UIView的子類的子類,所以從理論上來(lái)說(shuō),我們應(yīng)用框架UIKit是可以加載AR場(chǎng)景的
0401.png
2.給界面添加一個(gè)按鈕開(kāi)啟AR之旅,創(chuàng)建一個(gè)ARSCNViewController:繼承于UIViewController,點(diǎn)擊按鈕跳轉(zhuǎn)到自定義ARSCNViewController
0402.png
一個(gè)完整的ARKit工作環(huán)境必須要搭建三個(gè)對(duì)象:ARSCNView(一旦創(chuàng)建,系統(tǒng)會(huì)幫我們創(chuàng)建一個(gè)場(chǎng)景Scene和相機(jī)),ARSession(開(kāi)啟AR和關(guān)閉AR都是靠它),ARSessionConfiguration(少了會(huì)話追蹤配置,AR會(huì)話是無(wú)法獨(dú)立工作的)
定義全局屬性
#import"ARSCNViewViewController.h"http://3D游戲框架#import//ARKit框架#import@interfaceARSCNViewViewController()//AR視圖:展示3D界面@property(nonatomic,strong)ARSCNView *arSCNView;//AR會(huì)話,負(fù)責(zé)管理相機(jī)追蹤配置及3D相機(jī)坐標(biāo)@property(nonatomic,strong)ARSession *arSession;//會(huì)話追蹤配置:負(fù)責(zé)追蹤相機(jī)的運(yùn)動(dòng)@property(nonatomic,strong)ARSessionConfiguration *arSessionConfiguration;//飛機(jī)3D模型(本小節(jié)加載多個(gè)模型)@property(nonatomic,strong)SCNNode*planeNode;@end
懶加載(筆者個(gè)人習(xí)慣)ARKit環(huán)境
#pragmamark -搭建ARKit環(huán)境//懶加載會(huì)話追蹤配置- (ARSessionConfiguration *)arSessionConfiguration{if(_arSessionConfiguration!=nil) {? ? ? ? return_arSessionConfiguration;? ? }//1.創(chuàng)建世界追蹤會(huì)話配置(使用ARWorldTrackingSessionConfiguration效果更加好),需要A9芯片支持ARWorldTrackingSessionConfiguration *configuration = [[ARWorldTrackingSessionConfiguration alloc] init];//2.設(shè)置追蹤方向(追蹤平面,后面會(huì)用到)configuration.planeDetection = ARPlaneDetectionHorizontal;_arSessionConfiguration= configuration;//3.自適應(yīng)燈光(相機(jī)從暗到強(qiáng)光快速過(guò)渡效果會(huì)平緩一些)_arSessionConfiguration.lightEstimationEnabled = YES;? ? return_arSessionConfiguration;}//懶加載拍攝會(huì)話- (ARSession *)arSession{if(_arSession!=nil)? ? {? ? ? ? return_arSession;? ? }//1.創(chuàng)建會(huì)話_arSession= [[ARSession alloc] init];//2返回會(huì)話return_arSession;}//創(chuàng)建AR視圖- (ARSCNView *)arSCNView{if(_arSCNView!=nil) {? ? ? ? return_arSCNView;? ? }//1.創(chuàng)建AR視圖_arSCNView= [[ARSCNView alloc] initWithFrame:self.view.bounds];//2.設(shè)置視圖會(huì)話_arSCNView.session = self.arSession;//3.自動(dòng)刷新燈光(3D游戲用到,此處可忽略)_arSCNView.automaticallyUpdatesLighting = YES;? ? return_arSCNView;}
我們只需要先將AR視圖添加到當(dāng)前UIView中,然后開(kāi)啟AR會(huì)話即可開(kāi)始我們的AR之旅
***這里需要特別注意的是,最好將開(kāi)啟ARSession的代碼放入viewDidAppear而不是viewDidLoad中,這樣可以避免線程延遲的問(wèn)題。開(kāi)啟ARSession的代碼可不可以放入viewDidLoad中呢?答案是可以的,但是筆者不建議大家那么做***
@implementationARSCNViewViewController- (void)viewDidLoad {? ? [superviewDidLoad];// Do any additional setup after loading the view.}- (void)viewDidAppear:(BOOL)animated{? ? [superviewDidAppear:animated];//1.將AR視圖添加到當(dāng)前視圖[self.view addSubview:self.arSCNView];//2.開(kāi)啟AR會(huì)話(此時(shí)相機(jī)開(kāi)始工作)[self.arSession runWithConfiguration:self.arSessionConfiguration];}
默認(rèn)情況下,節(jié)點(diǎn)SCNNode的x/y/z位置是(0,0,0),也就是攝像頭所在的位置,每一個(gè)ARSession在啟動(dòng)時(shí),攝像頭的位置就是3D世界的原點(diǎn),而且這個(gè)原點(diǎn)不再隨著攝像頭的移動(dòng)而改變,是第一次就永久固定的
想要讓飛機(jī)顯示在你想要的位置,就需要更加深入的研究ARKit框架,需要了解ARKit的坐標(biāo)系及API,筆者將會(huì)在下一小節(jié)慢慢介紹
pragma mark- 點(diǎn)擊屏幕添加飛機(jī)
(void)touchesBegan:(NSSet)touches withEvent:(UIEvent)event
{
//1.使用場(chǎng)景加載scn文件(scn格式文件是一個(gè)基于3D建模的文件,使用3DMax軟件可以創(chuàng)建,這里系統(tǒng)有一個(gè)默認(rèn)的3D飛機(jī))--------在右側(cè)我添加了許多3D模型,只需要替換文件名即可
SCNScenescene = [SCNScene sceneNamed:@"Models.scnassets/ship.scn"];
//2.獲取飛機(jī)節(jié)點(diǎn)(一個(gè)場(chǎng)景會(huì)有多個(gè)節(jié)點(diǎn),此處我們只寫(xiě),飛機(jī)節(jié)點(diǎn)則默認(rèn)是場(chǎng)景子節(jié)點(diǎn)的第一個(gè))
//所有的場(chǎng)景有且只有一個(gè)根節(jié)點(diǎn),其他所有節(jié)點(diǎn)都是根節(jié)點(diǎn)的子節(jié)點(diǎn)
SCNNode
shipNode = scene.rootNode.childNodes[0];
//3.將飛機(jī)節(jié)點(diǎn)添加到當(dāng)前屏幕中
[self.arSCNView.scene.rootNode addChildNode:shipNode];
}
在筆者Xcode左側(cè)已經(jīng)導(dǎo)入了好幾個(gè)3D模型,只需要修改文件名既可以加載不同的3D模型,注意路徑區(qū)別
0403.png
飛機(jī)
0404.gif
來(lái)張椅子坐一下吧
椅子比較大,我們需要適當(dāng)調(diào)整一下位置
0405.png
0405.gif
完整代碼
#import"ARSCNViewViewController.h"http://3D游戲框架#import//ARKit框架#import@interfaceARSCNViewViewController()//AR視圖:展示3D界面@property(nonatomic,strong)ARSCNView *arSCNView;//AR會(huì)話,負(fù)責(zé)管理相機(jī)追蹤配置及3D相機(jī)坐標(biāo)@property(nonatomic,strong)ARSession *arSession;//會(huì)話追蹤配置:負(fù)責(zé)追蹤相機(jī)的運(yùn)動(dòng)@property(nonatomic,strong)ARSessionConfiguration *arSessionConfiguration;//飛機(jī)3D模型(本小節(jié)加載多個(gè)模型)@property(nonatomic,strong)SCNNode*planeNode;@end@implementationARSCNViewViewController- (void)viewDidLoad {? ? [superviewDidLoad];// Do any additional setup after loading the view.}- (void)viewDidAppear:(BOOL)animated{? ? [superviewDidAppear:animated];//1.將AR視圖添加到當(dāng)前視圖[self.view addSubview:self.arSCNView];//2.開(kāi)啟AR會(huì)話(此時(shí)相機(jī)開(kāi)始工作)[self.arSession runWithConfiguration:self.arSessionConfiguration];}#pragma mark- 點(diǎn)擊屏幕添加飛機(jī)- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event{//1.使用場(chǎng)景加載scn文件(scn格式文件是一個(gè)基于3D建模的文件,使用3DMax軟件可以創(chuàng)建,這里系統(tǒng)有一個(gè)默認(rèn)的3D飛機(jī))--------在右側(cè)我添加了許多3D模型,只需要替換文件名即可SCNScene*scene = [SCNScenesceneNamed:@"Models.scnassets/chair/chair.scn"];//2.獲取飛機(jī)節(jié)點(diǎn)(一個(gè)場(chǎng)景會(huì)有多個(gè)節(jié)點(diǎn),此處我們只寫(xiě),飛機(jī)節(jié)點(diǎn)則默認(rèn)是場(chǎng)景子節(jié)點(diǎn)的第一個(gè))//所有的場(chǎng)景有且只有一個(gè)根節(jié)點(diǎn),其他所有節(jié)點(diǎn)都是根節(jié)點(diǎn)的子節(jié)點(diǎn)SCNNode*shipNode = scene.rootNode.childNodes[0];//椅子比較大,可以可以調(diào)整Z軸的位置讓它離攝像頭遠(yuǎn)一點(diǎn),,然后再往下一點(diǎn)(椅子太高我們坐不上去)就可以看得全局一點(diǎn)shipNode.position =SCNVector3Make(0,-1,-1);//x/y/z/坐標(biāo)相對(duì)于世界原點(diǎn),也就是相機(jī)位置//3.將飛機(jī)節(jié)點(diǎn)添加到當(dāng)前屏幕中[self.arSCNView.scene.rootNode addChildNode:shipNode];}#pragma mark -搭建ARKit環(huán)境//懶加載會(huì)話追蹤配置- (ARSessionConfiguration *)arSessionConfiguration{if(_arSessionConfiguration !=nil) {return_arSessionConfiguration;? ? }//1.創(chuàng)建世界追蹤會(huì)話配置(使用ARWorldTrackingSessionConfiguration效果更加好),需要A9芯片支持ARWorldTrackingSessionConfiguration *configuration = [[ARWorldTrackingSessionConfiguration alloc] init];//2.設(shè)置追蹤方向(追蹤平面,后面會(huì)用到)configuration.planeDetection = ARPlaneDetectionHorizontal;? ? _arSessionConfiguration = configuration;//3.自適應(yīng)燈光(相機(jī)從暗到強(qiáng)光快速過(guò)渡效果會(huì)平緩一些)_arSessionConfiguration.lightEstimationEnabled =YES;return_arSessionConfiguration;}//懶加載拍攝會(huì)話- (ARSession *)arSession{if(_arSession !=nil)? ? {return_arSession;? ? }//1.創(chuàng)建會(huì)話_arSession = [[ARSession alloc] init];//2返回會(huì)話return_arSession;}//創(chuàng)建AR視圖- (ARSCNView *)arSCNView{if(_arSCNView !=nil) {return_arSCNView;? ? }//1.創(chuàng)建AR視圖_arSCNView = [[ARSCNView alloc] initWithFrame:self.view.bounds];//2.設(shè)置視圖會(huì)話_arSCNView.session =self.arSession;//3.自動(dòng)刷新燈光(3D游戲用到,此處可忽略)_arSCNView.automaticallyUpdatesLighting =YES;return_arSCNView;}- (void)didReceiveMemoryWarning {? ? [superdidReceiveMemoryWarning];// 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
代碼下載地址