Swift: ARKit Сохранить ARPlaneAnchor для следующего сеанса

ARKit совсем новичок, и я совсем новичок в Swift... Так что у меня проблемы...

Я хочу сохранить ARPlaneAnchor, обнаруженные во время сеанса, и перезагрузить их при перезапуске приложения. Мой телефон всегда будет в одном и том же месте, и я хочу просканировать комнату один раз. И вспоминая Anchor, который я находил в комнате каждый раз, когда запускаю приложение.

Я попробовал несколько решений:

Решение 1. Сохраните ARPlaneAnchor, используя: NSKeyedArchiver.archiveRootObject(plane, toFile: filePath)

Я получил эту ошибку:

Завершение работы приложения из-за необработанного исключения «NSInvalidArgumentException», причина: «-[ARPlaneAnchor encodeWithCoder:]: в экземпляр отправлен нераспознанный селектор

Я думаю, что, возможно, я не могу сохранить такие данные локально

Решение 2. Сохраните данные ARPlaneAnchor, а затем создайте их экземпляры при запуске приложения. данные в основном плавающие. Я мог легко создать ARAnchor, я мог преобразовать их в ARPlaneAnchor, но я не мог изменить параметры «центр» и «расширить» ARPlaneAnchor, потому что у них есть только геттер, а не сеттер. Поэтому я не могу создать хорошие якоря.

Я открыт для любого решения. Я думаю, что мне нужно сохранить объект ARAnchor, но пока я не мог найти способ сделать это без сбоя! Так что, если кто-то может мне помочь, я был бы очень благодарен.


person mcarlier    schedule 25.07.2017    source источник
comment
Причина, по которой вы получили ошибку, заключается в том, что ARPlaneAnchor не соответствует NSCoding   -  person Paolo    schedule 25.07.2017
comment
Спасибо за ответ. Есть ли способ привести его в соответствие с NSCoding? или мне нужно использовать другой способ хранения такого рода данных?   -  person mcarlier    schedule 25.07.2017


Ответы (1)


Во-первых... если ваше приложение ограничено ситуацией, когда устройство установлено постоянно, и пользователь никогда не может перемещать или поворачивать его, использование ARKit для отображения оверлейного контента на канале камеры - это своего рода "убийство комаров из пушки". ситуации. С тем же успехом вы могли бы во время разработки решить, какая проекция камеры нужна вашему 3D-движку, использовать «глупую» подачу камеры с вашим 3D-движком, работающим поверх, и не нуждаться в iOS 11 или устройстве с поддержкой ARKit.

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


Что касается вашей более конкретной проблемы...

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

Возможно, вы запутались из-за типичного варианта использования для обнаружения плоскости (и отображения на основе SceneKit):

  1. Включите обнаружение самолетов
  2. Ответьте на renderer(_:didAdd:for:), чтобы получить ARPlaneAnchor объектов
  3. В этом методе возвращайте виртуальный контент для связи с якорем плоскости.
  4. Позвольте ARSCNView автоматически расположить это содержимое так, чтобы оно соответствовало положению плоскости.

Однако, если положение вашего самолета статично по отношению к камере, вам все это не нужно.

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

Вместо этого ваши шаги могут выглядеть примерно так:

  1. Знать, где находится самолет (положение в мировом пространстве).
  2. Установите положение вашего виртуального контента в положение плоскости.
  3. Добавьте содержимое непосредственно в сцену.

Другими словами, ваше «Решение 2» — это шаг в правильном направлении, но недостаточно далеко. Вы хотите заархивировать не сам экземпляр ARPlaneAnchor, а содержащуюся в нем информацию — и тогда при разархивировании вам не нужно заново создавать экземпляр ARPlaneAnchor, вам просто нужно использовать эту информацию.

Итак, если это то, что вы делаете для размещения контента с «живым» обнаружением плоскости:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    guard let planeAnchor = anchor as? ARPlaneAnchor else { return }
    let extent = planeAnchor.extent
    let center = planeAnchor.center
    // planeAnchor.transform not used, because ARSCNView automatically applies it
    // to the container node, and we make a child of the container node

    let plane = SCNPlane(width: CGFloat(extent.x), height: CGFloat(extent.z))
    let planeNode = SCNNode(geometry: plane)
    planeNode.eulerAngles.x = .pi / 2
    planeNode.simdPosition = center
    node.addChildNode(planeNode)
}

Затем вы можете сделать что-то подобное для размещения статического контента:

struct PlaneInfo { // something to save and restore ARPlaneAnchor data
    let transform: float4x4
    let center: float3
    let extent: float3
}
func makePlane(from planeInfo: PlaneInfo) { // call this when you place content
    let extent = planeInfo.extent
    let center = float4(planeInfo.center, 1) * planeInfo.transform
    // we're positioning content in world space, so center is now
    // an offset relative to transform

    let plane = SCNPlane(width: CGFloat(extent.x), height: CGFloat(extent.z))
    let planeNode = SCNNode(geometry: plane)
    planeNode.eulerAngles.x = .pi / 2
    planeNode.simdPosition = center.xyz
    view.scene.rootNode.addChildNode(planeNode)
}

// convenience vector-width conversions used above
extension float4 {
    init(_ xyz: float3, _ w: Float) {
        self.init(xyz.x, xyz.y, xyz.z, 1)
    }
    var xyz: float3 {
        return float3(self.x, self.y, self.z)
    }
}
person rickster    schedule 25.07.2017
comment
СПАСИБО! Большое спасибо, что нашли время ответить мне, вы мне очень помогли! Я так много думал об ARKit, что не думал, что у меня уже есть вся информация для выполнения работы. Я понимаю, как убивать комаров из пушки, но я хочу, чтобы мой проект был адаптирован к любому пространству. Например, я сканирую пространство один раз с помощью ARKit, затем ставлю свой iPad в статичное положение и могу отображать элементы в пространстве. И тогда кто-то может ходить в пространстве и идти впереди или позади моего 3D-объекта. И с тем же приложением я могу делать то же самое в любом месте. Еще раз спасибо! - person mcarlier; 26.07.2017