Hello all
I am having trouble using my quaternion-based camera.
A few days ago I searched through the forum''s archive for the quaternion
topics and after i read all of them, i decided it will be best if i took
a quaternion-math-class from NewDeal (he is/was a member of Nehe''s forum)
and implement my camera over it. Everything worked like a charm...
My camera would yaw, pitch and roll, it would move forward and backward.
The problem i am reffering to appear into my eyes after i implemented
mouse look and i started to move the camera in complete circles. My entire
world appears to be slowly rolling into view altough i am not pressing any
roll button and the rotation around Z axis is 0 !
This is a strange one ... I double-checked my calculations and everything
seems to be OK. I am just hoping that there is a problem in Quaternion-math
class and maybe one of you guys can spot it out. I am going crazy with this

Please help me if you can...
Moromete
PS. I am posting here the source of quaternion-class and the source of my
camera class
#ifndef QUATERNION_H
#define QUATERNION_H
#include <iostream.h>
#include <stdio.h>
#include <math.h>
using namespace std;
class Quaternion{
public:
float w,x,y,z;
float qLength;
Quaternion(float newW, float newX, float newY, float newZ);
Quaternion();
void Normalize();
void toAxisAngle(float *result);
void MultQuat(Quaternion *q);
void EulerToQuat(float aX, float aY, float aZ);
void LoadIdentity();
};
//--------------------------------------------------------------
Quaternion::Quaternion(float newW, float newX, float newY, float newZ){
this->x = newX;
this->y = newY;
this->z = newZ;
this->w = newW;
this->qLength = (float)sqrt(this->x*this->x + this->y*this->y + this->z*this->z + this->w*this->w);
}
Quaternion::Quaternion(){
this->x = 0.0; // create mult identity quaternion
this->y = 0.0;
this->z = 0.0;
this->w = 1.0;
this->qLength = 1.0;
}
void Quaternion::Normalize(){
float l;
l = (float)1.0/this->qLength;
this->x *= l; // mult by inverse length to normalize
this->y *= l;
this->z *= l;
this->w *= l;
this->qLength = 1.0f;
}
void Quaternion::toAxisAngle(float *result){
float AxisAngle[4];
float scale;
scale = this->x*this->x + this->y*this->y + this->z*this->z;
if (scale != 0) {
AxisAngle[0] = (float)(2 * acos(this->w)); // angle to rotate
AxisAngle[1] = this->x / scale; // next 3 lines is x,y,z of vector to rotate about
AxisAngle[2] = this->y / scale;
AxisAngle[3] = this->z / scale;
result[0] = AxisAngle[0];
result[1] = AxisAngle[1];
result[2] = AxisAngle[2];
result[3] = AxisAngle[3];
} else {
result[0] = 0;
result[1] = 1;
result[2] = 0;
result[3] = 0;
}
}
void Quaternion::MultQuat(Quaternion *q){
float tempx, tempy, tempz, tempw;
tempw = this->w*q->w - this->x*q->x - this->y*q->y - this->z*q->z;
tempx = this->w*q->x + this->x*q->w + this->y*q->z - this->z*q->y;
tempy = this->w*q->y + this->y*q->w + this->z*q->x - this->x*q->z;
tempz = this->w*q->z + this->z*q->w + this->x*q->y - this->y*q->x;
this->x = tempx;
this->y = tempy;
this->z = tempz;
this->w = tempw;
this->qLength = (float)sqrt(this->x*this->x + this->y*this->y + this->z*this->z + this->w*this->w);
}
void Quaternion::EulerToQuat(float aX, float aY, float aZ){
this->y = 0.0; //lets make sure that quat is initialized
this->z = 0.0;
Quaternion* qY = new Quaternion();
Quaternion* qZ = new Quaternion();
this->x = sin(aX/2);
this->w = cos(aX/2);
qY->y = sin(aY/2);
qY->w = cos(aY/2);
qZ->z = sin(aZ/2);
qZ->w = cos(aZ/2);
this->MultQuat(qY);
this->MultQuat(qZ);
this->qLength = (float)sqrt(this->x*this->x + this->y*this->y + this->z*this->z + this->w*this->w);
}
void Quaternion::LoadIdentity(){
this->w = 1.0;
this->x = 0.0;
this->y = 0.0;
this->z = 0.0;
}
#endif
#ifndef CAMERA_H
#define CAMERA_H
#include <iostream.h>
#include <stdio.h>
#include "quaternion.h"
using namespace std;
class CCamera {
float speed;
float X, Y, Z;
float dirX, dirY, dirZ;
float upX, upY, upZ;
float leftX, leftY, leftZ;
float posX, posY, posZ;
float result[4];
Quaternion Qold, Qtemp;
public:
void Yaw(float yawval);
void RollLeft();
void RollRight();
void Pitch(float pitchval);
void RotateCamera();
void Forward();
void Backward();
void MousePosition(int widthX, int heightY);
void Reset();
CCamera();
~CCamera();
};
//---------------------------------------------------------
CCamera::CCamera() {
Reset();
posX = 0.0f;
posY = 0.0f;
posZ = 0.0f;
};
void CCamera::Reset() {
X = 0.0f;
Y = 0.0f;
Z = 0.0f;
}
CCamera::~CCamera() {
};
void CCamera::Yaw(float yawval) {
Y = yawval;
}
void CCamera::RollLeft() {
Z = 0.017453293f;
}
void CCamera::RollRight() {
Z = -0.017453293f;
}
void CCamera:itch(float pitchval) {
X = pitchval;
}
void CCamera::Forward() {
speed = 0.01f;
}
void CCamera::Backward() {
speed = -0.01f;
}
void CCamera::RotateCamera() {
Qtemp.LoadIdentity();
Qtemp.EulerToQuat(X, Y, Z);
Qtemp.Normalize();
Qtemp.MultQuat(&Qold);
Qtemp.toAxisAngle(result);
Qold.x = Qtemp.x;
Qold.y = Qtemp.y;
Qold.z = Qtemp.z;
Qold.w = Qtemp.w;
Qold.qLength = Qtemp.qLength;
// Am inmultit noua orientare cu vechea si am salvat rezultatul
glRotatef((result[0]*180)/3.14159265359, result[1], result[2], result[3]);
// Acum am rotit si camera (lumea in jurul camerei)
dirX = 2.0 * (Qold.x * Qold.z - Qold.w * Qold.y);
dirY = 2.0 * (Qold.y * Qold.z + Qold.w * Qold.x);
dirZ = 1.0 - 2.0 * (Qold.x * Qold.x + Qold.y * Qold.y);
upX = 2 * (Qold.x * Qold.y - Qold.w * Qold.z);
upY = 1 - 2 * (Qold.x * Qold.x + Qold.z * Qold.z);
upZ = 2 * (Qold.y * Qold.z + Qold.w * Qold.x);
leftX = 1 - 2 * (Qold.y * Qold.y + Qold.z * Qold.z);
leftY = 2 * (Qold.x * Qold.y + Qold.w * Qold.z);
leftZ = 2 * (Qold.x * Qold.z - Qold.w * Qold.y);
// In dir... am vectorul orientare extras din Quaternion
// In up... am orientarea vectorului "sus"
// In left... am orientarea vectorului "stanga"
posX += dirX * speed;
posY += dirY * speed;
posZ += dirZ * speed;
glTranslatef(posX, posY, posZ);
speed = 0.0f;
result[0] = 0;
result[1] = 0;
result[2] = 0;
result[3] = 0;
Qold.Normalize();
Reset();
};
void CCamera::MousePosition(int widthX, int heightY) {
POINT mousePos;
int middleX = widthX >> 1;
int middleY = heightY >> 1;
GetCursorPos(&mousePos);
if( (mousePos.x == middleX) && (mousePos.y == middleY) ) return;
SetCursorPos(middleX, middleY);
Yaw (-(float)( (middleX - mousePos.x) ) / 500.0f);
Pitch (-(float)( (middleY - mousePos.y) ) / 500.0f);
};
#endif