Не удается передать контейнер MDLMesh с 3D-моделью как SCNGeometry

Я создаю приложение AR (Xcode 10.1, Swift 4.2.1).

Я хочу загрузить USDZ 3D-объект в пустую сцену SceneKit, а затем обработать его как MDL сетку.

Вот мой код:

import ARKit
import SceneKit.ModelIO

let scene = SCNScene(named: "art.scnassets/emptyScene.scn")!

if let filePath = Bundle.main.path(forResource: "Helicopter", 
                                        ofType: "usdz", 
                                   inDirectory: "art.scnassets") {

    let refURL = URL(fileURLWithPath: filePath)
    let refNode = SCNReferenceNode(url: refURL)
    refNode?.load()
    scene.rootNode.addChildNode(refNode!)
}

let helicopterGeo = refNode!.geometry

let mdlMesh = MDLMesh(scnGeometry: helicopterGeo!)      // ERROR APPEARS HERE
try! mdlMesh.makeVerticesUniqueAndReturnError()
let flattenedGeometry = SCNGeometry(mdlMesh: mdlMesh)
let flattenedNode = SCNNode(geometry: flattenedGeometry)
scene.rootNode.addChildNode(flattenedNode)


Но компилятор выдает мне ошибку:

"Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value"

Вопрос в следующем: какой подход следует использовать для назначения геометрии "Helicopter.usdz" константе helicopterGeo?

Помогите найти обходной путь, пожалуйста!

Вы можете скачать USDZ файл для тестирования ЗДЕСЬ.


person Andy Fedoroff    schedule 14.10.2018    source источник
comment
Вы пробовали let helicopterGeo = refNode!.geometry?   -  person Steve O'Connor    schedule 17.10.2018


Ответы (3)


Это должно работать:

var scene: SCNScene!
if let filePath = Bundle.main.path(forResource: "Helicopter", 
                                    ofType: "usdz", 
                               inDirectory: "art.scnassets") {

    let refURL = URL(fileURLWithPath: filePath)
    let mdlAsset = MDLAsset(url: refURL)
    scene = SCNScene(mdlAsset: mdlAsset)

}

SCNReferenceNode работает только с файлами .scn. Затем вы можете получить геометрию из дочернего узла rootNode из scene.

let helicopterNode = scene.rootNode.childNode(withName: "helicopter", recursively: true)
let geometry = helicopterNode.geometry!

Редактировать

Используя один из файлов из галереи AR Quick Look, мне удалось заставить этот код работать . Основная проблема, с которой я столкнулся, была связана с именем конкретного дочернего узла, один из них назывался «RetroTV», но к нему не была прикреплена какая-либо геометрия, он был просто родителем для «RetroTVBody» и «RetroTVScreen». Единственная проблема в том, что он не загружает текстуры для геометрии.

var scene: SCNScene!
if let filePath = Bundle.main.path(forResource: "retrotv",
                                   ofType: "usdz",
                                   inDirectory: "art.scnassets") {

    let refURL = URL(fileURLWithPath: filePath)
    let mdlAsset = MDLAsset(url: refURL)
    scene = SCNScene(mdlAsset: mdlAsset)

    let tvNode = scene.rootNode.childNode(withName: "RetroTVBody", recursively: true)
    let geometry = tvNode!.geometry!

} else {

    print("invalid path!")

}

Приведенный выше код также работает с объявлениями tvNode и geometry вне оператора if let.

person Brandon    schedule 15.11.2018
comment
@argeo Возможно, helicopterNode равно нулю, знаете ли вы фактическое название геометрии вертолета в файле udsz? - person Brandon; 15.11.2018
comment
@argeo У меня нет файла usdz для проверки, но это ошибка времени выполнения или времени компиляции, попробуйте принудительно развернуть helicopterNode и посмотреть, изменится ли что-нибудь - person Brandon; 15.11.2018
comment
@argeo Вызывается ли код внутри вашего if let, я проверил его, и это проблема, с которой я столкнулся. - person Brandon; 15.11.2018
comment
@ARGeo Кажется, проблема в аргументе withName аргумента scene.rootNode.childNode - person Brandon; 16.11.2018
comment
@ARGeo попробуйте распечатать scene.rootNode.childNodes, чтобы убедиться, что он действительно работает. - person Brandon; 16.11.2018
comment
Спасибо за ответ, Брэндон! Баунти будет присуждена вам автоматически. - person Andy Fedoroff; 16.11.2018

У меня нет точного ответа, но в вашей ситуации я бы изучил иерархию refNode.

Поместите точку останова после загрузки и используйте отладчик, чтобы увидеть, есть ли у него дочерние элементы. У этих детей есть геометрия? У них есть дети с геометрией?

При создании 3D-ресурсов иногда несколько разделов группируются на родительском узле, и во многих случаях этот родительский узел пуст.

person EmilioPelaez    schedule 15.11.2018
comment
Там вообще нет никакой геометрии, кроме этой. И моя сцена пуста. Точка останова ничего полезного не говорит... - person Andy Fedoroff; 15.11.2018
comment
Использовали ли вы консоль, чтобы изучить дочерние элементы и посмотреть, есть ли у них какая-либо геометрия? - person EmilioPelaez; 16.11.2018
comment
Я также протестировал простую сферу, сделанную в Maya. Иерархии вообще не было (никаких групп, только узел shape шара Maya, соединенный с его узлом transform). Результат тот же: ошибка. - person Andy Fedoroff; 16.11.2018
comment
Спасибо за ответ, Эмилио! - person Andy Fedoroff; 16.11.2018

Была ли это ошибка в бинарном файле Maya, или ошибка usdz конвертации - я точно не знаю. Xcode не увидел правильное имя объекта в простейшей иерархии Scene graph: вместо pHelicopter1 он просто показал Helicopter. Мой 3D-объект был создан из pCube1 с помощью полигонального инструмента Extrude.

Вот окончательный код, и он отлично работает:

import ARKit
import SceneKit.ModelIO

//..........................................................

var scene = SCNScene(named: "art.scnassets/EmptyScene.scn")!

if let filePath = Bundle.main.path(forResource: "Helicopter",
                                        ofType: "usdz",
                                   inDirectory: "art.scnassets") {

    let refURL = URL(fileURLWithPath: filePath)
    let mdlAsset = MDLAsset(url: refURL)
    scene = SCNScene(mdlAsset: mdlAsset)
    let helicopterNode = scene.rootNode.childNode(withName: "pHelicopter1", 
                                               recursively: true)

    let geometry = helicopterNode!.geometry!
    let mdlMesh = MDLMesh(scnGeometry: geometry)
    try! mdlMesh.makeVerticesUniqueAndReturnError()
    let flattenedGeometry = SCNGeometry(mdlMesh: mdlMesh)
    let flattenedNode = SCNNode(geometry: flattenedGeometry)
    scene.rootNode.addChildNode(flattenedNode)

} else {
    print("Invalid path!")
}

введите здесь описание изображения

person Andy Fedoroff    schedule 16.11.2018