【譯】可視化並與重構的場景進行交互

使用多邊形網格估算物理環境的形狀。

官方Demo下載


一、總覽

在運行iPad OS 13.4或更高版本的第四代iPad Pro上,ARKit使用LiDAR掃描儀創建物理環境的多邊形模型。LiDAR掃描儀可從用戶面前的廣闊區域快速檢索深度信息,因此ARKit無需用戶移動即可估算真實世界的形狀。ARKit將深度信息轉換爲一系列頂點,這些頂點相互連接以形成網格。爲了劃分信息,ARKit製作了多個錨,每個錨分配了網格的唯一部分。網格錨共同代表了用戶周圍的真實場景。

使用這些網格,您可以:

  • 更精確地定位現實表面上的點。
  • 對ARKit可以識別的真實對象進行分類。
  • 使用位於其前面的真實對象來遮擋應用程序的虛擬內容。
  • 讓虛擬內容與物理環境進行實際交互,例如,通過將虛擬球從現實世界的牆壁上彈起,並使球遵循物理定律。

該示例應用程序展示了使用RealityKit的AR體驗。下圖說明了RealityKit如何利用ARKit的真實信息,並在運行該應用並將設備指向真實椅子時創建調試可視化效果。

二、可視化物理環境的形狀

爲了啓用場景網格物體,該示例將 world-configurationsceneReconstruction屬性設置爲網格物體選項之一。

arView.automaticallyConfigureSession = false
let configuration = ARWorldTrackingConfiguration()
configuration.sceneReconstruction = .meshWithClassification

該示例使用 RealityKit 的 ARView渲染其圖形。要在運行時可視化網格,請ARView提供.showSceneUnderstanding 調試選項。

arView.debugOptions.insert(.showSceneUnderstanding)

注意
該示例啓用了網格可視化,僅用於演示網格特徵。同樣,通常僅出於調試目的而啓用網格可視化

爲了開始AR體驗,該示例在主視圖控制器的 viewDidLoad 回調中配置並在應用程序首次啓動時運行會話。

arView.session.run(configuration)

三、添加平面檢測

當應用通過場景重建啓用平面檢測時,ARKit在製作網格時會考慮該信息。如果LiDAR掃描儀可能在真實表面上產生稍微不均勻的網格,則ARKit會在檢測到該表面上的平面的地方平滑網格。

爲了演示平面檢測對網格的影響,此應用程序顯示一個切換按鈕。在按鈕處理程序中,該示例調整了平面檢測配置並重新啓動了會話以實現更改。

@IBAction func togglePlaneDetectionButtonPressed(_ button: UIButton) {
    guard let configuration = arView.session.configuration as? ARWorldTrackingConfiguration else {
        return
    }
    if configuration.planeDetection == [] {
        configuration.planeDetection = [.horizontal, .vertical]
        button.setTitle("Stop Plane Detection", for: [])
    } else {
        configuration.planeDetection = []
        button.setTitle("Start Plane Detection", for: [])
    }
    arView.session.run(configuration)
}

四、在對象表面上找到一個點

使用網格檢索表面位置的應用程序可以達到前所未有的準確性。通過考慮網格,射線投射可以與非平面表面或具有很少或沒有特徵的表面(如白牆)相交。

爲了演示準確的光線投射結果,該應用程序在用戶點擊屏幕時投射光線。該示例根據需要指定了 .estimatedPlane 允許目標和對齊選項 .any,以檢索網格現實對象上的點。

