В чем разница между использованием ARAnchor для вставки узла и прямой вставки узла?
В ARKit я нашел 2 способа вставки узла после hitTest
Вставьте ARAnchor, затем создайте узел в рендерере (_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode?
let anchor = ARAnchor(transform:hit.worldTransform) sceneView.session.add(anchor:anchor)
Вставьте узел напрямую
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:)
Надеюсь, поможет.