Подтвердить что ты не робот

Как сохранить ARKit SCNNode на месте

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

Код:

 func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

    if let planeAnchor = anchor as? ARPlaneAnchor {

    if planeDetected == false { // Bool only allows 1 plane to be added
            planeDetected = true
        self.addPlane(node: node, anchor: planeAnchor)
    }

    }
}

Это добавляет SCNNode

    func addPlane(node: SCNNode, anchor: ARPlaneAnchor) {

    // We add the anchor plane here

    let showDebugVisuals = Bool()
    let plane = Plane(anchor, showDebugVisuals)
    planes[anchor] = plane
    node.addChildNode(plane)



    // We add our custom SCNNode here 

    let scene = SCNScene(named: "art.scnassets/PlayerModel.scn")!
    let Body = scene.rootNode.childNode(withName: "Body", recursively: true)!

    Body.position = SCNVector3.positionFromTransform(anchor.transform)
    Body.movabilityHint = .movable
    wrapperNode.position = SCNVector3.positionFromTransform(anchor.transform)

    wrapperNode.addChildNode(Body)

    scnView.scene.rootNode.addChildNode(wrapperNode)

Я пытался добавить узел плоскости/привязки и поместить в него узел "Тело", но он все еще движется. Я подумал, может быть, это как-то связано с функцией обновления.

 func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
 }

Или, скорее всего, установка позиции

wrapperNode.position = SCNVector3.positionFromTransform(anchor.transform)

Iv'e просмотрел каждый файл/видео источника/проекта в Интернете, и ни у кого нет простого решения этой простой проблемы.

4b9b3361

Ответ 1

Есть два вида "передвижения", которые могут происходить здесь.


Одним из них является то, что ARKit постоянно уточняет свою оценку того, как положение устройства в реальном мире отображается в абстрактном координатном пространстве, в которое вы помещаете виртуальный контент. Например, предположим, что вы помещаете виртуальный объект в (0, 0, -0.5), а затем переместите ваше устройство влево ровно на 10 см. Виртуальный объект будет закреплен в физическом пространстве, только если ARKit точно отслеживает движение. Но визуально-инерционная одометрия не является точной наукой, поэтому вполне возможно, что ARKit считает, что вы переместились влево на 10,5 см - в этом случае ваш виртуальный объект будет "скользить" вправо на 5 мм, даже если его положение в координатном пространстве ARKit/SceneKit остается постоянным.

Вы не можете ничего с этим поделать, кроме надежды на то, что Apple создаст устройства с лучшими сенсорами, лучшими камерами или улучшенными процессорами/графическими процессорами и улучшит науку о мировом слежении. (С течением времени это, вероятно, безопасная ставка, хотя, вероятно, это не поможет в вашем текущем проекте.)


Так как вы также имеете дело с обнаружением самолета, есть еще одна морщина. ARKit постоянно совершенствует свои оценки того, где находится обнаруженная плоскость. Таким образом, хотя реальная позиция плоскости не меняется, ее положение в координатном пространстве ARKit/SceneKit равно.

Этот тип движения, как правило, полезен: если вы хотите, чтобы ваш виртуальный объект казался привязанным к поверхности реального мира, вы хотите быть уверенным в том, где находится эта поверхность. Вы увидите некоторое движение, когда обнаружение плоскости станет более уверенным в положении поверхности, но через короткое время вы увидите меньшее "скольжение" при перемещении камеры вокруг привязанных к плану виртуальных объектов, чем тех, которые просто плавают в мире пространство.


Однако в вашем коде вы не пользуетесь обнаружением плоскостей, чтобы заставить ваш пользовательский контент (из "PlayerModel.scn") придерживаться привязки плоскости:

wrapperNode.position = SCNVector3.positionFromTransform(anchor.transform)
wrapperNode.addChildNode(Body)
scnView.scene.rootNode.addChildNode(wrapperNode)

Этот код использует начальную позицию привязки плоскости для позиционирования wrapperNode в мировом пространстве (потому что вы делаете его дочерним по отношению к корневому узлу). Если вместо этого вы сделаете wrapperNode дочерним по отношению к узлу привязки плоскости (тот, который вы получили в renderer(_:didAdd:for:)), он останется прикрепленным к плоскости, так как ARKit уточняет свою оценку положения плоскости. Сначала вы получите немного больше движения, но когда "плоскость" обнаружится, ваш виртуальный объект будет "скользить" меньше.

(Когда вы делаете узел дочерним по отношению к плоскости, вам не нужно устанавливать его положение - нулевое положение означает, что оно находится там, где находится плоскость. В любом случае, вам нужно установить его положение только относительно плоскости, т.е. как далеко выше/ниже/вдоль него.)

Ответ 2

Чтобы сохранить SCNNode на месте, вы можете отключить определение плоскости sceneView, как только получите желаемый результат.

let configuration = ARWorldTrackingConfiguration(); configuration.planeDetection = [] self.sceneView.session.run(configuration)

Причина в том, что ARKit постоянно переоценивает положение обнаруженной плоскости, в результате чего ваш SCNNode перемещается.