0

我正在使用 ARKit(SceneKit) 开发基于 AR 的 iOS 应用程序。我使用 Apple 示例代码https://developer.apple.com/documentation/arkit/handling_3d_interaction_and_ui_controls_in_augmented_reality作为此基础。使用它我可以移动或旋转整个虚拟对象。

但我想使用用户手指选择和移动/旋转虚拟对象中的子节点,类似于我们如何移动/旋转整个虚拟对象本身。

我尝试了以下两个链接,但它只是在特定轴上移动子节点,而不是在用户移动手指时自由移动到任何地方。

ARKit - 沿特定轴(不在平面上)拖动节点

使用 SceneKit 在 ARKit 中拖动 SCNNode

我也尝试用 SCNode 替换作为 SCNReferenceNode 的虚拟对象,以便现有虚拟对象存在的任何功能也适用于子节点,它不起作用。

谁能帮助我了解如何自由移动/旋转虚拟对象以及虚拟对象的子节点?

请在下面找到我当前使用的代码,

       let tapPoint: CGPoint = gesture.location(in: sceneView)
        let result = sceneView.hitTest(tapPoint, options: nil)
        if result.count == 0 {
            return
        }
        let scnHitResult: SCNHitTestResult? = result.first
        movedObject = scnHitResult?.node //.parent?.parent

        let hitResults = self.sceneView.hitTest(tapPoint, types: .existingPlane)
        if !hitResults.isEmpty{
            guard let hitResult = hitResults.last else { return }
            movedObject?.position = SCNVector3Make(hitResult.worldTransform.columns.3.x, hitResult.worldTransform.columns.3.y, hitResult.worldTransform.columns.3.z)
        }
4

1 回答 1

2

移动对象:

执行 hitTest 以检查您触摸的位置,并检测您触摸的平面并获得位置。通过使用 SCNVector3 更改 node.position 值,将 SCNNode 移动到该位置。

代码:

@objc func panDetected(recognizer: UIPanGestureRecognizer){
let hitResult = self.arSceneView.hitTest(loc, types: .existingPlane)
if !hitResult.isEmpty{
guard let hitResult = hitResult.last else { return }
self.yourNode.position = SCNVector3Make(hitResult.worldTransform.columns.3.x, hitResult.worldTransform.columns.3.y, hitResult.worldTransform.columns.3.z)
}

上面的代码足以将您的节点移动到检测到的平面上,在您触摸的任何地方,而不仅仅是在单个轴上。

根据您的手势旋转节点是一项非常艰巨的任务,我已经研究了很长一段时间的解决方案,但从未达到完美的输出。但是,我在 GitHub 中遇到了这个存储库,它可以让您以非常令人印象深刻的结果做到这一点。 https://github.com/Xartec/ScreenSpaceRotationAndPan

使用手势旋转节点所需的 Swift 版本代码是:

var previousLoc: CGPoint?
var touchCount: Int?

@objc func panDetected(recognizer: UIPanGestureRecognizer){

    let loc = recognizer.location(in: self.view)
    var delta = recognizer.translation(in: self.view)

    if recognizer.state == .began {
        previousLoc = loc
        touchCount = recognizer.numberOfTouches
    }
    else if gestureRecognizer.state == .changed {
        delta = CGPoint.init(x: 2 * (loc.x - previousLoc.x), y: 2 * (loc.y - previousLoc.y))
        previousLoc = loc
        if touchCount != recognizer.numberOfTouches {
            return
        }
        var rotMatrix: SCNMatrix4!
        let rotX = SCNMatrix4Rotate(SCNMatrix4Identity, Float((1.0/100) * delta.y), 1, 0, 0)
        let rotY = SCNMatrix4Rotate(SCNMatrix4Identity, Float((1.0 / 100) * delta.x), 0, 1, 0)
        rotMatrix = SCNMatrix4Mult(rotX, rotY)

        let transMatrix = SCNMatrix4MakeTranslation(yourNode.position.x, yourNode.position.y, yourNode.position.z)
        self.yourNode.transform = SCNMatrix4Mult(self.yourNode.transform, SCNMatrix4Invert(transMatrix))
        let parentNoderanslationMatrix = SCNMatrix4MakeTranslation((self.yourNode.parent?.worldPosition.x)!, (self.yourNode.parent?.worldPosition.y)!, (self.yourNode.parent?.worldPosition.z)!)
        let parentNodeMatWOTrans = SCNMatrix4Mult((self.yourNode.parent?.worldTransform)!, SCNMatrix4Invert(parentNoderanslationMatrix))
        self.yourNode.transform = SCNMatrix4Mult(self.yourNode.transform, parentNodeMatWOTrans)
        let camorbitNodeTransMat = SCNMatrix4MakeTranslation((self.arSceneView.pointOfView?.worldPosition.x)!, (self.arSceneView.pointOfView?.worldPosition.y)!, (self.arSceneView.pointOfView?.worldPosition.z)!)
        let camorbitNodeMatWOTrans = SCNMatrix4Mult((self.arSceneView.pointOfView?.worldTransform)!, SCNMatrix4Invert(camorbitNodeTransMat))
        self.yourNode.transform = SCNMatrix4Mult(self.yourNode.transform, SCNMatrix4Invert(camorbitNodeMatWOTrans))
        self.yourNode.transform = SCNMatrix4Mult(self.yourNode.transform, rotMatrix)
        self.yourNode.transform = SCNMatrix4Mult(self.yourNode.transform, camorbitNodeMatWOTrans)
        self.yourNode.transform = SCNMatrix4Mult(self.yourNode.transform, SCNMatrix4Invert(parentNodeMatWOTrans))
        self.yourNode.transform = SCNMatrix4Mult(self.yourNode.transform, transMatrix)
    }
}
于 2018-05-23T08:05:32.130 回答