4

I'm looking to understand quaternions for three.js, but for all the tutorials, I haven't been able to translate them into the application I need. This is the problem:

Given a sphere centered at (0,0,0), I want to angle an object on the sphere's surface, that acts as the focal point for the camera. This point is to be moved and rotated on the surface with keyboard input. Setting the focal point into a chosen orbit is easy of course, but maintaining the right rotation perpendicular to the surface escapes me. I know quaternions are neccessary for smooth movement and arbitrary axis rotation, but I don't know where to start.

The second part then is rotating the camera offset with the focal point. The snippet I found for this does not have the desired effect anymore, as the cameraOffset does not inherit the rotation:

var cameraOffset = relativeCameraOffset.clone().applyMatrix4( focalPoint.matrixWorld );
camera.position.copy( focalPoint.position.clone().add(cameraOffset) );
camera.lookAt( focalPoint.position );

Update 1: Tried it with fixed camera on the pole and rotating the planet. But unless I'm missing something important, this fails as well, due to the directions getting skewed completely when going towards the equator. (Left becomes forward). Code in update is:

        acceleration.set(0,0,0);

        if (keyboard.pressed("w")) acceleration.x = 1 * accelerationSpeed;
        if (keyboard.pressed("s")) acceleration.x = -1 * accelerationSpeed;
        if (keyboard.pressed("a")) acceleration.z = 1 * accelerationSpeed;
        if (keyboard.pressed("d")) acceleration.z = -1 * accelerationSpeed;
        if (keyboard.pressed("q")) acceleration.y = 1 * accelerationSpeed;
        if (keyboard.pressed("e")) acceleration.y = -1 * accelerationSpeed;

        velocity.add(acceleration);
        velocity.multiplyScalar(dropOff);
        velocity.max(minV);
        velocity.min(maxV);

        planet.mesh.rotation.x += velocity.x;
        planet.mesh.rotation.y += velocity.y;
        planet.mesh.rotation.z += velocity.z;

So I'm still open for suggestions.

8
  • You may need help with quaternions, but not to solve your problem. See stackoverflow.com/questions/21005526/… Commented Jan 24, 2014 at 14:12
  • I see how that would solve one-time positioning and alignment, but movement would be more and more distorted the closer you are to the poles and I don't see a way around that. Commented Jan 24, 2014 at 16:13
  • Could you please explain exactly what you want to achieve in terms of what the keyboard shall do? Do you want the view to go up/down/left/right by the same angle every time the user presses one of these keys for a defined amount of time? (i.e.: avoid gimbal lock when looking at the poles and left/right do nothing). Ideally you'd need 6 keys: up-down, left-right, clowckwise-counterclockwise roll, but you may have something else in mind, so better ask before answering out of topic! Commented Jan 24, 2014 at 17:53
  • 1
    Can you keep the camera fixed above the north pole, and spin the planet underneath? Logically easier. Commented Jan 24, 2014 at 22:21
  • 1
    The current planet rotation, and the extra spin you want to add during each iteration have to be combined. This is not an addition like in your sample code. You have to create a new rotation for the current iteration and combine it with the previous planet total rotation. Combining rotations is equivalent to matrix multiplications or quaternion multiplications. Commented Jan 26, 2014 at 13:57

2 Answers 2

4

Finally found the solution from a mixture of matrices and quaternions:

    //Setup
    var ux = new THREE.Vector3(1,0,0);
    var uy = new THREE.Vector3(0,1,0);
    var uz = new THREE.Vector3(0,0,1);

    var direction = ux.clone();
    var m4 = new THREE.Matrix4();
    var dq = new THREE.Quaternion(); //direction quad base
    var dqq;   //final direction quad
    var dq2 = new THREE.Quaternion();
    dq2.setFromAxisAngle(uz,Math.PI/2); //direction perpendicular rot

        //Update
        if (velocity.length() < 0.1) return;
        if (velocity.x) { focalPoint.translateY( velocity.x ); }
        if (velocity.y) { focalPoint.translateX( velocity.y ); }
        //create new direction from focalPoint quat, but perpendicular
        dqq = dq.clone().multiply(focalPoint.quaternion).multiply(dq2);

        velocity.multiplyScalar(dropOff);
        //forward direction vector          
        direction = ux.clone().applyQuaternion(dqq).normalize();
        //use Matrix4.lookAt to align focalPoint with the direction
        m4.lookAt(focalPoint.position, planet.mesh.position, direction);
        focalPoint.quaternion.setFromRotationMatrix(m4);

        var cameraOffset = relativeCameraOffset.clone();
        cameraOffset.z = cameraDistance;

        cameraOffset.applyQuaternion(focalPoint.quaternion);

        camera.position = focalPoint.position.clone().add(cameraOffset) ;
        //use direction for camera rotation as well
        camera.up = direction;
        camera.lookAt( focalPoint.position );

This is the hard core of it. It pans (and with some extension rotates) around the planet without the poles being an issue.

Sign up to request clarification or add additional context in comments.

Comments

1

I'm not sure to understand your problem. But for help, I draw a boat on a sphere with the code below.

var geometry = new THREE.ShapeGeometry(shape);
var translation = new THREE.Matrix4().makeTranslation(boat.position.x, boat.position.y, boat.position.z);
var rotationZ = new THREE.Matrix4().makeRotationZ(-THREE.Math.degToRad(boat.cap));
var rotationX = new THREE.Matrix4().makeRotationX(-THREE.Math.degToRad(boat.latitude));
var rotationY = new THREE.Matrix4().makeRotationY(Math.PI / 2 + THREE.Math.degToRad(boat.longitude));
var roationXY = rotationY.multiply(rotationX);
geometry.applyMatrix(rotationZ);
geometry.applyMatrix(roationXY );
geometry.applyMatrix(translation);
  1. First, I apply a rotation on Z to define boat cap
  2. Then, I apply rotation on Y,X to to set the boat perpendicular to the surface of the sphere
  3. Finally I apply a translation to put the boat on the surafce of the sphere

The rotations order is important

1 Comment

Tried it like this, but even without the translation, the position of the object flickers between 2 points. (Meaning I get different Lat/Lon on each update). Maybe so because the order of rotation matters without quaternions, but I'm really just guessing here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.