skip to Main Content

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.

enter image description here

2

Answers


  1. By doing some basic debugging, you can see that geo.elements and geo.sources are all empty, and this is why nothing got copied. I suspect that SCNNode.flattenedClone (which you used in readGeo) 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.

    let geo = readGeo(fn: "alcohol.usdz", texture: "texture.png").geometry!
    
    RunLoop.main.run(until: .now) // run the run loop for just one iteration
    
    let copiedGeo = self.helper_cloneGeo(geo: geo)
    let newNode = SCNNode(geometry: copiedGeo)
    
    Login or Signup to reply.
  2. Not sure why but this works. Likely related to SceneKit internal implementation, as Sweeper suggested.

    func helper_cloneGeo(geo: SCNGeometry) -> SCNGeometry {
      return SCNNode(geometry: geo).clone().geometry!
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search