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

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

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

  • Вставьте ARAnchor, затем создайте node в renderer (_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) → SCNNode?

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

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

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

4b9b3361

Ответ 1

Обновление: Как и в 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, вам нужен способ ссылки на позиции/ориентации в 3D (реальном) пространстве, потому что SpriteKit не является 3D. Вам нужно ARAnchor отслеживать позиции в 3D, чтобы они могли отображаться в 2D.

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

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


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

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

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


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

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

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

Ответ 2

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

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

Смотрите документы, и вы можете увидеть разницу в API:)

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