編者按:AR遊戲很常見,但在直播畫面中出現AR屏幕,在其中再嵌套直播畫面的玩法你試過麼?咱們將經過兩篇文章由淺入深,帶你一塊兒看看AR能與音視頻直播碰撞出怎樣的火花。node
本篇咱們將從ARKit開發原理,到demo代碼,帶你們一塊兒實現一個AR應用。數組
下篇咱們將圍繞音視頻信息採集,到場景渲染,與你們分享如何實現AR視頻會議的demo實例。歡迎訪問 RTC 開發者社區,與更多開發者交流經驗,參與更多技術活動。bash
今年7月Apple推出了AR工具ARKit,着實閃着了你們的眼睛。從目前的評測能夠知道 ARKit已經很是成熟,徹底能夠進行商用了。session
在iOS中,加強現實由ARKit和渲染兩部分組成。ARKit主要負責AR計算,它將ARCamera捕獲的視頻幀看成背景,使用視覺慣性測距(VIO)來精確跟蹤周圍的世界,進行座標轉換,場景搭建及平面的捕獲;而後,經過 SceneKit(3D)/SpritKit(2D) 或 Metal 庫進行渲染,使虛擬物體與真實世界相接合,達到加強現實的目的。ide
今天咱們就來詳細的瞭解一下 ARKit,看看 Apple 爲咱們提供了怎樣強大的工具,可讓咱們迅速的構建一個AR應用程序。工具
在講解咱們的 AR 程序以前,咱們先要了解幾個ARKit的基本概念。只有這幾個基本概念瞭解清楚以後,咱們才能清楚的知道如何去寫一個AR程序。post
AR 的目標是往真實世界中的特定點插入虛擬內容,而且在真實世界中移動時還能對此虛擬內容保持追蹤。優化
ARKit 從視頻幀中得到某張圖片的特徵後,就能夠從多個幀中追蹤這些特徵。隨着用戶在真實世界中的移動,就能夠利用相應的特徵點來估算 3D 姿態信息。用戶移動地越多,就會得到越多的特徵,並優化這些估算的 3D 姿態信息。ui
有沒有可能檢測不出特徵點的狀況呢?固然有,可能檢測不出特徵點的狀況以下:atom
ARKit 的平面檢測用於檢測出現實世界的水平面,也就是在 3D 空間中,Y值爲0的一個區域。平面檢測是一個動態的過程,當攝像機不斷移動時,檢測到的平面也會不斷的變化。此外,隨着平面的動態檢測,不一樣平面也可能會合併爲一個新的平面。
只有檢測真實世界有水平面以後,才能找到錨定點,並將虛擬物體放到這個錨定點上。
除了平臺檢測外,還有點擊檢測。顧名思意,就是當用戶點擊屏幕時,ARKit 將點擊屏幕的2D空間位置轉換爲ARKit 經過 ARCamera 捕獲到的視頻幀的 3D 空間位置。並在這個位置檢測是否有平面。
世界追蹤都追蹤什麼呢?ARKit 會追蹤如下幾個信息:
ARKit 使用視覺慣性測距技術,對攝像頭採集到的圖像序列進行計算機視覺分析,而且與設備的運動傳感器信息相結合。ARKit 會識別出每一幀圖像中的特徵點,而且根據特徵點在連續的圖像幀之間的位置變化,而後與運動傳感器提供的信息進行比較,最終獲得高精度的設備位置和偏轉信息。
除了上面這幾個概念外,咱們還須要知道ARKit提供的一些基本知識。
ARSession 是 ARkit 的核心。它是鏈接ARCamera與ARACNView之間的橋樑。像捕獲視頻,與 CoreMotion 的數據整合,場景的理解,平面檢測等等都須要 ARSession 來協調各模塊進行協同處理。
另外,ARSession 有兩種獲取 ARFrame 的方法:
push 實時不斷的獲取相機位置,由ARSession主動告知用戶。經過實現ARSession的代理來獲取。
(void)session:(ARSession *)session didUpdateFrame:(ARFrame *)frame
複製代碼
pull 用戶想要時,主動去獲取。經過 ARSession的屬性currentFrame來獲取。
該類的做用是設置一些 ARSession 相關的配置,如是否使用平面檢測就是經過這個參數來設置的。
ARSCNView 繼承自 SceneKit 中的 SCNView。ARSCNView是一個很是複雜的類,它不只擁有SCNView的功能,並且它還管理着 ARSession。以下圖所示:
SceneKit 的主要做用是將虛擬物體展現在3D場景中。每一個虛擬物體均可以用 SCNNode 來表明,SCNNode 在 SCNScene 中展示,而無數SCNScene 組成 3D 世界。
它有幾個重要的方法須要特別強調一下:
hitTest 方法
- (NSArray<ARHitTestResult *> *)hitTest:(CGPoint)point types:(ARHitTestResultType)types;
複製代碼
point:2D座標點(手機屏幕某一點);
ARHitTestResultType:捕捉類型是 點 仍是 面;
NSArray<ARHitTestResult *> *:追蹤結果數組。數組的結果排序是由近到遠。
根據2D座標點搜索3D模型位置。當咱們在手機屏幕點擊某一個點的時候,能夠捕捉到這一個點所在的3D模型的位置。爲何返回值是一個數組呢?這是由於手機屏幕一個是長方形的二維空間,而相機捕捉到的是一個由這個二維空間映射出去的長方體。咱們點擊屏幕一個點,能夠理解爲在這個長方體的邊緣射出一條線,這一條線上可能會有多個3D物體模型。
renderer 方法
(void)renderer:(id<SCNSceneRenderer>)renderer updateAtTime:(NSTimeInterval)time
複製代碼
它是 ARSCNViewDelegate 中的回調方法,每次 3D 引擎要渲染新的視頻幀時都會調用該方法。
重載 renderer 方法
- (void)renderer:(id<SCNSceneRenderer>)renderer didAddNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor
複製代碼
它是 ARSCNViewDelegate 中的回調方法,每次 ARKit 檢測到了平面時都會調用此方法。咱們能夠經過這個代理方法得知咱們添加一個虛擬物體到AR場景下的錨點(AR現實世界中的座標)
SCNNode表明一個虛擬物體。經過 SCNNode 能夠對虛擬物體進行變換和旋轉,還能夠作幾何變換,光照等操做。
在ARKit中它表明一個場景。SCNScene 包括背景 和 虛似物體。其中背景能夠是從 ARCamera捕獲的視頻幀。而虛擬物體由 rootNode 存儲,它就是前面介紹的 SCNNode。
包含真實世界位置和方向的信息。經過它能夠輕鬆地將虛擬物體添加,更新或從會話中刪除。
ARCamera 用於捕捉視頻流。通常咱們無需去建立一個ARCamera,由於在初始化 AR 時,它就幫咱們將ARCamera建立好了。另外,咱們通常也不直接使用 ARCamera 的 API,默認都是設置好的。
攝像頭視頻幀的包裝類。從 ARCamera 中獲取的每一幅視頻幀都被封裝成 ARFrame。它包含位置追蹤信息、環境參數、視頻幀。重點是它包含了蘋果檢測的特徵點,經過rawFeaturePoints能夠獲取,不過只是特徵的位置,具體的特徵向量並無開放。
使用 SCNMaterial 能夠對虛擬物體 SCNNode 進行貼圖。
所謂任意門就是在真實環境中虛擬一扇門,當走進這扇門後,能夠看到另一個世界。
初始化ARKit
- (void)viewDidLoad {
[super viewDidLoad];
// Set the view's delegate self.sceneView.delegate = self; // Show statistics such as fps and timing information self.sceneView.showsStatistics = YES; // Create a new scene SCNScene *scene = [SCNScene new]; // Set the scene to the view self.sceneView.scene = scene; //Grid to identify plane detected by ARKit _gridMaterial = [SCNMaterial material]; _gridMaterial.diffuse.contents = [UIImage imageNamed:@"art.scnassets/grid.png"]; //when plane scaling large, we wanna grid cover it over and over _gridMaterial.diffuse.wrapS = SCNWrapModeRepeat; _gridMaterial.diffuse.wrapT = SCNWrapModeRepeat; _planes = [NSMutableDictionary dictionary]; //tap gesture UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(placeTransDimenRoom:)]; [self.sceneView addGestureRecognizer:tap]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // Create a session configuration ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfiguration new]; configuration.planeDetection = ARPlaneDetectionHorizontal; // Run the view's session
[self.sceneView.session runWithConfiguration:configuration];
}
複製代碼
處理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];
}
}
複製代碼
放置transDimenRoom
對於隱藏空間,抽象成兩個類來表達:transDimenRoom,transDimenStruct。
後者用於提供一些平板等基礎結構,前者將這些結構拼成一個房間,留一個門框出來讓用戶可以看見裏面。
當須要放置任意門時,就用+transDimenRoomAtPosition:方法建立一個transDimenRoom,當用戶走進去時,用 -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
複製代碼
檢測到用戶走進房間
目前爲了簡單起見,是判斷用戶與房間中心的距離,當距離小於1時,就認爲用戶進入了房間。這裏的邏輯之後會收歸到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];
}
}
複製代碼
今天首先向你們介紹了一下 ARKit 的基本知識,而後經過任意門這個實例告訴了你們如何寫一個ARKit程序。這個 任意門 能夠應用在不少場景中,你們能夠經過這個實例進行擴展,充份發揮本身的想像力。
其實本節最最關鍵的是讓你們知道 ARKit中的那些基本概念。ARSession是它的核心,它協調內部模塊進行場景的各類計算。而 ARSCNView 只是渲染技術中的一種,咱們完成能夠經過 OpenGL/Metal 來替換掉它。
在下篇,咱們將會介紹,如何講ARkit應用於視頻直播。