首页 文章

如何使用ARKit和Gesture Recognizer移动和旋转SCNode?

提问于
浏览
0

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

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

我尝试了以下两个链接,但它只是在特定轴上移动子节点,但在用户移动手指时不能随意移动 .

ARKit - Drag a node along a specific axis (not on a plane)

Dragging SCNNode in ARKit Using SceneKit

此外,我尝试用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)
        }

1 回答

  • 1

    移动对象:

    执行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)
        }
    }
    

相关问题