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?
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]
}
You could deep clone a SCNNode
, which creates an unshared geometry and unshared materials with the original.
fileprivate func deepCopyNode(node: SCNNode) -> SCNNode {
let clone = node.clone()
clone.geometry = node.geometry?.copy() as? SCNGeometry
if let g = node.geometry {
clone.geometry?.materials = g.materials.map{ $0.copy() as! SCNMaterial }
}
return clone
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With