0

我正在处理具有已更改的枢轴和位置的子节点。我发现了很多 SCNNode 转换主题,但似乎没有一个能代表我的情况。

我有六个球:(不能发布超过 2 个链接,图片位于 i.stack.imgur.com/v3Lc4.png)

我选择了其中的前四个,调整枢轴,调整位置(以抵消枢轴平移效果),然后旋转。这是我使用的代码:

//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 子节点释放回rootNode,我使用这段代码作为完成块:

//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.
}
}
4

1 回答 1

0

SCNActions 直接更新表示树,而不是模型树,这可能在 2014 WWDC 视频中得到了最好的解释(跳到 16:38)。这意味着在整个动画过程中,每个动画节点的当前变换只能从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)
    }
})

node.worldTransform == node.presentationNode.worldTransform当它到达完成处理程序时,我期待 TBH 。

于 2016-08-11T10:14:14.587 回答