swift ARAnchor到底是什么?

a0x5cqrl  于 2022-12-17  发布在  Swift
关注(0)|答案(1)|浏览(216)

我正在努力理解和使用ARKit,但有一件事我不能完全理解。
苹果对ARAnchor表示:
可用于在AR场景中放置对象的真实位置和方向。
但这还不够。所以我的问题是:

  • ARAnchor到底是什么?
  • 锚点和特征点之间有什么区别?
  • ARAnchor只是特征点的一部分吗?
  • ARKit如何确定其锚点?
mwecs4sa

mwecs4sa1#

更新日期:2022年12月16日

靶区;DR

A锚钉

ARAnchor是一个不可见的空对象,它将3D模型固定在锚点位置。将ARAnchor想象成一个带有局部轴的parent transform node(可以平移、旋转和缩放)。每个3D模型都有一个枢轴点,对吗?因此,在ARKit中,这个枢轴点必须与ARAnchor相交。
如果您在ARKit应用中不使用锚点(在RealityKit中,不使用锚点是不可能的,因为它们是场景的一部分),您的3D模型可能会偏离放置位置,这将极大地影响应用的真实感和用户体验。

根据ARKit 2017文档:
ARAnchor是一个真实世界的位置和方向,可用于在AR场景中放置对象。将锚添加到会话中有助于ARKit优化锚点周围区域的世界跟踪准确性,以便虚拟对象相对于真实世界保持在适当位置。如果虚拟对象移动,请从旧位置删除相应的锚点,并在新位置添加一个锚点。
ARAnchor是ARKit中其他10个锚类型的父类,因此所有这些子类都继承自ARAnchor。通常情况下,您不会直接使用ARAnchor。我还必须说,ARAnchorFeature Points没有任何共同之处。Feature Points是用于跟踪和调试的相当特殊的可视化元素。
ARAnchor不会自动跟踪真实的世界的目标。当你需要自动化时,你必须使用renderer()session()示例方法,它们可以在你分别遵守ARSCNViewDelegateARSessionDelegate协议的情况下实现。
下面是平面锚的可视化表示图像。请记住:默认情况下,你既看不到检测到的平面,也看不到它对应的ARPlaneAnchor。因此,如果你想看到场景中的锚,你可以使用三个细SCNCylinder图元来“可视化”它。圆柱体的每种颜色代表一个特定的轴:所以RGB就是XYZ。

