Stop sharing node's geometry with its clone programmatically

纵然是瞬间 提交于 2019-12-05 23:58:29

问题


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?


回答1:


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]
}



回答2:


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
}


来源:https://stackoverflow.com/questions/39902802/stop-sharing-nodes-geometry-with-its-clone-programmatically

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!