ARKit實戰(zhàn):如何實現(xiàn)任意門
相關(guān)
到底有多強?蘋果的增強現(xiàn)實框架:ARKit
ARKit進階:物理世界
ARKit進階:材質(zhì)
技術(shù)
任意門特效的實現(xiàn),主要用到了關(guān)于紋理、材質(zhì)、光照的相關(guān)知識,掌握起來并不困難。
如果對相關(guān)知識不熟悉,可以看一下上面的文章。
github
如果對工程感興趣,可以在github上找到源碼。歡迎star, fork。
github地址:ARKit_trans-dimensional-room
效果
Demo視頻合集
Demo視頻合集有兩段任意門視頻,可以看看效果,分別是:pet_find_transDeminalRoom,
ARKit trans-dimensional room。
目標(biāo)
我們的目標(biāo)是要實現(xiàn)一個獨立的隱藏空間,這個空間只有一個門留給用戶展示,當(dāng)用戶走進去時,可以看到內(nèi)部的細(xì)節(jié)。
思路
先構(gòu)建一個封閉的空間,再用透明材質(zhì)將它包裹起來,當(dāng)用戶進入這個空間后,可以將背景換成全景的圖片,當(dāng)用戶走出時,將背景換回攝像頭數(shù)據(jù)。
實現(xiàn)
實現(xiàn)分三部分:
1 . 處理ARKit檢測到的平面
用于提示可以用于交互的平面,后期模擬物理世界也要用到。
- (void)renderer:(id<SCNSceneRenderer>)renderer didAddNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor{
if ([anchor isKindOfClass:[ARPlaneAnchor class]] && !_stopDetectPlanes){
NSLog(@"detected plane");
[self addPlanesWithAnchor:(ARPlaneAnchor*)anchor forNode:node];
[self postInfomation:@"touch ground to place room"];
}
}
- (void)renderer:(id<SCNSceneRenderer>)renderer didUpdateNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor{
if ([anchor isKindOfClass:[ARPlaneAnchor class]]){
NSLog(@"updated plane");
[self updatePlanesForAnchor:(ARPlaneAnchor*)anchor];
}
}
- (void)renderer:(id<SCNSceneRenderer>)renderer didRemoveNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor{
if ([anchor isKindOfClass:[ARPlaneAnchor class]]){
NSLog(@"removed plane");
[self removePlaneForAnchor:(ARPlaneAnchor*)anchor];
}
}
2 . 放置transDimenRoom
對于隱藏空間,抽象成兩個類來表達:transDimenRoom
,transDimenStruct
。
后者用于提供一些平板等基礎(chǔ)結(jié)構(gòu),前者將這些結(jié)構(gòu)拼成一個房間,留一個門框出來讓用戶能夠看見里面。
當(dāng)需要放置任意門時,就用+transDimenRoomAtPosition:
方法創(chuàng)建一個transDimenRoom
,當(dāng)用戶走進去時,用-hideWalls:
隱藏四周的墻壁,切換成全景背景。
@interface transDimenRoom : SCNNode
@property (nonatomic, strong) SCNNode *walls;
+(instancetype)transDimenRoomAtPosition:(SCNVector3)position;
//TODO:check if user in room
-(BOOL)checkIfInRoom:(SCNVector3)position;
-(void)hideWalls:(BOOL)hidden;
@end
3 . 檢測到用戶走進房間
目前為了簡單起見,是判斷用戶與房間中心的距離,當(dāng)距離小于1時,就認(rèn)為用戶進入了房間。
這里的邏輯以后會收歸到transDimenRoom
中。
- (void)renderer:(id<SCNSceneRenderer>)renderer updateAtTime:(NSTimeInterval)time{
if (_room.presentationNode) {
SCNVector3 position = self.sceneView.pointOfView.presentationNode.worldPosition;
SCNVector3 roomCenter = _room.walls.worldPosition;
CGFloat distance = GLKVector3Length(GLKVector3Make(position.x - roomCenter.x, 0, position.z - roomCenter.z));
if (distance < 1){
NSLog(@"In room");
[self handleUserInRoom:YES];
return;
}
[self handleUserInRoom:NO];
}
}
展望
工程大致提供了讓用戶從真實世界進入虛擬空間的力能,目前功能還有一些問題需要改進:
- 進入房間后,用skyBox代替背景,會看不到門后的真實世界,考慮用shader去渲染門的內(nèi)容
- 判斷用戶進入房間的方法比較粗糙