Cameranode Rotate as iOS Device Moving

Rotate camera around itself

There are many ways to handle rotation, some are very suitable for giving headaches to the coder.

It sounds like the model is at 0,0,0, meaning it’s in the center of the world, and the camera is tranformed to a certain location. In the first example using matrices, you basically rotate that transformation. So you transform first, then rotate, which yes will cause it to rotate around the origin (0,0,0).

What you should do instead, to rotate the camera in local space, is rotate the camera first in local space and then translate it to its position in world space.

Translation x rotation matrix results in rotation in world space

Rotation x translation matrix results in rotation in local space

So a solution is to remove the translation from the camera first (moving it back to 0,0,0), then apply the rotation matrix, and then reapply the translation. This comes down to the same result as starting with an identity matrix. For example:

let rotated = SCNMatrix4Rotate(SCNMatrixIdentity, moveX, 0, 1, 0)
cameraNode.transform = SCNMatrix4Multiply(rotated, cameraNode.transform)

Lock camera rotation around

Create empty node and add cameraNode as its child. rotate cameraNode for x and emptyNode for y.

Please help me correctly apply device rotation data

J.Doe!

First there is a slight trick. If you want to use the iphone laying down as the default position you have to notice that the axis used on sceneKit are different then those used by the DeviceMotion. Check the axis:

deviceMotion axis
sceneKit axis
(source: apple.com)

First thing you need to set is the camera position. When you start a SceneKit project it creates your camera in the position (0, 0, 15). There is a problem with that:

The values of eulerAngles = (0,0,0) would mean the object would be in the plane xz, but as long as you are looking from Z, you just see it from the side. For that to be equivalent to the iphone laying down, you would need to set the camera to look from above. So it would be like you were looking at it from the phone (like a camera, idk)

// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)

// place the camera
cameraNode.position = SCNVector3(x: 0, y: 15, z: 0)
// but then you need to make the cameraNode face the ship (the origin of the axis), rotating it
cameraNode.eulerAngles.x = -Float(M_PI)*0.5 //or Float(M_PI)*1.5

With this we are going to see the ship from above, so the first part is done.
Now we gotta make the ship remain "still" (facing the ground) with the device rotation.

//First we need to use SCNRendererDelegate
class GameViewController : UIViewController SCNSceneRendererDelegate{
private let motion = CMMotionManager();
...

Then on viewDidLoad:

//important if you remove the sceneKit initial action from the ship.
//The scene would be static, and static scenes do not trigger the renderer update, setting the playing property to true forces that:
scnView.playing = true;
if(motion.deviceMotionAvailable){
motion.startDeviceMotionUpdates();
motion.deviceMotionUpdateInterval = 1.0/60.0;
}

Then we go to the update method

Look at the axis: the axis Y and Z are "switched" if you compare the sceneKit axis and the deviceMotion axis. Z is up on the phone, while is to the side on the scene, and Y is up on the scene, while to the side on the phone. So the pitch, roll and yaw, respectively associated to the X, Y and Z axis, will be applied as pitch, yaw and roll.

Notice I've put the roll value positive, that's because there is something else "switched". It's kinda hard to visualize. See the Y axis of device motion is correlated to the Z axis of the scene. Now imagine an object rotation along this axis, in the same direction (clock-wise for example), they would be going in opposite directions because of the disposition of the axis. (you can set the roll negative too see how it goes wrong)

func renderer(renderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) {
if let rot = motion.deviceMotion?.attitude{
print("\(rot.pitch) \(rot.roll) \(rot.yaw)")
ship.eulerAngles.x = -Float(rot.pitch);
ship.eulerAngles.y = -Float(rot.yaw);
ship.eulerAngles.z = Float(rot.roll);
}

Hope that helps! See ya!

Move camera in Scenekit

If you want to slide left/right, or up/down, then you don't need the cameraOrbit node (that's what Scenekit camera orbit around object uses).

Instead, you just want to slide left/right (X axis) or up/down (Y axis) in response to touch. It looks like you're doing that. But if cameraNode is a child of cameraOrbit, you'll be moving in the coordinate system of cameraOrbit, which is also being rotated by your gesture handler! Make the camera node a child of your scene's root node.

Now the confounding thing happens when your camera isn't lined up with the root coordinate system. If the camera's X, Y, and Z axes are parallel to the scene's X/Y/Z axes, you can adjust the camera's X/Y positions to move. But if the camera's been rotated, or pointed off Z axis, you need to adjust the camera node's transform, to move left/right or up/down in the plane of the camera. I'll try to expand this answer sometime soon to demonstrate that.



Related Topics



Leave a reply



Submit