在ARKit中,您可以使用不同的场景自动将ARAnchors添加到您的场景中
*ARplane定位点

  • 如果水平和/或垂直**planeDetection**示例属性为ON,ARKit可以在运行会话中添加ARPlaneAnchors。有时启用planeDetection会大大增加场景理解阶段所需的时间。
    ARImageAnchor 符合ARTrackable协议 *)

  • 这种类型的锚点包含关于检测到的图像的位置、取向和比例的信息(锚放置在图像中心)。要激活图像跟踪,请使用**detectionImages**示例属性。在ARKit 2.0中,您最多可以跟踪25张图像,在ARKit 3.0 / 4.0中,最多可以跟踪100张图像。但是,在这两种情况下,最多只能同时检测4张图像。然而,在ARKit 5.0 / 6.0中,你可以同时检测和跟踪多达100张图像(但它还没有实现)。
    ARBodyAnchor 符合ARTrackable方案 *)

  • 您可以通过运行基于**ARBodyTrackingConfig()**的会话来启用身体跟踪。您将在CG backbone 的Root Joint处获得ARBodyAnchor,或者换句话说,在被跟踪角色的骨盆位置处获得ARBodyAnchor。
    ARFaceAnchor 符合ARTrackable协议 *)

  • Face锚存储头部拓扑结构、姿势和面部表情的信息。您可以在前置TrueDepth摄像头的帮助下跟踪ARFaceAnchor。当检测到面部时,Face Anchor将附着在鼻子后面,位于面部中心。在ARKit 2.0中,您只能跟踪一张面部,在ARKit 3.0及更高版本中,您可以同时跟踪多达3张面部。然而,跟踪的面部数量取决于TrueDepth传感器和处理器版本的存在:配备TrueDepth摄像头的小工具最多可以跟踪3张脸,配备A12+芯片组但不配备TrueDepth摄像头的小工具最多也可以跟踪3张脸。
    *对象定位点

  • 此锚的类型保留有关在世界跟踪会话中检测到的真实世界3D对象的6个自由度(位置和方向)的信息。请记住,您需要为会话配置的detectionObjects属性指定ARReferenceObject示例。
    *A环境探测器锚点

  • 探测锚在世界跟踪会话中提供空间特定区域的环境照明信息。ARKit的人工智能使用它来为反射着色器提供环境反射。
    *AR参与者锚定

  • 这是多用户AR体验中不可缺少的锚类型,如果要使用,可以在ARWorldTrackingConfig中将isCollaborationEnabled属性使用true值,然后导入MultipeerConnectivity框架。
    *臂网锚固件

  • ARKit和LiDAR将重建的用户周围的真实场景细分为具有相应多边形几何形状的网格锚点。随着ARKit对真实世界的理解不断完善,网格锚点会不断更新其数据。尽管ARKit会更新网格以反映物理环境的变化,网格的后续更改并不打算真实的反映。有时您重建的场景可以有多达**30-40 anchors**或更多。这是因为每个分类对象(墙、椅子、门或table)都有自己的个人锚。每个ARMeshAnchor存储关于相应顶点的数据,八种分类情况之一,其面和顶点的法线。
    *ARGeoAnchor(符合 * ARTrackable * 协议)

  • 在ARKit 4.0+中有一个地理锚(又称位置锚),它使用GPS、苹果Map和来自苹果服务器的其他环境数据来跟踪地理位置。这种类型的锚点标识了应用可以参考的世界上的特定区域。当用户在场景中移动时,会话根据地理锚点的坐标和设备的罗盘指向更新位置锚点的转换。查看supported cities列表。
    *ARAppClipCodeAnchor(符合 * ARTrackable * 协议)

  • 此锚在ARKit 4.0+中跟踪App Clip Code在物理环境中的位置和方向。您可以使用App Clip Code使用户能够在真实的世界中发现您的App Clip。有集成NFC的App Clip Code和仅扫描的App Clip Code。

在AR会话中创建锚点还有其他常规方法
*点击测试方法

  • 点击屏幕,将一个点投影到一个不可见的检测平面上,将ARAnchor放置在假想光线与该平面相交的位置。顺便说一下,ARHitTestResult类及其对应的ARSCN视图和ARSKView命中测试方法将在iOS 14中弃用,因此您必须习惯光线投射。
    *光线投射方法
  • 如果你使用光线投射,点击屏幕会在一个不可见的检测平面上产生一个投影的3D点。但是你也可以在3D场景中的A和B位置之间执行光线投射。因此,光线投射可以是2D到3D和3D到3D。当使用跟踪光线投射时,ARKit可以随着对检测表面的了解越来越多而不断细化光线投射。
    *特征点
  • ARKit在真实世界对象的高对比度边缘自动生成的特殊黄点可以为您提供放置ARanchor的位置。
    *ARCamera的变换
  • iPhone或iPad的摄像头位置和方向simd_float4x4可以很容易地用作ARAnchor的位置。
    *任意世界位置
  • 在场景中的任意位置放置一个自定义的ARWorldAnchor,您可以生成ARKit版本的world anchor,就像RealityKit中的AnchorEntity(.world(transform: mtx))一样。

此代码段演示如何在委托的方法中使用ARPlaneAnchor:renderer(_:didAdd:for:)

