SCNNode 释放具有改变的变换和枢轴属性的子节点
SCNNode releasing children with altered transform and pivot properties
我正在处理枢轴和位置已更改的子节点。找了很多SCNNode改造的题目,不过好像none代表我的情况
我有六个球:(不能post超过2个链接,图片在i.stack.imgur.com/v3Lc4.png)
而我select前四名,调整枢轴,调整位置(对抗枢轴平移效应),旋转。这是我使用的代码:
//core code
let fourBalls = SCNNode()
for i in 1...4
{
let ball = scene.rootNode.childNode(withName: "b" + String(i), recursively: false)!
ball.removeFromParentNode()
fourBalls.addChildNode(ball)
}
scene.rootNode.addChildNode(fourBalls)
//adjust the pivot of the fourBalls node
fourBalls.pivot = SCNMatrix4MakeTranslation(-1.5, 0.5, -5)
//fix the position
fourBalls.position = SCNVector3Make(-1.5, 0.5, -5)
//rotate
let action = SCNAction.rotateBy(x: 0, y: 0, z: CGFloat(M_PI_2), duration: 2)
fourBalls.run(action)
它做得很好:
现在,我需要将 fourBalls 子节点释放回根节点,我使用这段代码作为完成块:
//core problem
//how to release the node with the transform?
for node in fourBalls.childNodes
{ node.transform = node.worldTransform
node.removeFromParentNode()
self.scene.rootNode.addChildNode(node)
}
问题来了,我放错了:
所以我的问题是,如何将子节点释放到具有正确的枢轴、位置和变换属性的根节点?
这是我的完整 GameViewController.swift 给想尝试的你:
import SceneKit
class GameViewController: UIViewController {
let scene = SCNScene()
override func viewDidLoad() {
super.viewDidLoad()
let ball1 = SCNSphere(radius: 0.4)
let ball2 = SCNSphere(radius: 0.4)
let ball3 = SCNSphere(radius: 0.4)
let ball4 = SCNSphere(radius: 0.4)
let ball5 = SCNSphere(radius: 0.4)
let ball6 = SCNSphere(radius: 0.4)
ball1.firstMaterial?.diffuse.contents = UIColor.purple()
ball2.firstMaterial?.diffuse.contents = UIColor.white()
ball3.firstMaterial?.diffuse.contents = UIColor.cyan()
ball4.firstMaterial?.diffuse.contents = UIColor.green()
ball5.firstMaterial?.diffuse.contents = UIColor.black()
ball6.firstMaterial?.diffuse.contents = UIColor.blue()
let B1 = SCNNode(geometry: ball1)
B1.position = SCNVector3(x:-2,y:1,z:-5)
scene.rootNode.addChildNode(B1)
B1.name = "b1"
let B2 = SCNNode(geometry: ball2)
B2.position = SCNVector3(x:-1,y:1,z:-5)
scene.rootNode.addChildNode(B2)
B2.name = "b2"
let B3 = SCNNode(geometry: ball3)
B3.position = SCNVector3(x:-2,y:0,z:-5)
scene.rootNode.addChildNode(B3)
B3.name = "b3"
let B4 = SCNNode(geometry: ball4)
B4.position = SCNVector3(x:-1,y:0,z:-5)
scene.rootNode.addChildNode(B4)
B4.name = "b4"
let B5 = SCNNode(geometry: ball5)
B5.position = SCNVector3(x:-2,y:-1,z:-5)
scene.rootNode.addChildNode(B5)
B5.name = "b5"
let B6 = SCNNode(geometry: ball6)
B6.position = SCNVector3(x:-1,y:-1,z:-5)
scene.rootNode.addChildNode(B6)
B6.name = "b6"
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3Make(-1.5,0,2)
scene.rootNode.addChildNode(cameraNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = UIColor.yellow()
scene.rootNode.addChildNode(ambientLightNode)
let scnView = self.view as! SCNView
scnView.scene = scene
scnView.allowsCameraControl = false
scnView.backgroundColor = UIColor.orange()
//core code
let fourBalls = SCNNode()
for i in 1...4
{
let ball = scene.rootNode.childNode(withName: "b" + String(i), recursively: false)!
ball.removeFromParentNode()
fourBalls.addChildNode(ball)
}
scene.rootNode.addChildNode(fourBalls)
//adjust the pivot of the fourBalls node
fourBalls.pivot = SCNMatrix4MakeTranslation(-1.5, 0.5, -5)
//fix the position
fourBalls.position = SCNVector3Make(-1.5, 0.5, -5)
//rotate
let action = SCNAction.rotateBy(x: 0, y: 0, z: CGFloat(M_PI_2), duration: 2)
fourBalls.run(action, completionHandler:
{
//core problem
for node in fourBalls.childNodes
{
node.transform = node.worldTransform
node.removeFromParentNode()
self.scene.rootNode.addChildNode(node)
}
})
}
override func shouldAutorotate() -> Bool {
return true
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.current().userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
}
SCNActions 直接更新表示树,而不是模型树,这可能在 2014 WWDC video (skip to 16:38). What this means is that throughout the animation the current transform for each of the animating nodes is only available from the presentationNode
中得到了最好的解释。如果我们从这里获取转换,您的代码就可以工作。
对 Swift 2 向后移植表示歉意...
//rotate
let action = SCNAction.rotateByX(0, y: 0, z: CGFloat(M_PI_2), duration: 2)
fourBalls.runAction(action, completionHandler: {
//core problem
for node in fourBalls.childNodes
{
node.transform = node.presentationNode.worldTransform
node.removeFromParentNode()
self.scene.rootNode.addChildNode(node)
}
})
TBH 当它到达完成处理程序时我期待 node.worldTransform == node.presentationNode.worldTransform
。
我正在处理枢轴和位置已更改的子节点。找了很多SCNNode改造的题目,不过好像none代表我的情况
我有六个球:(不能post超过2个链接,图片在i.stack.imgur.com/v3Lc4.png)
而我select前四名,调整枢轴,调整位置(对抗枢轴平移效应),旋转。这是我使用的代码:
//core code
let fourBalls = SCNNode()
for i in 1...4
{
let ball = scene.rootNode.childNode(withName: "b" + String(i), recursively: false)!
ball.removeFromParentNode()
fourBalls.addChildNode(ball)
}
scene.rootNode.addChildNode(fourBalls)
//adjust the pivot of the fourBalls node
fourBalls.pivot = SCNMatrix4MakeTranslation(-1.5, 0.5, -5)
//fix the position
fourBalls.position = SCNVector3Make(-1.5, 0.5, -5)
//rotate
let action = SCNAction.rotateBy(x: 0, y: 0, z: CGFloat(M_PI_2), duration: 2)
fourBalls.run(action)
它做得很好:
现在,我需要将 fourBalls 子节点释放回根节点,我使用这段代码作为完成块:
//core problem
//how to release the node with the transform?
for node in fourBalls.childNodes
{ node.transform = node.worldTransform
node.removeFromParentNode()
self.scene.rootNode.addChildNode(node)
}
问题来了,我放错了:
所以我的问题是,如何将子节点释放到具有正确的枢轴、位置和变换属性的根节点?
这是我的完整 GameViewController.swift 给想尝试的你:
import SceneKit
class GameViewController: UIViewController {
let scene = SCNScene()
override func viewDidLoad() {
super.viewDidLoad()
let ball1 = SCNSphere(radius: 0.4)
let ball2 = SCNSphere(radius: 0.4)
let ball3 = SCNSphere(radius: 0.4)
let ball4 = SCNSphere(radius: 0.4)
let ball5 = SCNSphere(radius: 0.4)
let ball6 = SCNSphere(radius: 0.4)
ball1.firstMaterial?.diffuse.contents = UIColor.purple()
ball2.firstMaterial?.diffuse.contents = UIColor.white()
ball3.firstMaterial?.diffuse.contents = UIColor.cyan()
ball4.firstMaterial?.diffuse.contents = UIColor.green()
ball5.firstMaterial?.diffuse.contents = UIColor.black()
ball6.firstMaterial?.diffuse.contents = UIColor.blue()
let B1 = SCNNode(geometry: ball1)
B1.position = SCNVector3(x:-2,y:1,z:-5)
scene.rootNode.addChildNode(B1)
B1.name = "b1"
let B2 = SCNNode(geometry: ball2)
B2.position = SCNVector3(x:-1,y:1,z:-5)
scene.rootNode.addChildNode(B2)
B2.name = "b2"
let B3 = SCNNode(geometry: ball3)
B3.position = SCNVector3(x:-2,y:0,z:-5)
scene.rootNode.addChildNode(B3)
B3.name = "b3"
let B4 = SCNNode(geometry: ball4)
B4.position = SCNVector3(x:-1,y:0,z:-5)
scene.rootNode.addChildNode(B4)
B4.name = "b4"
let B5 = SCNNode(geometry: ball5)
B5.position = SCNVector3(x:-2,y:-1,z:-5)
scene.rootNode.addChildNode(B5)
B5.name = "b5"
let B6 = SCNNode(geometry: ball6)
B6.position = SCNVector3(x:-1,y:-1,z:-5)
scene.rootNode.addChildNode(B6)
B6.name = "b6"
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3Make(-1.5,0,2)
scene.rootNode.addChildNode(cameraNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = UIColor.yellow()
scene.rootNode.addChildNode(ambientLightNode)
let scnView = self.view as! SCNView
scnView.scene = scene
scnView.allowsCameraControl = false
scnView.backgroundColor = UIColor.orange()
//core code
let fourBalls = SCNNode()
for i in 1...4
{
let ball = scene.rootNode.childNode(withName: "b" + String(i), recursively: false)!
ball.removeFromParentNode()
fourBalls.addChildNode(ball)
}
scene.rootNode.addChildNode(fourBalls)
//adjust the pivot of the fourBalls node
fourBalls.pivot = SCNMatrix4MakeTranslation(-1.5, 0.5, -5)
//fix the position
fourBalls.position = SCNVector3Make(-1.5, 0.5, -5)
//rotate
let action = SCNAction.rotateBy(x: 0, y: 0, z: CGFloat(M_PI_2), duration: 2)
fourBalls.run(action, completionHandler:
{
//core problem
for node in fourBalls.childNodes
{
node.transform = node.worldTransform
node.removeFromParentNode()
self.scene.rootNode.addChildNode(node)
}
})
}
override func shouldAutorotate() -> Bool {
return true
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.current().userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
}
SCNActions 直接更新表示树,而不是模型树,这可能在 2014 WWDC video (skip to 16:38). What this means is that throughout the animation the current transform for each of the animating nodes is only available from the presentationNode
中得到了最好的解释。如果我们从这里获取转换,您的代码就可以工作。
对 Swift 2 向后移植表示歉意...
//rotate
let action = SCNAction.rotateByX(0, y: 0, z: CGFloat(M_PI_2), duration: 2)
fourBalls.runAction(action, completionHandler: {
//core problem
for node in fourBalls.childNodes
{
node.transform = node.presentationNode.worldTransform
node.removeFromParentNode()
self.scene.rootNode.addChildNode(node)
}
})
TBH 当它到达完成处理程序时我期待 node.worldTransform == node.presentationNode.worldTransform
。