web-dev-qa-db-fra.com

Glisser SCNNode dans ARKit à l'aide de SceneKit

J'ai un simple SCNNode dans ARKit et j'essaie de le faire glisser partout où j'ai déplacé mon doigt sur le téléphone. Voici mon code.

 @objc func pan(recognizer :UIGestureRecognizer) {

        guard let currentFrame = self.sceneView.session.currentFrame else {
            return
        }

        var translation = matrix_identity_float4x4
        translation.columns.3.z = -1.5

        let sceneView = recognizer.view as! ARSCNView
        let touchLocation = recognizer.location(in: sceneView)

        let hitTestResult = sceneView.hitTest(touchLocation, options: [:])

        if !hitTestResult.isEmpty {

            print("hit result")

            guard let hitResult = hitTestResult.first else {
                return
            }

            let node = hitResult.node

            node.simdTransform = matrix_multiply(currentFrame.camera.transform, translation)
        }
    }

Le problème est que la traînée est très lente et non lisse.

11
john doe

Je gère la traduction avec PanGesture comme ceci. La division par 700 consiste à lisser et à ajuster la vitesse de déplacement. J'ai atteint cette valeur par essai ou erreur. Vous pouvez expérimenter.

@objc func onTranslate(_ sender: UIPanGestureRecognizer) {
    let position = sender.location(in: scnView)
    let state = sender.state

    if (state == .failed || state == .cancelled) {
        return
    }

    if (state == .began) {
        // Check it's on a virtual object
        if let objectNode = virtualObject(at: position) {
            // virtualObject(at searches for root node if it's a subnode
            targetNode = objectNode
            latestTranslatePos = position
        }

    }
    else if let _ = targetNode {

        // Translate virtual object
        let deltaX = Float(position.x - latestTranslatePos!.x)/700
        let deltaY = Float(position.y - latestTranslatePos!.y)/700

        targetNode!.localTranslate(by: SCNVector3Make(deltaX, 0.0, deltaY))

        latestTranslatePos = position

        if (state == .ended) {
            targetNode = nil
        }
    }
}
3
leandrodemarco

Avait le même problème. Utiliser un SCNTransaction a fait l'affaire pour moi.

@objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
    [...]

    SCNTransaction.begin()
    SCNTransaction.animationDuration = 0
    imagePlane.position.x = hitTestResult.localCoordinates.x
    imagePlane.position.y = hitTestResult.localCoordinates.y
    SCNTransaction.commit()
}
0
d4Rk

J'avais un problème similaire. Bien que vous deviez utiliser les conseils de John dans les commentaires et utiliser les états de geste panoramique corrects (début, changement, fin), je pense que le problème pourrait être que vous récupériez le hitResult.node alors que vous devriez récupérer le parent du nœud, ou même le parent du parent, etc ... J'ai eu ce problème et j'ai fini par le résoudre en remontant les niveaux du parent jusqu'à ce que l'objet entier soit sélectionné au lieu d'une partie de celui-ci.

0
Alan S