func renderer(_ renderer: SCNSceneRenderer, 
             didAdd node: SCNNode, 
              for anchor: ARAnchor) {
    
    guard let planeAnchor = anchor as? ARPlaneAnchor 
    else { return }

    let grid = Grid(anchor: planeAnchor)
    node.addChildNode(grid)
}

锚实体

AnchorEntity是RealityKit中的阿尔法和欧米茄。根据RealityKit文档2019:

AnchorEntity是在AR会话中将虚拟内容与现实对象绑定的锚。

RealityKit框架和Reality Composer应用程序在WWDC'19上发布。它们有一个名为AnchorEntity的新类。您可以使用AnchorEntity作为任何实体层次结构的根点。并且必须将其添加到场景锚点集合中。AnchorEntity自动跟踪真实的世界目标。在RealityKit和Reality Composer中,AnchorEntity位于层次结构的顶部。这个锚可以容纳一百个模特,在这种情况下,它比每个模特使用100个个人锚更稳定。

让我们看看它在代码中的样子:

func makeUIView(context: Context) -> ARView {
    
    let arView = ARView(frame: .zero)
    let modelAnchor = try! Experience.loadModel()
    arView.scene.anchors.append(modelAnchor)
    return arView
}

**AnchorEntity**有三个组件:

要找出ARAnchorAnchorEntity之间的区别,请查看此帖子
以下是RealityKit 2.0 for iOS中提供的9个AnchorEntity案例:

// Fixed position in the AR scene
AnchorEntity(.world(transform: mtx)) 

// For body tracking (a.k.a. Motion Capture)
AnchorEntity(.body)

// Pinned to the tracking camera
AnchorEntity(.camera)

// For face tracking (Selfie Camera config)
AnchorEntity(.face)

// For image tracking config
AnchorEntity(.image(group: "GroupName", name: "forModel"))

// For object tracking config
AnchorEntity(.object(group: "GroupName", name: "forObject"))

// For plane detection with surface classification
AnchorEntity(.plane([.any], classification: [.seat], minimumBounds: [1, 1]))

// When you use ray-casting
AnchorEntity(raycastResult: myRaycastResult)

// When you use ARAnchor with a given identifier
AnchorEntity(.anchor(identifier: uuid))

// Creates anchor entity on a basis of ARAnchor
AnchorEntity(anchor: arAnchor)

以下是RealityKit 2.0 for macOS中仅有的两个AnchorEntity案例:

// Fixed world position in VR scene
AnchorEntity(.world(transform: mtx))

// Camera transform
AnchorEntity(.camera)

此外,您可以使用ARAnchor的任何子类来满足AnchorEntity的需求,这一点也不是多余的:

var anchor = AnchorEntity()

func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {

    guard let faceAnchor = anchors.first as? ARFaceAnchor 
    else { return }

    arView.session.add(anchor: faceAnchor)           // ARKit Session

    self.anchor = AnchorEntity(anchor: faceAnchor)
    anchor.addChild(model)        
    arView.scene.anchors.append(self.anchor)         // RealityKit Scene
}

Reality Composer的主播:

目前(2022年2月)Reality Composer仅有4种类型的锚点实体:

// 1a
AnchorEntity(plane: .horizontal)

// 1b
AnchorEntity(plane: .vertical)

// 2
AnchorEntity(.image(group: "GroupName", name: "forModel"))

// 3
AnchorEntity(.face)

// 4
AnchorEntity(.object(group: "GroupName", name: "forObject"))

AR USD方案

当然,我应该说几句关于初步锚点的话。对于那些喜欢使用Python脚本来编写USDZ模型的人,有3种初步锚点类型(2022年7月)--它们是planeimageface初步锚点。请查看此代码片段,了解如何以Python方式实现模式。

def Cube "ImageAnchoredBox"(prepend apiSchemas = ["Preliminary_AnchoringAPI"])
{
    uniform token preliminary:anchoring:type = "image"
    rel preliminary: imageAnchoring:referenceImage = <ImageReference>

    def Preliminary_ReferenceImage "ImageReference"
    {
        uniform asset image = @somePicture.jpg@
        uniform double physicalWidth = 45
    }
}

