В чем разница между использованием ARAnchor для вставки узла и прямой вставки узла?

В ARKit я нашел 2 способа вставки узла после hitTest

  1. Вставьте ARAnchor, затем создайте узел в рендерере (_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode?

    let anchor = ARAnchor(transform:hit.worldTransform)
    sceneView.session.add(anchor:anchor)
    
  2. Вставьте узел напрямую

    node.position = SCNVector3(hit.worldTransform.columns.3.x, hit.worldTransform.columns.3.y, hit.worldTransform.columns.3.z)
    sceneView.scene.rootNode.addChildNode(node)
    

Оба смотрят на работу для меня, но почему так или иначе?

2 ответа

Решение

Обновление: Начиная с iOS 11.3 (он же "ARKit 1.5"), есть разница между добавлением ARAnchor в сеанс (а затем связать с ним содержимое SceneKit через ARSCNViewDelegate обратные вызовы) и просто размещение контента в пространстве SceneKit.

Когда вы добавляете привязку к сеансу, вы говорите ARKit, что определенная точка в мировом пространстве имеет отношение к вашему приложению. Затем ARKit может выполнить дополнительную работу, чтобы убедиться, что его мировое координатное пространство точно совпадает с реальным миром, по крайней мере, в непосредственной близости от этой точки.

Таким образом, если вы пытаетесь заставить виртуальный контент выглядеть "привязанным" к какой-либо реальной точке интереса, например, положить объект на стол или стену, вы должны увидеть меньший "дрейф" из-за неточности отслеживания мира, если вы дадите этот объект является якорем, чем если бы вы просто поместили его в пространство SceneKit. И если этот объект перемещается из одной статической позиции в другую, вы захотите удалить исходный якорь и впоследствии добавить его в новую позицию.

Кроме того, в iOS 11.3 вы можете выбрать "перераспределение", процесс, который помогает ARKit возобновить сеанс после того, как он прерывается (по телефону, переключением приложений и т. Д.). Сеанс все еще работает, пока он пытается выяснить, как сопоставить то, где вы были раньше, с тем, где вы сейчас находитесь, что может привести к изменению положения якорей в мировом пространстве после успешного перемещения.

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

См. Раздел "Использование привязок для улучшения качества отслеживания виртуальных объектов" в статье Apple по обработке 3D-взаимодействий и элементам управления в статье / образце кода дополненной реальности.

Остальная часть этого ответа исторически актуальна для iOS 11.0-11.2.5 и объясняет некоторый контекст, поэтому я оставлю это ниже...


Рассмотрим сначала использование ARAnchor без SceneKit.

  • Если вы используете ARSKView вам нужен способ ссылаться на позиции / ориентации в трехмерном (реальном) пространстве, потому что SpriteKit не является трехмерным. Тебе нужно ARAnchor отслеживать позиции в 3D, чтобы они могли отображаться в 2D.

  • Если вы создаете свой собственный движок с Metal (или GL, по какой-то странной причине)... это не API описания 3D-сцены - это API-интерфейс для программирования на GPU - так что у него нет понятия о мировом пространстве. Ты можешь использовать ARAnchor как мост между представлением ARKit о мировом пространстве и всем, что вы строите.

Так что в некоторых случаях вам нужно ARAnchor потому что это единственный разумный способ ссылаться на 3D-позиции. (И, конечно, если вы используете обнаружение самолета, вам нужно ARPlaneAnchor потому что ARKit на самом деле переместит их относительно пространства сцены, поскольку он уточнил свои оценки того, где находятся плоскости.


С ARSCNView SceneKit уже имеет трехмерное мировое координатное пространство, и ARKit выполняет всю работу по приведению этого пространства в соответствие с реальным пространственным отображением ARKit. Итак, учитывая float4x4 Преобразование, которое описывает положение (и ориентацию и т. д.) в мировом пространстве, вы можете:

  • Создать ARAnchor добавьте его в сеанс и ответьте на ARSCNViewDelegate обратный вызов для предоставления содержимого SceneKit для каждого якоря, к которому ARKit добавит и разместит для вас сцену.
  • Создать SCNNode установите его simdTransform и добавить его в качестве ребенка сцены rootNode,

Пока у вас есть бег ARSession Между этими двумя подходами нет никакой разницы - это эквивалентные способы сказать одно и то же. Так что, если вам нравится делать вещи способом SceneKit, в этом нет ничего плохого. (Вы даже можете использовать SCNVector3 а также SCNMatrix4 вместо SIMD-типов, если хотите, но вам придется конвертировать туда-сюда, если вы также получаете SIMD-типы из API-интерфейсов ARKit.)


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

В этом случае ARKit может удалить якоря из сеанса - см. run(_:options:) метод и ARSession.RunOptions, (Да, все они, потому что на данный момент вы не можете больше доверять ни одному из них, чтобы они были действительными.) Если вы поместили контент в сцену с помощью якорей и делегированных обратных вызовов, ARKit уничтожит весь контент. (Вы получаете делегированные обратные вызовы, которые он удаляет.) Если вы поместили контент с помощью SceneKit API, он остается на сцене (но, скорее всего, не в том месте).

Таким образом, то, что использовать, зависит от того, как вы хотите обрабатывать сбои и прерывания сеанса (и вне этого нет никакой реальной разницы).

SCNVector3 - это просто "представление трехкомпонентного вектора". SCNVector3 документы.

При использовании ARAnchor у вас есть доступ к трехкомпонентному вектору, но вы также можете "отслеживать позиции и ориентации реальных или виртуальных объектов относительно камеры" ARAnchor docs. И именно поэтому вы используете сеанс для добавления якоря вместо использования сцены.

Посмотрите документы и вы увидите разницу с точки зрения API:)

Надеюсь, поможет.

Другие вопросы по тегам