【问题标题】:iOS: How to make a node rotate around a specific axis in SceneKitiOS:如何使节点围绕 SceneKit 中的特定轴旋转
【发布时间】:2020-08-25 05:00:13
【问题描述】:

我是 Swift 编程和 SceneKit 框架的新手。 我正在尝试构建一个 Rubik's twist 应用程序,到目前为止,我所得到的是位于我相机中心的链。 Rubik's twist chain

这就是我实现它的方式:

 var snake = [SCNNode]()
    var bounds_z = Float()
    var bounds_x = Float()
    var j = 0
    for i in 0...11{
        let piece_scene_1 = SCNScene(named: "piece.scnassets/piece.scn")!
        let piece_scene_2 = SCNScene(named: "piece.scnassets/piece.scn")!
        piece_scene_1.rootNode.childNodes[0].scale = SCNVector3(0.9, 0.9, 0.9)
        piece_scene_2.rootNode.childNodes[0].scale = SCNVector3(0.9, 0.9, 0.9)
        bounds_z = Float(2*(piece_scene_1.rootNode.childNodes[0].geometry?.boundingBox.max.z ?? 0.0))
        bounds_x = Float(2*(piece_scene_1.rootNode.childNodes[0].geometry?.boundingBox.min.x ?? 0.0))
        snake.append(piece_scene_1.rootNode.childNodes[0])
        snake.append(piece_scene_2.rootNode.childNodes[0])
        snake[j].name = "piece_\(j)"
        snake[j+1].name = "piece_\(j+1)"
        snake[j+1].rotation = SCNVector4(0, 1, 0, Float.pi)
        snake[j].position = SCNVector3(x: Float(i)*bounds_x,y: Float(0),z: Float(i)*bounds_z)
        snake[j+1].position = SCNVector3(x: Float(i)*bounds_x,y: Float(0),z: Float(i+1)*bounds_z)
        scene.rootNode.addChildNode(snake[j])
        scene.rootNode.addChildNode(snake[j+1])
        j+=2
    }
    cameraNode.look(at: snake[(snake.count/2)-1].position)

我现在的问题是让一组棋子在被点击时旋转。我的想法是制作一个容器节点,在轻敲之前添加所有节点,然后围绕轻敲件面的法线轴旋转容器(与容器相邻)。 这是我的尝试:

@objc func handleTap(_ gestureRecognize: UIGestureRecognizer){

            let sceneView = self.view as! SCNView
            let p = gestureRecognize.location(in: sceneView)
            let hitResults = sceneView.hitTest(p, options: [:])
            if hitResults.count > 0 {
                // retrieved the first clicked object
                let result: SCNHitTestResult = hitResults[0]
                let container = SCNNode()
                let id_name = result.node.name
                let id_array = id_name?.components(separatedBy: CharacterSet.decimalDigits.inverted)
                  // add nodes to container
                    for item in id_array! {
                         if let id = Int(item){
                            for i in 0...id-1{
                                container.addChildNode(scene.rootNode.childNode(withName: "piece_\(i)", recursively: true)!)
                                }
                           // add container to scene
                            scene.rootNode.addChildNode(container)
                            // get container orientation
                            var GLKQuat = GLKQuaternionMake(container.orientation.x, container.orientation.y, container.orientation.z, container.orientation.w)
                            // get future orientation
                            let multiplier = GLKQuaternionMakeWithAngleAndAxis(Float.pi/2, 0, 0, 1)                        
                            // assign new orientation to container
                            GLKQuat = GLKQuaternionMultiply(GLKQuat, multiplier)
                            container.orientation = SCNQuaternion(GLKQuat.x, GLKQuat.y, GLKQuat.z, GLKQuat.w)           
                            // maintain childs position after rotation
                            for childnode in container.childNodes{
                                let child_transform = childnode.parent!.convertTransform(childnode.transform, to: scene.rootNode)
                                childnode.removeFromParentNode()
                                childnode.transform = child_transform
                                scene.rootNode.addChildNode(childnode)}
                           }
                         }
                       }
                     }

问题是因为容器是一个scene.rootNode.child,会围绕它的z轴旋转 像这样: Rubiks twist chain after rotation

【问题讨论】:

    标签: ios transform scenekit scnnode


    【解决方案1】:

    绕z轴旋转是由这行代码引起的

    let multiplier = GLKQuaternionMakeWithAngleAndAxis(Float.pi/2, 0, 0, 1) 
    

    如果要绕另一个轴旋转,则必须指定 x、y 和 z 分量: from the Apple documentation

    【讨论】:

    • 这正是我要说的。如何让我的容器围绕分接节点的 z 轴旋转?
    【解决方案2】:

    经过几天的努力,我终于找到了解决办法:

     let container = SCNNode()
     for i in 0...id-1{
     container.addChildNode(scene.rootNode.childNode(withName: "piece_\(i)", recursively: true)!)
     }
     container.name = "body_to_rotate"
     // add the container to scene root node
     scene.rootNode.addChildNode(container)
     // transform from container to tapped node 
     let container_transform = container.parent!.convertTransform(container.transform, to: result.node)
     container.transform = container_transform
     // add container as child node to tapped node
     result.node.addChildNode(container)
     // make the rotation happen
     let old_rotation = result.node.orientation
     var quat_rot = GLKQuaternionMake(old_rotation.x, old_rotation.y, old_rotation.z, old_rotation.w)
     let multiplier = GLKQuaternionMakeWithAngleAndAxis(Float.pi/2, 0, 0, 1)
                                        quat_rot = GLKQuaternionMultiply(quat_rot, multiplier)
     result.node.orientation = SCNQuaternion(quat_rot.x, quat_rot.y, quat_rot.z, quat_rot.w)
     for childnode in container.childNodes{
         let child_transform = childnode.parent!.convertTransform(childnode.transform, to: scene.rootNode)
         childnode.removeFromParentNode()
         childnode.transform = child_transform
         scene.rootNode.addChildNode(childnode)
         }
     // delete container
     container.removeFromParentNode()
    

    【讨论】:

      猜你喜欢
      • 2018-07-05
      • 1970-01-01
      • 1970-01-01
      • 2019-08-05
      • 2019-01-14
      • 2014-10-05
      • 2018-02-25
      • 2019-06-27
      • 1970-01-01
      相关资源
      最近更新 更多