Arcball camera locked when parallel to up vector

566 Views Asked by At

I'm currently in the process of finishing the implementation for a camera that functions in the same way as the camera in Maya. The part I'm stuck in the tumble functionality.

The problem is the following: the tumble feature works fine so long as the position of the camera is not parallel with the up vector (currently defined to be (0, 1, 0)). As soon as the camera becomes parallel with this vector (so it is looking straight up or down), the camera locks in place and will only rotate around the up vector instead of continuing to roll.

This question has already been asked here, unfortunately there is no actual solution to the problem. For reference, I also tried updating the up vector as I rotated the camera, but the resulting behaviour is not what I require (the view rolls as a result of the new orientation).

Here's the code for my camera:

using namespace glm;
// point is the position of the cursor in screen coordinates from GLFW
float deltaX = point.x - mImpl->lastPos.x;
float deltaY = point.y - mImpl->lastPos.y;

// Transform from screen coordinates into camera coordinates
Vector4 tumbleVector = Vector4(-deltaX, deltaY, 0, 0);
Matrix4 cameraMatrix = lookAt(mImpl->eye, mImpl->centre, mImpl->up);
Vector4 transformedTumble = inverse(cameraMatrix) * tumbleVector;

// Now compute the two vectors to determine the angle and axis of rotation.
Vector p1 = normalize(mImpl->eye - mImpl->centre);
Vector p2 = normalize((mImpl->eye + Vector(transformedTumble)) - mImpl->centre);

// Get the angle and axis
float theta = 0.1f * acos(dot(p1, p2));
Vector axis = cross(p1, p2);

// Rotate the eye.
mImpl->eye = Vector(rotate(Matrix4(1.0f), theta, axis) * Vector4(mImpl->eye, 0));

The vector library I'm using is GLM. Here's a quick reference on the custom types used here:

typedef glm::vec3 Vector;
typedef glm::vec4 Vector4;
typedef glm::mat4 Matrix4;
typedef glm::vec2 Point2;

mImpl is a PIMPL that contains the following members:

Vector eye, centre, up;
Point2 lastPoint;
1

There are 1 best solutions below

1
On

Here is what I think. It has something to do with the gimbal lock, that occurs with euler angles (and thus spherical coordinates).

If you exceed your minimal(0, -zoom,0) or maxima(0, zoom,0) you have to toggle a boolean. This boolean will tell you if you must treat deltaY positive or not.

It could also just be caused by a singularity, therefore just limit your polar angle values between 89.99° and -89.99°.

Your problem could be solved like this.

So if your camera is exactly above (0, zoom,0) or beneath (0, -zoom,0) of your object, than the camera only rolls. (I am also assuming your object is at (0,0,0) and the up-vector is set to (0,1,0).)

There might be some mathematical trick to resolve this, I would do it with linear algebra though.

You need to introduce a new right-vector. If you make a cross product, you will get the camera-vector. Camera-vector = up-vector x camera-vector. Imagine these vectors start at (0,0,0), then easily, to get your camera position just do this subtraction (0,0,0)-(camera-vector).

So if you get some deltaX, you rotate towards the right-vector(around the up-vector) and update it.

Any influence of deltaX should not change your up-vector.

If you get some deltaY you rotate towards the up-vector(around the right-vector) and update it. (This has no influence on the right-vector).

https://en.wikipedia.org/wiki/Rotation_matrix at Rotation matrix from axis and angle you can find a important formula.

You say u is your vector you want to rotate around and theta is the amount you want to pivot. The size of theta is proportional to deltaX/Y.

For example: We got an input from deltaX, so we rotate around the up-vector.

up-vector:= (0,1,0)

right-vector:= (0,0,-1)

cam-vector:= (0,1,0)

theta:=-1*30° // -1 due to the positive mathematical direction of rotation


R={[cos(-30°),0,-sin(-30°)],[0,1,0],[sin(-30°),0,cos(-30°)]}

new-cam-vector=R*cam-vector // normal matrix multiplication

One thing is left to be done: Update the right-vector.

right-vector=camera-vector x up-vector .