Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't feed a MDLMesh container with 3D model as SCNGeometry

I'm creating AR app (Xcode 10.1, Swift 4.2.1).

I'd like to load USDZ 3D object into an empty SceneKit's scene and then process it as MDL mesh.

Here's my code:

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)


But compiler gives me an error:

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

The question is: what approach should I use to assign a "Helicopter.usdz" geometry to a helicopterGeo constant?

Help me find a workaround, please!

You can download USDZ file for testing HERE.

like image 771
Andy Jazz Avatar asked Oct 14 '18 21:10

Andy Jazz


2 Answers

This should work:

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 only works for .scn files. You can then get the geometry from a child node of the rootNode of the scene.

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

Edit

Using one of the files from the AR Quick Look Gallery I managed to get this code to work. The main problem that I had was with the name of the specific child node, there was one called "RetroTV" but it did not have any geometry attached to it, it was just the parent for both "RetroTVBody" and "RetroTVScreen." The only problem is that it isn't loading the textures for the geometry.

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!")

}

The above code also works with the tvNode and geometry declarations outside of the if let statement.

like image 117
Brandon Avatar answered Oct 30 '22 02:10

Brandon


I don't have an exact answer, but what I would do in your situation would be to examine the hierarchy of refNode.

Place a breakpoint after it's loaded and use the debugger to see if it's got any children. Do those children have any geometries? Do they have any children with geometry?

When creating 3D assets, sometimes multiple sections will be grouped on a parent node, and in many cases that parent node is empty.

like image 45
EmilioPelaez Avatar answered Oct 30 '22 03:10

EmilioPelaez