let tapLocation = sender.location(in: arView)
if let result = arView.raycast(from: tapLocation, allowing: .estimatedPlane, alignment: .any).first {
    // ...

當用戶的射線投射返回結果時,此應用通過在交點處放置一個小球體來提供視覺反饋。

let resultAnchor = AnchorEntity(world: result.worldTransform)
resultAnchor.addChild(sphere(radius: 0.01, color: .lightGray))
arView.scene.addAnchor(resultAnchor, removeAfter: 3)

五、分類真實世界的對象

ARKit具有分類功能,可以分析其網格化的世界模型以識別特定的實際對象。在網格中,ARKit可以對地板,桌子,座椅,窗戶和天花板進行分類。請參閱完整列表ARMeshClassification

如果用戶點擊屏幕,並且射線投射與現實的網格物體相交,則此應用程序將顯示網格類別的文本。

ARViewautomaticallyConfigureSession屬性爲True時,默認情況下RealityKit禁用分類,因爲遮擋和物理過程不需要它。要啓用網格分類,樣本將sceneReconstruction屬性設置爲.meshWithClassification 來覆蓋默認值。

arView.automaticallyConfigureSession = false
let configuration = ARWorldTrackingConfiguration()
configuration.sceneReconstruction = .meshWithClassification

該應用程序嘗試從網格中檢索相交點的分類。

nearbyFaceWithClassification(to: result.worldTransform.position) {
 (centerOfFace, classification) in

網格中的每三個頂點形成一個三角形,稱爲面。ARKit爲每個面分配一個分類,因此樣本在網格中搜索相交點附近的面。如果臉部有分類,則此應用程序將其顯示在屏幕上。由於此例程涉及大量處理,示例將異步執行工作,所以渲染器不會停止。

DispatchQueue.global().async {
    for anchor in meshAnchors {
        for index in 0..<anchor.geometry.faces.count {
            // Get the center of the face so that we can compare it to the given location.
            let geometricCenterOfFace = anchor.geometry.centerOf(faceWithIndex: index)
            
            // Convert the face's center to world coordinates.
            var centerLocalTransform = matrix_identity_float4x4
            centerLocalTransform.columns.3 = SIMD4<Float>(geometricCenterOfFace.0, geometricCenterOfFace.1, geometricCenterOfFace.2, 1)
            let centerWorldPosition = (anchor.transform * centerLocalTransform).position
             
            // We're interested in a classification that is sufficiently close to the given location––within 5 cm.
            let distanceToFace = distance(centerWorldPosition, location)
            if distanceToFace <= 0.05 {
                // Get the semantic classification of the face and finish the search.
                let classification: ARMeshClassification = anchor.geometry.classificationOf(faceWithIndex: index)
                completionBlock(centerWorldPosition, classification)
                return
            }
        }
    }

有了分類,示例將創建3D文本以顯示它。

let textEntity = self.model(for: classification)

爲了防止網格物體部分遮擋文本,示例會稍微偏移文本以提高可讀性。該示例計算光線負向的偏移量,該偏移量可有效地將文本稍微移向遠離曲面的相機。

let rayDirection = normalize(result.worldTransform.position - self.arView.cameraTransform.translation)
let textPositionInWorldCoordinates = result.worldTransform.position - (rayDirection * 0.1)

爲了使文本始終在屏幕上顯示相同的大小,該示例將根據文本與相機的距離應用比例尺。

let raycastDistance = distance(result.worldTransform.position, self.arView.cameraTransform.translation)
textEntity.scale = .one * raycastDistance

爲了顯示文本,示例將其放在調整後的相交點的錨定實體中,該交點的方向是面向鏡頭。

var resultWithCameraOrientation = self.arView.cameraTransform
resultWithCameraOrientation.translation = textPositionInWorldCoordinates
let textAnchor = AnchorEntity(world: resultWithCameraOrientation.matrix)
textAnchor.addChild(textEntity)
self.arView.scene.addAnchor(textAnchor, removeAfter: 3)

爲了從檢索的分類中可視化表面頂點的位置,該樣本在頂點的真實位置上創建了一個小球體。

if let centerOfFace = centerOfFace {
    let faceAnchor = AnchorEntity(world: centerOfFace)
    faceAnchor.addChild(self.sphere(radius: 0.01, color: classification.color))
    self.arView.scene.addAnchor(faceAnchor, removeAfter: 3)
}

六、用網格遮擋虛擬內容

遮擋是一種功能,從攝像機的角度來看,現實世界的某些部分覆蓋了應用程序的虛擬內容。爲了實現這種幻覺,RealityKit 會檢查用戶查看的虛擬內容之前是否存在任何網格,並省略繪製那些網格遮蓋的虛擬內容的任何部分的操作。該示例通過將occlusion選項添加到環境的sceneUnderstanding屬性中來啓用遮擋。

arView.environment.sceneUnderstanding.options.insert(.occlusion)

在運行時,此應用程序忽略了虛擬文本在網狀現實世界任何部分後面的繪製部分。

七、使用物理與現實世界的物體互動

使用場景網格,虛擬內容可以與物理環境進行實際交互,因爲網格爲RealityKit的物理引擎提供了一個精確的世界模型。該示例通過將physics選項添加到環境的 sceneUnderstanding 屬性中來啓用物理學。

爲了檢測虛擬內容何時與網狀現實對象接觸,該示例使用擴展名中的碰撞形狀定義了文本的大小。在Scene的擴展 addAnchor(_:,removeAfter:) 方法中。

Timer.scheduledTimer(withTimeInterval: seconds, repeats: false) { (timer) in
    model.physicsBody?.mode = .dynamic
}

當文本掉落時,它與網狀現實世界對象(例如降落在地板上)碰撞時會做出反應。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章