How do you load a .dae file into an SCNNode in iOS SceneKit?
Asked Answered
S

7

22

I am having trouble understanding how geometry from .dae files should be loaded into an iOS SceneKit scene graph.

I know that you can load .dae files directly into an SCNScene:

// create a new scene
let scene = SCNScene("test.scnassets/test.dae")

I also know that you can create an empty SCNScene and add built-in 3D objects into it as child nodes:

let scene = SCNScene()
var sphereNode = SCNNode()
sphereNode.geometry = SCNSphere(radius: 1.0)
scene.rootNode.addChildNode(sphereNode)

In the second case, can you load a .dae file into SCNNode instead of using built in objects? Or is it expected that all .dae files need to be loaded into the SCNScene first?

If the latter is true, how then do you place the SCNNode objects into the right place in the scene graph hierarchy under SCNScene?

EDIT #1:

This is working for me now, which is modified version of what @FlippinFun suggested.

let url = NSBundle.mainBundle().URLForResource("test.scnassets/test", withExtension: "dae")
let source = SCNSceneSource(URL: url, options: nil)
let block = source.entryWithIdentifier("ID10", withClass: SCNGeometry.self) as SCNGeometry
scene.rootNode.addChildNode(SCNNode(geometry: block))

But perhaps there's a better way? The above involves manually loading each identifier from the .dae tree. In my file, there's a node "SketchUp" with child identifiers "ID2" and "ID10". This method will not let you load the root "SketchUp". (I get a runtime error.)

Sylviasylviculture answered 18/8, 2014 at 4:20 Comment(5)
I already post this. Here is a link. #25032274Martyr
Thanks. So your suggestion is to use SCNSceneSource. Unfortunately that's crashing for me at the moment.Sylviasylviculture
There seems to be a bug in your code that retrives the geometry. The class should be SCNGeometry rather than SCNNode. Eg: let block = source.entryWithIdentifier("ID10", withClass: SCNGeometry.self) as SCNGeometry. With this fix, it's working for me.Sylviasylviculture
Yes there is a bug. I will make an edit. Thanks!Martyr
Re this 10 yr old question. The full answer these days (2023) is https://mcmap.net/q/245407/-how-to-get-a-ordinary-mixamo-character-animation-working-in-scenekitBucephalus
S
11

The usual pattern is to load your scene and retrieve the node you are interested in with its name using

[scene.rootNode childNodeWithName:aName recursively:YES];

Then you can reparent this node to your main scene.

Scad answered 18/8, 2014 at 9:35 Comment(6)
But in that case, the node is already a direct child of the root node, correct? So if I need to it to be under some other node in the scene graph, I will need to reposition it, with this approach. That's why I was asking about loading the SCNNode geometry independent of the SCNScene.Sylviasylviculture
In any case, this is a useful approach. Thanks.Sylviasylviculture
you would typically create a new scene with your "other" dae file, retrieve the node you are interested in, and reparent it in your main sceneParasiticide
How do you typically reparent a node?Sylviasylviculture
you can take a look at the -[SCNNode asc_addChildNodeNamed:fromSceneNamed:withScale:] extension method in the WWDC 2014 sample code. Build the scene, get the node with -childNodeWithName:recursively: and then simply -addChildNode: to a node in your main scene.Parasiticide
Why didn't add scene1.rootNode to scene2 ? My .scn file ONLY have animations on rootNode, how to deal with this.Mulry
I
11

I had a similar problem where I had one .dae file and I wanted to load multiple nodes from that file into a node. This worked for me:

var node = SCNNode()
let scene = SCNScene(named: "helloScene.dae")
var nodeArray = scene.rootNode.childNodes

for childNode in nodeArray {
  node.addChildNode(childNode as SCNNode)
}

First, I set a node that will hold it all together so it looks like it does in the original file. Next we import the .dae file we want and copy all the nodes inside of it. Lastly, for each node in the array I added it to the node.

Indecorous answered 15/11, 2014 at 17:53 Comment(1)
I replaced var nodeArray = scene.rootNode.childNodes with var nodeArray = scene!.rootNode.childNodesPigeon
C
7

Thanks for your help!

Here is a simple collada2Node class.

//collada2SCNNode
class func collada2SCNNode(filepath:String) -> SCNNode {
    var node = SCNNode()
    let scene = SCNScene(named: filepath)
    var nodeArray = scene!.rootNode.childNodes

    for childNode in nodeArray {
        node.addChildNode(childNode as SCNNode)
    }
    return node
}
Collettecolletti answered 4/1, 2015 at 9:46 Comment(0)
U
4
func nodeWithFile(path: String) -> SCNNode {

    if let scene = SCNScene(named: path) {

        let node = scene.rootNode.childNodes[0] as SCNNode
        return node

    } else {
        println("Invalid path supplied")
        return SCNNode()
    }

}
Unconcerned answered 9/4, 2015 at 13:50 Comment(0)
M
3

The following answers didn't work for me.

Here is what worked for me in Xcode 7.0 beta 5 , iOS 9.0 beta / Swift 2.0:

3D model type: Collada 3D model name: "model.dae"

  1. Load the scene:

    let lampScene = SCNScene(named: "art.scnassets/model.dae")
    
  2. Access the child SCNode which is in the SCNScene:

    let lampRootNode = lampScene?.rootNode.childNodes[0]
    
  3. Add the lamp node from the loaded scene into the current loaded and viewed scene:

    self.scene.rootNode.addChildNode(lampRootNode!)
    

NOTE: The self.scene exists due to:

private var scene:SCNScene!

Prior of adding the object to the scene I have made some scene setup according to the scene kit example. If you need the code mention it in the comments.

Hope it helps.

Maitilde answered 27/8, 2015 at 13:13 Comment(1)
Why didn't you use a SCNReferenceNode? Is there an advantage to this approach?Venom
B
1

The only practical way we have found to so this: 2023.

(1) Very simply open the YourFileName.dae file, using a normal real text editor such as VSCode.

enter image description here

Notice that the file contains things like materials, effects, etc.

Simply scroll to the library_geometries and you'll immediately see the id,

In this case "geometry316".

(Note that almost always the library_geometries is simply the final long line of the file, easy to find.)

Very simply, the id (example, "geometry316") is NOT SHOWN IN XCODE, it's just an Xcode bug they will likely fix soon.

(2) Then to get and show the node it's just:

var kingDragon: SCNNode!
...


let p = Bundle.main.url(forResource: "Badass Dragon", withExtension: "dae")!
let source = SCNSceneSource(url: p, options: nil)!
let g = source.entryWithIdentifier("geometry316",
              withClass: SCNGeometry.self)! as SCNGeometry
kingDragon = SCNNode(geometry: g)
castleWall.addChildNode(kingDragon)

That's it.

Note!

If you further wish to load and use character animations, the total solution is outlined here: https://mcmap.net/q/245407/-how-to-get-a-ordinary-mixamo-character-animation-working-in-scenekit

Bucephalus answered 11/1, 2023 at 19:31 Comment(0)
M
0
guard let shipScene = SCNScene(named: "ship.dae") else { return }
let shipNode = SCNNode()
let shipSceneChildNodes = shipScene.rootNode.childNodes
for childNode in shipSceneChildNodes {
    shipNode.addChildNode(childNode)
}
Matheny answered 27/10, 2018 at 13:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.