1

I'm trying to recode the camera management in SceneKit. For that, I use UIPanGestureRecognizer for the rotation of camera around an object (In this case around the centre of scene).

Next I get the different ratio or length to determinate the angle to add at axes (X, Y, Z) of imaginary sphere where camera is attached (cameraOrbit in code).

My problem is that I use the position of camera to determinate the angle to add at sphere. But the position is constant. When I change the sphere rotation, the position of child node camera are never updated. Then angle never change.

import SceneKit
import UIKit

class SceneManager
{
    private let scene: SCNScene
    private let view: SCNView
    private let camera: SCNNode
    private let cameraOrbit: SCNNode
    private let cameraRadius: Float

    init(view: SCNView, assetFolder: String, sceneName: String, cameraName: String, backgroundColor: UIColor) {
        self.view = view
        self.scene = SCNScene(named: (assetFolder + "/" + sceneName))!
        if (self.scene.rootNode.childNodeWithName(cameraName, recursively: true) == nil) {
            print("Fatal error: Cannot find camera in scene with name :\"", cameraName, "\"")
            exit(1)
        }
        self.camera = self.scene.rootNode.childNodeWithName(cameraName, recursively: true)! // Retrieve cameraNode created in scene file
        self.cameraOrbit = SCNNode()
        self.cameraOrbit.addChildNode(self.camera)
        self.cameraRadius = sqrt(pow((self.camera.position.x), 2) + pow(self.camera.position.y, 2)) // CameraOrbit radius for rotation camera in panHandler
        self.scene.rootNode.addChildNode(self.cameraOrbit)
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panHandler(_:)))
        panGesture.maximumNumberOfTouches = 1
        self.view.addGestureRecognizer(panGesture)
        self.view.backgroundColor = backgroundColor
        self.view.pointOfView = self.camera
        self.view.scene = self.scene
    }

    @objc private func panHandler(sender: UIPanGestureRecognizer) {
        let alpha = cos(self.camera.position.z / self.cameraRadius) // Get angle of camera

        // --
        print(self.camera.position) // <-------- (X, Y, Z) The axes position are always the same
        // --

        var ratioX = 1 - ((CGFloat)(alpha) / (CGFloat)(M_PI)) // Get the radio with angle for apply to Z and X axes rotation
        var ratioZ = ((CGFloat)(alpha) / (CGFloat)(M_PI))
        // Change direction of rotation depending camera's position in trigonometric circle
        if (self.camera.position.z > 0 && self.camera.position.x < 0) {
            ratioZ *= -1
        } else if (self.camera.position.z < 0 && self.camera.position.x < 0) {
            ratioX *= -1
            ratioZ *= -1
        } else if (self.camera.position.z > 0 && self.camera.position.x > 0) {
            ratioX *= -1
        }
        // Set the angle rotation to add at imaginary sphere (cameraOrbit)
        let xAngleToAdd = (sender.velocityInView(sender.view!).y / 10000) * ratioX
        let yAngleToAdd = (sender.velocityInView(sender.view!).x / 10000) * (-1)
        let zAngleToAdd = (sender.velocityInView(sender.view!).y / 10000) * ratioZ
        let rotation = SCNAction.rotateByX(xAngleToAdd, y: yAngleToAdd, z: zAngleToAdd, duration: 0.5)
        self.cameraOrbit.runAction(rotation)
    }
}

If anyone have an idea? Thanks

Magiguigui
  • 151
  • 2
  • 13
  • I noticed that you refer to "cameranode" from `self.rootNode.childNodeWithName`. And then call `self.camearOrbit.addChildNode(self.cameranode)`. Shoudn't you call `self.cameranode.removeFromParentNode` before adding the cameranode to the cameraOrbit? – Pro Blaster Jul 23 '16 at 19:09

1 Answers1

2

When you update the parent node's transform (position, rotation, scale), the child nodes' transform remains unchanged in local coordinates (relative to the parent), it only changes in world coordinates.

If you want to access the world transform for a given node, use the worldTransform property.

Karl Sigiscar
  • 289
  • 1
  • 7