与重建的场景可视化和交互

1,552 阅读6分钟

使用多边形网格估计物理环境的形状。 developer.apple.com/videos/play…

概述

在运行iPad OS 13.4或更高版本的第四代iPad Pro上,ARKit使用激光雷达扫描仪创建物理环境的多边形模型。激光雷达扫描仪从用户面前的广阔区域快速检索深度信息,因此ARKit无需用户移动即可估计现实世界的形状。ARKit将深度信息转换为一系列顶点,这些顶点连接起来形成网格。要对信息进行分区,ARKit制作多个锚,每个锚分配网格的唯一部分。总的来说,网格锚代表了用户周围的现实世界场景

使用这些网格,您可以:

-更准确地定位现实世界表面上的点。

-对ARKit可以识别的现实世界对象进行分类。

-用前面的真实对象遮挡应用程序的虚拟内容。

-让虚拟内容现实地与物理环境互动,例如,将虚拟球从现实世界的墙上弹下来,并让球遵循物理定律。

此示例应用程序展示了使用RealityKit的AR体验。下图说明了RealityKit如何利用ARKit的现实世界信息,并在您运行此应用程序并将设备指向现实世界的椅子时创建调试可视化。

image.png

可视化物理环境的形状

要启用场景网格,示例将世界配置的sceneReconstruction属性设置为网格选项之一。

image.png

示例使用RealityKit的[ARView](developer.apple.com/documentati…

arView.debugOptions.insert(.showSceneUnderstanding)

示例仅启用网格可视化以演示网格功能;同样,您通常仅出于调试目的启用网格可视化。

为了开始AR体验,示例在应用程序首次启动时,在主视图控制器的“viewDidLoad”回调中配置并运行会话。

arView.session.run(configuration)

添加平面检测

当应用程序通过场景重建启用平面检测时,ARKit在制作网格时会考虑这些信息。当激光雷达扫描仪可能在现实世界的表面上产生略微不均匀的网格时,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)
}

在物体表面上找到一个点

使用网格检索表面位置的应用程序可以实现前所未有的准确性。通过考虑网格,光线投射可以与非平面表面或特征很少或没有特征的表面(如白色墙壁)相交。

为了演示准确的光线投射结果,当用户轻点屏幕时,此应用程序会投射光线。示例指定了ARRaycastQuery.Target.estimatedPlane allowable-target和ARRaycastQuery.TargetAlignment.any对齐选项,以检索网格现实世界对象上的点。

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

image.png

当用户的光线投射返回结果时,此应用程序通过在交叉点放置一个小球体来提供视觉反馈。

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

image.png

###对现实世界的对象进行分类

ARKit有一个分类功能,可以分析其网格世界模型,以识别特定的现实世界对象。在网格中,ARKit可以对地板、桌子、座椅、窗户和天花板进行分类。有关完整列表,请参阅[ARMeshClassification](developer.apple.com/documentati…

如果用户轻点屏幕,并且光线广播与网格化的真实物体相交,此应用程序将显示网格分类的文本。

image.png

ARView属性的[automaticallyConfigureSession](developer.apple.com/documentati…](developer.apple.com/documentati…](developer.apple.com/documentati…

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

此应用程序尝试从网格中检索交点的分类。

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

网格中的每三个顶点形成一个三角形,称为*面。*ARKit为每个面孔分配分类,因此示例在网格中搜索交叉点附近的面孔。如果面部有分类,此应用程序将显示在屏幕上。由于此例程涉及广泛的处理,样本异步工作,因此渲染器不会停止。

网格中的每三个顶点形成一个三角形,称为*面。*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)
}

image.png

用网格遮挡虚拟内容

从相机的角度来看,遮挡是一项功能,现实世界的一部分覆盖了应用程序的虚拟内容。为了实现这At runtime, this app omits drawing portions of the virtual text that are behind any part of the meshed, real world.种错觉,RealityKit检查用户查看的虚拟内容前面是否有任何网格,并省略了绘制被这些网格遮挡的虚拟内容的任何部分。示例通过将[occlusion](developer.apple.com/documentati…

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

在运行时,此应用程序省略了网格化现实世界任何部分后面的虚拟文本的绘图部分。

image.png

使用物理与现实世界的物体互动

使用场景网格,虚拟内容可以现实地与物理环境交互,因为网格为RealityKit的物理引擎提供了准确的世界模型。该示例通过将[physics'](https://developer.apple.com/documentation/realitykit/arview/environment/sceneunderstanding/options/3521435-physics)选项添加到环境的[sceneUnderstanding`](developer.apple.com/documentati…

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

为了检测虚拟内容何时与网格化的现实世界对象接触,示例使用addAnchor(_:,removeAfter:)场景扩展中的碰撞形状定义文本的比例。

if model.collision == nil {   
model.generateCollisionShapes(recursive: true)   
model.physicsBody = .init()}

当此应用程序对对象进行分类并显示一些文本时,它会等待三秒钟后删除虚拟文本。当示例将文本的physicsBodymode设置为PhysicsBodyMode.dynamic时,文本会以下降对重力做出反应。

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

当文本下降时,当它与网格化的现实世界物体碰撞时会做出反应,例如降落在地板上。

image.png