如果您想了解更多关于AR USD模式的信息,请阅读Meduim上的this story

可视化定位实体

下面是一个如何在RealityKit(mac版本)中可视化锚点的示例。

import AppKit
import RealityKit

class ViewController: NSViewController {
    
    @IBOutlet var arView: ARView!
    var model = Entity()
    let anchor = AnchorEntity()

    fileprivate func visualAnchor() -> Entity {

        let colors: [SimpleMaterial.Color] = [.red, .green, .blue]

        for index in 0...2 {
            
            let box: MeshResource = .generateBox(size: [0.20, 0.005, 0.005])
            let material = UnlitMaterial(color: colors[index])              
            let entity = ModelEntity(mesh: box, materials: [material])

            if index == 0 {
                entity.position.x += 0.1

            } else if index == 1 {
                entity.transform = Transform(pitch: 0, yaw: 0, roll: .pi/2)
                entity.position.y += 0.1

            } else if index == 2 {
                entity.transform = Transform(pitch: 0, yaw: -.pi/2, roll: 0)
                entity.position.z += 0.1
            }
            model.scale *= 1.5
            self.model.addChild(entity)
        }
        return self.model
    }

    override func awakeFromNib() {
        anchor.addChild(self.visualAnchor())
        arView.scene.addAnchor(anchor)
    }
}

关于ARCore中的ArAnchors

在文章的最后,我想谈谈ARCore 1.33中使用的四种类型的锚点。Google的官方文档对锚点做了如下说明:“ArAnchor描述了真实的世界中的固定位置和方向"。ARCore锚点的工作原理与ARKit锚点类似。
让我们来看看ArAnchors的类型:

*本地锚

  • 与应用程序一起存储在本地,并且仅对该应用程序示例有效。用户必须实际位于放置锚的位置。锚点可以连接到Trackable或ARCore Session
    *云锚
  • 存储在Google Cloud中,可在应用示例之间共享。用户必须实际位于放置锚的位置。云锚点是托管在云中的锚点(对于X1 M54 N1 X,你可以创建一个云锚点,该云锚点可以在创建后的一天到365天内被解析)。这些问题可由多个用户解决,以在用户及其设备之间建立通用参考框架。
    *地理空间锚点
  • 基于大地纬度、经度和高度,加上Google的Visual Positioning System数据,可提供世界上几乎任何地方的精确位置;这些锚点可以在应用程序示例之间共享。2只要应用程序连接到互联网并能够使用VPS,用户就可以从远程位置放置锚点。
    *地形定位
  • 是地理空间锚的一个子类型,允许您仅使用纬度和经度放置AR对象,利用GoogleMap中的信息来查找距地面的精确高度。

当在ARCore中锚定对象时,请确保它们靠近您正在使用的锚点。避免将对象放置在距离锚点8米以外的位置,以防止由于ARCore更新世界空间坐标而导致意外的旋转移动。如果需要将对象放置在距离现有锚点8米以外的位置,请创建一个更靠近此位置的新锚点,并将对象附加到新锚点。
这些Kotlin代码片段向您展示了如何使用地理空间锚:

fun configureSession(session: Session) {
    session.configure(
        session.config.apply {
            geospatialMode = Config.GeospatialMode.ENABLED
        }
    )
}
val earth = session?.earth ?: return

if (earth.trackingState != TrackingState.TRACKING) { return }
earthAnchor?.detach()

val altitude = earth.cameraGeospatialPose.altitude - 1
val qx = 0f; val qy = 0f; val qz = 0f; val qw = 1f

earthAnchor = earth.createAnchor(latLng.latitude, 
                                 latLng.longitude, 
                                 altitude, 
                                 qx, qy, qz, qw)

相关问题