I observed a very strange behavior where a copied SCNGeometry doesn’t work immediately. I had to wait one run-loop (DispatchQueue.main.async
) in order to make it work. Is it a bug or am I doing something wrong?
Here’s my code:
func helper_cloneGeo(geo: SCNGeometry) -> SCNGeometry {
let copiedGeo = geo.copy() as! SCNGeometry
copiedGeo.materials = geo.materials.map { $0.copy() as! SCNMaterial }
return copiedGeo
}
override init() {
super.init()
let geo = readGeo(fn: "alcohol.usdz", texture: "texture.png").geometry!
// HERE!!!
// SCNGeometry is only clone-able after async!!
// DispatchQueue.main.async {
let copiedGeo = self.helper_cloneGeo(geo: geo)
let newNode = SCNNode(geometry: copiedGeo)
self.rootNode.addChildNode(newNode)
// }
}
The readGeo
is just a helper function that reads a 3d model file, which should be correct, because the original (not cloned) node works.
You can download my sample project here: https://drive.google.com/file/d/1kYyqCAJXnXqpZc6vaaXORe_UVmLH6wHL/view?usp=sharing
In this project, when you run it, it shows the model. Then if you comment out the DispatchQueue.main.async
(like in the code above), the model won’t be shown.
2
Answers
By doing some basic debugging, you can see that
geo.elements
andgeo.sources
are all empty, and this is why nothing got copied. I suspect thatSCNNode.flattenedClone
(which you used inreadGeo
) somehow made a node with a "lazy" geometry that doesn’t get immediately created.If you don’t want to do this asynchronously, you can always just run the run loop yourself.
Not sure why but this works. Likely related to SceneKit internal implementation, as Sweeper suggested.