具有先前设备位置的 ARKit 项目点

fan*_*ant 2 scenekit swift arkit

我将 ARKit 与 CNN 结合起来,以在 ARKit 节点漂移时不断更新它们。所以:

  1. 使用 ARKit 估计节点位置并在世界中放置一个虚拟对象
  2. 使用CNN获取其估计的物体二维位置
  3. 相应地更新节点位置(以优化其在 3D 空间中的位置)

问题是#2 需要 0.3s 左右。因此我无法使用,sceneView.unprojectPoint因为该点将对应于来自 #1 的设备世界位置的 3D 点。

如何计算从我的旧位置到 CNN 的 2D 点的 3D 矢量?

ric*_*ter 5

unprojectPoint只是一个矩阵数学便利函数,类似于许多面向图形的库(如 DirectX、旧式 OpenGL、Three.js 等)中的函数。在 SceneKit 中,它作为视图上的一个方法提供,这意味着它使用模型/视图/投影矩阵和视图当前用于渲染的视口进行操作。但是,如果您知道该函数的工作原理,则可以自己实现它。

Unproject 函数通常会做两件事:

  1. 将视口坐标(像素)转换为剪辑空间坐标系(所有方向上的 -1.0 到 1.0)。

  2. 反转投影变换(假设剪辑空间中有一些任意 Z 值)和视图(相机)变换以获得 3D 世界空间坐标。

有了这些知识,我们就可以构建自己的功能。(警告:未经测试。)

func unproject(screenPoint: float3, // see below for Z depth hint discussion
                 modelView: float4x4,
                projection: float4x4,
                  viewport: CGRect) -> float3 {

    // viewport to clip: subtract viewport origin, divide by size, 
    // scale/offset from 0...1 to -1...1 coordinate space
    let clip = (screenPoint - float3(viewport.x, viewport.y, 1.0))
               / float3(viewport.width, viewport.height, 1.0)
               * float3(2) - float3(1)
    // apply the reverse of the model-view-projection transform
    let inversePM = (projection * modelView).inverse
    let result = inversePM * float4(clip.x, clip.y, clip.z, 1.0)
    return float3(result.x, result.y, result.z) / result.w // perspective divide
}
Run Code Online (Sandbox Code Playgroud)

现在,使用它...modelView您传递给该函数的矩阵是 的逆矩阵ARCamera.transform,您也可以projectionMatrix直接从ARCamera. 因此,如果您在某个时间点抓取 2D 位置,那么也可以抓取相机矩阵,这样您就可以在那个时候向后工作到 3D。

我提到的“Z 深度提示”仍然存在问题:当渲染器将 3D 投影到 2D 时,它会丢失信息(实际上是那些 D 之一)。因此,当您转换回 3D 时,您必须恢复或猜测该信息——screenPoint您传递给上述函数的是 x 和 y 像素坐标,加上 0 和 1 之间的深度值。零离相机更近,1 是更远。如何使用这种类型取决于算法的其余部分是如何设计的。(至少,您可以同时取消投影 Z=0 和 Z=1,并且您将获得 3D 线段的端点,您的原始点沿着该线的某处。)

当然,这是否真的可以与您新颖的基于 CNN 的方法结合起来完全是另一个问题。但至少你学到了一些有用的 3D 图形数学!