Quaternion camera translations

Started by
5 comments, last by Rakshasa 17 years, 1 month ago
Hi, I've been having some trouble translating my quaternion camera for some time now, and I was wondering if you could help me out. I know I don't fully understand the math behind matrices and quaternions and whatnot, but am learning quite fast. I'm making a free-rotating camera, which allows free navigation using the mouse and it's all three buttons, but I can't find any help on translating the camera when the camera orientation is totally free. It seems as if the vector for the translations is for some reason mirrored over every global axis. Here are the relevant parts of the code:

void GLCamera::setPerspective () {
	GLfloat mat[16];

	rotation.createMatrix(mat);

	glMultMatrixf (mat);

	glTranslatef (campos.x, campos.y, campos.z);
}

void GLCamera::rotate (float x, float y, float z) {
	GLQuaternion qYaw, qPitch;
		
	qPitch.createFromAngle (1.0f, 0.0f, 0.0f, y);
	qYaw.createFromAngle (0.0f, 1.0f, 0.0f, x);
	
	rotation = qYaw * rotation;
	rotation = qPitch * rotation;
}

void GLCamera::translate (float x, float y, float z) {
	campos += rotation * Vector3d (x,y,z) * 0.1f;
}

Vector3d GLQuaternion::operator* (const Vector3d v) const {
        Vector3d vn (v);
	vn.normalize ();
	GLQuaternion vq, rq;
	vq.m_x = vn.x;
	vq.m_y = vn.y;
	vq.m_z = vn.z;
	vq.m_w = 0.0f;
		
	rq = vq * conjugate ();
	rq = *this * rq;
		
	return (Vector3d (rq.m_x, rq.m_y, rq.m_z));
}

GLQuaternion GLQuaternion::conjugate () const {
	return (GLQuaternion (-m_x, -m_y, -m_z, m_w));
}

Everyone just seems to be making a 3d-shooter, and tutorials for those seem to be no good when making a true 3d-camera.
Doesn't matter how much you lose as long as you make sure the winner loses enough blood.
Advertisement
Couple o' things:

1. You didn't post the code that (presumably) makes use of the GLCamera::translate() function to change the position of the ship, so it's a little hard to say why you're not getting the correct results. Can you post that code?

2. Why are you normalizing the input vector in the quaternion-vector multiplication function? I'm not sure if that's the cause of the problem, but in any event it's not typical; the length of a vector should be invariant under rotation.

3. IMO overloading operator*() as 'quaternion-vector multiplication' is a bad idea - that's something you might revisit after you get things working.
1.
static void main_loop () {	SDL_Event event;	while (1) {		while (SDL_PollEvent (&event)) {			switch (event.type) {			case SDL_MOUSEMOTION:				gfx.putMouseAt (event.motion.x, event.motion.y);				if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_LEFT)) {					gfx.rotate (event.motion.xrel, event.motion.yrel);				} else if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT)) {					gfx.move (float(event.motion.xrel)/100, -float(event.motion.yrel)/100, 0.0f);				}				break;			case SDL_MOUSEBUTTONDOWN:				switch (event.button.button) {				case SDL_BUTTON_WHEELDOWN:					gfx.moveOut ();				break;				case SDL_BUTTON_WHEELUP:					gfx.moveIn ();				break;				}			break;			}		}		usleep (2);	}}void Gfx::rotate (float x, float y) {	camera.rotate (x, y, 0.0f);}void Gfx::move (float x, float y, float z) { 	camera.translate (x, y, z);}


I am aware there is some unwanted spaghetti in the code... (Main calling gfx calling camera..), but I just haven't gotten to rewrite them... =P

2. The input vector was normalized in the tutorial x, which I used to write the basics of the camera and quaternion classes. It seemed a bit odd, I must admit.

3. operator* is also overloaded as quaternion multiplication. At the moment I consider it a nice feat to be able to use * to multiply a vector with a quaternion.
Doesn't matter how much you lose as long as you make sure the winner loses enough blood.
Quote:Original post by Rakshasa
1.
*** Source Snippet Removed ***
I see several places there where the camera's position is adjusted. Which of them isn't working?

Also, I don't see the moveIn() and moveOut() functions anywhere, so you might post those as well.
Sigh, I just keep forgetting everything...

	void moveIn () {		camera.translate (0.0f, 0.0f, -0.1f);	}	void moveOut () {		camera.translate (0.0f, 0.0f, 0.1f);	}


All the move functions work incorrectly after the camera has been rotated, but work correctly if I translate from the original position.

It's as if the rotated camera translation is applied mirrored over every global axis or something.
Doesn't matter how much you lose as long as you make sure the winner loses enough blood.
There are still a lot of places that the error could be (for example, in the quat-to-matrix conversion code), but here's another thing that I noticed:
void GLCamera::setPerspective () {    GLfloat mat[16];    rotation.createMatrix(mat);    glMultMatrixf (mat);    glTranslatef (campos.x, campos.y, campos.z);}
This is almost certainly wrong.

First of all, the term 'perspective' in 3D graphics generally refers to a type of projection; a name such as setViewTransform() might be more appropriate here.

Now, assuming this function is intended to set the view transform, the operations are in the right order but the transforms themselves are incorrect. Each component transform needs to be inverted, like this:
void GLCamera::setPerspective () {    GLfloat mat[16];    rotation.conjugate().createMatrix(mat);    glMultMatrixf (mat);    glTranslatef (-campos.x, -campos.y, -campos.z);}
Once you make this change, you may find that your key mappings for changing the ship's rotation are 'backwards'. This is because they're probably already backwards to compensate for the incorrect view transform; just reverse them and you should be ok.

Note that making the above change still might not fix the problem (the bits of code you haven't posted might still be in error), but it should be a step in the right direction.
Thank you jyk, you've been most helpful. I changed the function to setViewTransform as you suggested, and after I inverted all the transform attributes, the camera transformation started working correctly. Now there is a slight new problem; When the Yaw is ±90 degrees, pitch becomes roll.

EDIT: I fixed the rotation by rewriting the rotation function like this:
void GLCamera::rotate (float x, float y, float z) {	yaw += x;	pitch += y;			if (yaw > 360)		yaw -= 360;	else if (yaw < -360)		yaw += 360;	if (pitch > 360)		pitch -= 360;	else if (pitch < -360)		pitch += 360;			GLQuaternion qYaw, qPitch;			qPitch.createFromAngle (1.0f, 0.0f, 0.0f, pitch);	qYaw.createFromAngle (0.0f, 1.0f, 0.0f, yaw);		rotation = qYaw * qPitch;}


Thank you again, jyk. Now the camera works just as intended.

[Edited by - Rakshasa on March 12, 2007 2:20:25 AM]
Doesn't matter how much you lose as long as you make sure the winner loses enough blood.

This topic is closed to new replies.

Advertisement