Rotate camera around origin problem

Hey guys!

I’m trying to rotate a camera around the global origin, as if it was moving on a sphere, maintaining the same length to the origin at all times. Like the movement that is typical for any 3D model-viewer.

It works great when just rotating around the y-axis, pointing upwards.

camera.rotateAround(
    				new Vector3(0f, 0f, 0f), 
    				new Vector3(0f,1f,0f), 
    				1f);

The API is like this, for reference:

camera.rotateAround(
    				point, 
    				axis, 
    				degrees);

However, when I want the camera to rotate upwards or downwards, I need to take care that the camera might already be rotated. Therefore, I can’t just rotate around the x- og z-axis. I tried finding the perpendicular vector in 2D and rotating it around that, and that worked!

camera.rotateAround(
    				new Vector3(0f, 0f, 0f), 
    				new Vector3(
    						-camera.position.z,
    						0f,
    						camera.position.x), 
    				1f);

Here’s the problem though: Whenever my camera is directly above or directly below the origin, this math breaks and I can no longer rotate. I’d like to, though. How can I solve this problem, so it doesn’t break in these two cases?

It sounds like you are running into gimbal lock, which this video does a good job of explaining:

The best solution to this is to represent your rotations by quaternions instead of Euler angles. The math for those can be a little confusing at first, but once you get the hang of it you’ll really like them.

Thanks for the reply!

I tried using Quaternions instead, and it works… kind of. When rotating the camera around itself, there are no problems. However, when I try to rotate it around the origin, the gimbal lock problem persists.

This is what I do.

Quaternion quat = new Quaternion( // Assemble the quaternion from perpendicular vector
    				new Vector3(
    						-camera.position.z,
    						0f,
    						camera.position.x), 
    				Gdx.input.getDeltaY() // This is supposedly the angle of rotation. I'm using the mouse to move the camera.
    		);
camera.position.set(0f, 0f, 0f);
camera.rotate(quat);
camera.position.add(
    				new Vector3(  // Moving the camera 10 units away, along the opposite vector of the cameras facing direction
    						-camera.direction.x,
    						-camera.direction.y,
    						-camera.direction.z).nor().mul(10f)
    				);

The problem is probably how I make that quaternion, but I don’t know how else I’d do it. I’m using LibGDX, by the way. :slight_smile:

You can’t get gimbal lock with quaternions…describe what camera control you’re trying to implement.

There’s an invisible sphere around the origin, on which the camera can move. The camera will always point to the center of the sphere (the origin). This creates the effect of rotating the actual world.

The reason I need this behavior, is that I need to be able to look at a model in the origin, from any angle.

I’d say: arcball. It’s a nice start. I like to modify it so that when you click-and-drag outside of the invisible sphere that camera rotates about the vector into the screen. The combo makes it really easy to look at something in an arbitrary orientation.

I’m quite sure arcball is not what I am looking for. I find it very hard to control what I’m looking at, with that solution.

Is there anything wrong with the code I posted? Am I doing something wrong with the quaternions? It was a shot in the dark for me, using them, so I can’t tell if I’m doing something horribly wrong.

EDIT: I just found out my implementation has the same annoying thing as arcball, where the whole scene is tilted and it’s impossible to adjust this with the mouse. The gimbal lock also persists. I’m all ears about how to implement the camera without the silly gimbal lock.

The mod I suggested is to deal with the tilt.

I don’t know how to implement this, then. I’d still do it the way I showed you, and that doesn’t really work when I run it. Googling did nothing, as it seems I’m currently doing it correctly. Or maybe I can’t clearly see what they are doing differently.

I don’t know how I would implement your modification either.

Can you post some pseudocode, or be more specific about how an arcball is different from what I’m currently doing, or what I am doing wrong? :slight_smile:

I’ll try to find time tom. (monday)

Use this method to convert from a quaternion to a rotation matrix:

public static Matrix4f rotationFromQuaternion(Quaternion q) {
	Matrix4f mat = new Matrix4f();

	float xSq = q.x * q.x;
	float ySq = q.y * q.y;
	float zSq = q.z * q.z;
	float wSq = q.w * q.w;
	float twoX = 2.0f * q.x;
	float twoY = 2.0f * q.y;
	float twoW = 2.0f * q.w;
	float xy = twoX * q.y;
	float xz = twoX * q.z;
	float yz = twoY * q.z;
	float wx = twoW * q.x;
	float wy = twoW * q.y;
	float wz = twoW * q.z;

	mat.m00 = wSq + xSq - ySq - zSq;
	mat.m10 = xy - wz;
	mat.m20 = xz + wy;
	mat.m30 = 0;
	mat.m01 = xy + wz;
	mat.m11 = wSq - xSq + ySq - zSq;
	mat.m21 = yz - wx;
	mat.m31 = 0;
	mat.m02 = xz - wy;
	mat.m12 = yz + wx;
	mat.m22 = wSq - xSq - ySq + zSq;
	mat.m32 = 0;
	mat.m03 = 0;
	mat.m13 = 0;
	mat.m23 = 0;
	mat.m33 = 1;
	return mat;
}

You can just multiply this matrix by your camera matrix and it will give you what you want. org.lwjgl.util.Quaternion has the method Quaternion.setFromAxisAngle() for constructing a quaternion from a vector and an orientation. My guess is that you should be using that.

It’s a little more involved than converting a quat to matrix. You have an initial quat prior to a mouse action which you need to compose with something that feels like a natural manipulation of the object (which is another quaternion) to get the new result. Choose an axis based on the direction of the mouse-drag has never felt very good to me.

That is a good point. I guess it all depends on how his rotation method is actually implemented. Are you using cross products to compute the up, forward, and right vectors of the camera? If so, make sure that you are not taking a cross between two parallel vectors as this will output the zero vector and is an undesirable result.

Thanks for the help guys!

The next section is about upward/downward rotation only. The vector to rotate about changes, because I’m also rotating around the y-axis (poiting upwards).

Currently, I’m finding the vector to rotate about, by taking the taking the x/z coords of the camera position, switching them around and negating the new x-coord.
This is to find the perpendicular vector to the camera position, in 2D space (the y-axis points upwards).

I imagine the problem arises when trying to define this perpendicular vector, when both the x-coord and z-coord are both zero (the case where the camera is directly above or below the origin). I think thats the reason it doesn’t help to use the vector “as” a quaternion, because the vector will still never be assembled correctly.

Now, I think my problem comes down to this: How can I find this vector in a reliable way? A way that doesn’t break in specific cases. :stuck_out_tongue:

Haven’t had a time window yet to toss this together…just saying I remember and still plan on doing it.

OK. In the spirit of hack-and-slash, here’s the 10 minute version. Slight modified source of SHC as a test harness:

http://pastebin.java-gaming.org/f7d425d0481
http://pastebin.java-gaming.org/9f7d4420d84

Most likely very buggy and only standard arcball (without constraint support):

http://pastebin.java-gaming.org/7d42d640181

I’ve set the projected radius to .5 so that you can drag outside of the sphere easy to correct for tilt without any extra bells and whistles for evalulation purposes. Somebody surely has a nice clean java version somewhere.

Oh yeah…it doesn’t even account for the screen aspect (so the sphere/circle is warped)…so all the controls ARE going to feel off.