Как перемещать и вращать SCNode с помощью ARKit и Gesture Recognizer?

Я работаю над приложением для iOS на основе AR с использованием ARKit (SceneKit). Я использовал пример кода Apple https://developer.apple.com/documentation/arkit/handling_3dality_interaction / a> в качестве основы для этого. Используя это, я могу перемещать или вращать весь виртуальный объект.

Но я хочу выбрать и переместить / повернуть дочерний узел в виртуальном объекте с помощью пальца пользователя, аналогично тому, как мы перемещаем / вращаем весь виртуальный объект.

Я попробовал две ссылки ниже, но они перемещают только дочерний узел по определенной оси, но не перемещаются свободно в любом месте, когда пользователь перемещает палец.

ARKit - перетащите узел вдоль определенной оси (не на плоскости)

Перетаскивание SCNNode в ARKit с помощью SceneKit

Также я попытался заменить виртуальный объект, который является SCNReferenceNode, на SCNode, чтобы любые функции, существующие для существующего виртуального объекта, также применялись к дочернему узлу, он не работал.

Может ли кто-нибудь помочь мне, как свободно перемещать / вращать не только виртуальный объект, но и дочерний узел виртуального объекта?

Пожалуйста, найдите код, который я сейчас использую, ниже,

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

person yaali    schedule 22.05.2018    source источник


Ответы (1)


Чтобы переместить объект:

Выполните HitTest, чтобы проверить, где вы коснулись, определить, какой плоскости вы коснулись, и определите позицию. Переместите свой SCNNode в эту позицию, изменив значение node.position с помощью SCNVector3.

Код:

@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)
    }
}
person SWAT    schedule 23.05.2018
comment
Это не вызывает плавного движения моего узла. Как только я касаюсь узла, он просто куда-то ушел. Это не следует за движением моих пальцев. - person yaali; 24.05.2018
comment
Объясни свою проблему еще немного. это поможет мне найти причину проблемы. Я предположил, что в вашей конфигурации включено обнаружение самолетов. - person SWAT; 24.05.2018
comment
Да, в моей конфигурации включено обнаружение горизонтальной плоскости. Что я пытаюсь сделать, так это то, что у меня есть целый виртуальный объект, помещенный в поверхность. В нем много дочерних узлов. Я хочу переместить каждый дочерний узел пальцем и тоже должен иметь возможность его вращать. Теперь, когда я пробую этот код, когда я касаюсь дочернего узла, он исчезает со своего места, и я вижу, что он плавает где-то дальше по экрану. - person yaali; 24.05.2018
comment
Код, который я вам дал, не предназначен для отделения дочернего узла и перемещения его отдельно от parentNode, он перемещает узлы вместе. Я добавлю код для отделения дочернего узла, но, пожалуйста, поделитесь своим кодом. Это бы очень помогло. - person SWAT; 24.05.2018
comment
Я отредактировал свой вопрос. Найдите код, который я пытаюсь сделать. - person yaali; 24.05.2018