测量ARKit中两个ARImageAnchor之间的距离

时间:2020-01-27 03:11:41

标签: swift image arkit detection measure

TL; DR;

是否可以向连接到ARImageAnchor的一个SCNNode添加SCNAction,从而将该节点移动到连接到另一个ARImageAnchor的另一个SCNNode?

我的本​​科论文涉及重现此video中的行为。我正在使用ARKit,而iOS版本或设备功能并不是很重要。

我要实现的目标是在两个不同的SCNNode足够接近时加入它们,但是它们的位置信息似乎很不规则,似乎与场景中的实际位置不符。

当我打印有关正在处理的两个节点的信息时,lldb会给我这样的数字:

  • 对象X:

锚点.tranform.columns.3

SIMD4<Float>(0.019269282, -0.2338481, -0.2880894, 1.0)

节点.worldPosition

▿ Optional<SCNVector3>
  ▿ some : SCNVector3
    - x : 0.019269282
    - y : -0.2338481
    - z : -0.2880894
  • 对象Y:

锚点.tranform.columns.3

SIMD4<Float>(-7.6405444, -25.205889, -26.780603, 1.0)

节点.worldPosition

▿ Optional<SCNVector3>
  ▿ some : SCNVector3
    - x : -7.6405444
    - y : -25.205889
    - z : -26.780603

我的意思是,为什么两个物体的位置之间有很大差异? (均针对其锚点和节点的位置)。他们的父母是平等的(场景的根节点)并且在同一场景中,难道他们不应该给我每个节点至少相似的位置吗?

在测量两个对象之间的距离时,我注意到以下代码

guard let p1 = a0.atomAnchor?.transform.simd_vector3,
     let p2 = a1.atomAnchor?.transform.simd_vector3 else { return }

     let d = simd_distance(p1, p2)
     print(d)

我会采取不一致的措施,具体取决于相机在打印图像和手机相机之间的距离。

我的ARSessionDelegate执行以下操作:

extension ViewController: ARSessionDelegate {
    
    var minimumDistanceBetweenAtoms: Float {
        return 50
    }
    
    // MARK:- Delegate method
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        guard let imageAnchor = anchor as? ARImageAnchor else {
            print("anchor not found")
            return
        }

        guard let worldScene = sceneView?.scene else { print("Scene not initialized"); return }
        guard let atomFound = atoms.first(where: { $0.referenceImage.name == imageAnchor.referenceImage.name }) else {
            print("atom not found in resources")
            return
        }

        guard atomFound.type != .referenceObject else { return }
        visibleAtoms.append(atomFound)
        atomFound.initializeAtom(inScene: worldScene, withAnchor: imageAnchor)
    }
    
    
    func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        guard let imageAnchor = anchor as? ARImageAnchor else {
            print("anchor not found")
            return
        }
        visibleAtoms.forEach({
            guard !$0.flag else { return }
            $0.didUpdateTo(anchor: imageAnchor)
        })
    }

    func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
        visibleAtoms.forEach({ [weak self] a0 in
            guard !a0.isMoving(), !a0.flag else { return }
            
            self?.visibleAtoms.forEach({ a1 in
                guard !a1.isMoving(), !(a1 === a0), !a0.flag else { return }
                
                guard let p1 = a0.atomAnchor?.transform.simd_vector3,
                    let p2 = a1.atomAnchor?.transform.simd_vector3 else { return }
                
                
                let d = simd_distance(p1, p2)
                print(d)
                if d < minimumDistanceBetweenAtoms {
                    if let molecule = a0.combination(withAtom: a1) {
                        a0.flag = true
                        a1.flag = true
                    }
                }
            })
        })
    }
    
}

考虑将Atom类用作节点行为的封装器:

    func initializeAtom(inScene scene: SCNScene, withAnchor anchor: ARImageAnchor) {
        guard let object = type.atomObject() else { return }
        
        let (min, max) = object.boundingBox
        let size = SCNVector3Make(max.x - min.x, max.y - min.y, max.z - min.z)
        
        let widthRatio = Float(anchor.referenceImage.physicalSize.width) / size.x
        let heightRatio = Float(anchor.referenceImage.physicalSize.height) / size.z
        object.transform = SCNMatrix4(anchor.transform)
        
        guard let finalRatio = [widthRatio, heightRatio].min() else { return }
        
        let appearanceAction = SCNAction.scale(to: CGFloat(finalRatio / 2), duration: 0.4)
        appearanceAction.timingMode = .easeOut
        object.scale = SCNVector3Make(0, 0, 0)
        scene.rootNode.addChildNode(object)
        object.runAction(appearanceAction)
        
        
        atomAnchor = anchor
        atomScene = scene
        atomObject = object
    }
    
    func didUpdateTo(anchor: ARImageAnchor) {
        guard anchor == atomAnchor else { return }
        atomAnchor = anchor
        if isMoving() { atomObject?.removeAction(forKey: "movement") }
        moveTo(newAnchor: anchor)
    }
    
    private func moveTo(newAnchor: ARAnchor, withDurationOf duration: TimeInterval = 0.3) {
        let action = SCNAction.move(to: newAnchor.transform.vector3, duration: duration)
        atomObject?.runAction(action, forKey: "movement")
    }

我的ARWorldTrackingConfiguration只是设置参考图像并使用参数[.resetTracking, .removeExistingAnchors]运行。

我有一个Utils文件来放置我需要的所有可用扩展,这是我在这段代码中使用的部分:

extension simd_float4x4 {
    
    var vector3: SCNVector3 {
        return SCNVector3(columns.3.x, columns.3.y, columns.3.z)
    }
    
    var simd_vector3: simd_float3 {
        return simd_float3(columns.3.x, columns.3.y, columns.3.z)
    }
    
}

PS:Github code

0 个答案:

没有答案
相关问题