Larisa Larisa - 1 month ago 13
Swift Question

Stop sharing node's geometry with its clone programmatically

When you create a copy of an object, geometry and its properties (materials...) are shared with that object.
In Xcode Scene Editor you can easily disable that by setting

Geometry Sharing
(under
Attributes Inspector
) to
Unshare
.

I want to achieve the same thing programmatically, but can't find any similar properties in
SceneKit
documentation.
I have found a similar post where someone proposed copying the object, its geometry and its material. I tried doing so but had no success.

This is the relevant part of my code:

let randomColors: [UIColor] = [UIColor.blue, UIColor.red, UIColor.yellow, UIColor.gray]
let obstacleScene = SCNScene(named: "art.scnassets/Scenes/obstacleNormal.scn")
let obstacle = obstacleScene?.rootNode.childNode(withName: "obstacle", recursively: true)

for i in 1...15 {
let randomPosition = SCNVector3(x: Float(i) * 3.5, y: 0.15, z: sign * Float(arc4random_uniform(UInt32(Int(playgroundZ/2 - 2.0))) + 1))
let randomColor = randomColors[Int(arc4random_uniform(UInt32(3)))]

let obstacleCopy = obstacle?.clone()
obstacleCopy?.position = randomPosition
obstacleCopy?.geometry?.materials.first?.diffuse.contents = randomColor
obstacleCopy?.eulerAngles = SCNVector3(x: 10.0 * Float(i), y: Float(30 - i), z: 5.0 * Float(i) * sign) //malo na random

obstacleCopy?.physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
obstacleCopy?.physicsBody?.isAffectedByGravity = false
obstacleCopy?.physicsBody?.categoryBitMask = PhysicsCategory.obstacle
obstacleCopy?.physicsBody?.collisionBitMask = PhysicsCategory.none
obstacleCopy?.physicsBody?.contactTestBitMask = PhysicsCategory.car1 | PhysicsCategory.car2 | PhysicsCategory.barrier

obstacleArray.append(obstacleCopy!)
raceScene!.rootNode.addChildNode(obstacleCopy!)
}


I want to set different attributes on those objects but can't, because their geometry is shared.
I tried doing this with copying the object and cloning it, but I couldn't see any differences with copying or cloning it.

Is there a property which you can use to achieve geometry unsharing, similar to the option in the Scene Editor, OR should the method of also copying object's geometry and its materials work?

Answer

According to the clone() API reference, you can copy the geometry after cloning, this will create a new unshared geometry for your node.

let newNode = node.clone()
newNode.geometry = node.geometry?.copy() as? SCNGeometry

The material attached to the copied geometry is still the same one being used on the original, so any changes will still affect both. Either create a new material, or make a copy.

if let newMaterial = newNode.geometry?.materials.first.copy() as? SCNMaterial {
    //make changes to material
    newNode.geometry?.materials = [newMaterial]
}