Как разместить трехмерный объект (файл .scn) на обнаруженной вертикальной плоскости, которая должна быть параллельна плоскости в ARKIt? - PullRequest
0 голосов
/ 24 мая 2019

Я собираюсь обнаружить горизонтальную и вертикальную плоскость в ARKit.После определения, является ли это горизонтальной или вертикальной поверхностью, соответственно добавьте плоскость серого цвета на обнаруженную поверхность. При нажатии на обнаруженную плоскость я собираюсь добавить 3D-объект из файла .scn.

Мой код работает нормально для размещения3D-объект (файл .scn) в горизонтальной плоскости, но не работает правильно с вертикальной плоскостью.

3D-объект (файл .scn) для вертикальной плоскости, такой как фоторамка, направлен вправо в редакторе SceneKit.Поэтому я изменил его EularAngleY ​​на -0, и теперь он обращен к фронту в редакторе SceneKit.Когда я нажимаю на обнаруженную вертикальную плоскость, которая обращена вперед, то и фоторамка направлена ​​вправо, и если я перемещаю устройство вправо и размещаю фоторамку, это правильно.

Я хочу разместить 3D-объект .scn-файл, который должен быть параллелен плоскости (если вертикальная плоскость направлена ​​вперед, то она должна быть лицевой стороной даже в .scn-файле и в любом направлении).не параллельно обнаруженной плоскости.

Нужно ли мне менять угол поворота также относительно угла наклона обнаруженной плоскости или нужно вносить какие-либо изменения в файл .scn в редакторе SceneKit?Как мне этого добиться?

Пожалуйста, проверьте нижеприведенный код на попадание в обнаруженную вертикальную плоскость.Что-то не так?

@objc func addObjectToSceneView1(withGestureRecognizer recognizer: UIGestureRecognizer){
    let tapLocation = recognizer.location(in: sceneView)
    let hitTestResults = sceneView.hitTest(tapLocation, types: .existingPlaneUsingExtent)

    guard let hitTestResult = hitTestResults.first, let anchor = hitTestResult.anchor as? ARPlaneAnchor else { return }


    let translation = hitTestResult.worldTransform.columns.3

    let x = translation.x
    let y = translation.y
    let z = translation.z

    guard let shipScene = SCNScene(named: "art.scnassets/frame/frame.scn"),
        let shipNode = shipScene.rootNode.childNode(withName: "frame", recursively: true)
        else { return }

    shipNode.position = SCNVector3(x,y,z)

    sceneView.scene.rootNode.addChildNode(shipNode)
}

.scn файл, как показано ниже.Этот файл .scn правильный?Или х должен быть с глубиной кадра?Каждый раз, когда я нажимаю на самолет, он показывает только это изображение.

frame.scn file

1 Ответ

2 голосов
/ 27 мая 2019

Как я уже упоминал в ответе здесь , лучше добавить ARAnchor к ARSession, чем напрямую добавлять SCNNode в граф сцены после выполнения теста на попадание.В настоящее время размещенный вами код не учитывает вращение обнаруженной плоскости.Чтобы код работал, вам нужно будет определить нормаль обнаруженной плоскости, взять точечное произведение и скрестить произведение с желаемой ориентацией модели, вычислить вращение, а затем применить вращение.Тем не менее, ARSession сделает все это за вас.При использовании ARAnchor(transform: hitTestResult.worldTransform) вращение кодируется в якорь.Таким образом, вам нужно иметь дело только с преобразованиями с собственным локальным координатным пространством модели.

Например:

@objc func addObjectToSceneView1(withGestureRecognizer recognizer: UIGestureRecognizer){
    let tapLocation = recognizer.location(in: sceneView)
    let hitTestResults = sceneView.hitTest(tapLocation, types: .existingPlaneUsingExtent)

    guard let hitTestResult = hitTestResults.first, let anchor = hitTestResult.anchor as? ARPlaneAnchor else { return }
    // create anchor and add to session and wait for callback
    let anchor = ARAnchor(transform: hitTestResult.worldTransform)
    sceneView.session.add(anchor: anchor)
}

Затем в вашем сеансе перезвоните делегату:

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
    if anchor is ARPlaneAnchor {
        // node for plane anchor
        let anchorNode = SCNNode()
        return anchorNode
    } else {
        // must be node for most recent hit test
        guard let frameScene = SCNScene(named: "art.scnassets/frame/frame.scn"),
              let frameNode = frameScene.rootNode.childNode(withName: "frame", recursively: true) else { return nil }
        return frameNode
    }
}

В вашем файле scn вы захотите найти модельв начале координат лежит без каких-либо преобразований.Это означает, что вам, вероятно, понадобится вложить узлы и расположить базовую модель относительно родительского пустого узла.

Xcode SCN editor screenshot

Здесь «рамка» - это внешняяузел без преобразования, возвращаемый из nodeForAnchor, и «изображение» поворачивается, чтобы быть плоским и масштабироваться до размера содержимого.

Окончательный результат:

Screencast of final product

...