# OpenGL camera using quaternion

This topic is 4860 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm trying to implement a camera class in OpenGL. I'm not sure if it's rounding errors or I implemented quaternions wrong. Here are some screenshots of what happens. I'm changing the rotation in the x axis by 0.5 degrees. The first pic is where I start. In the second pic I rotate by 0.5 degrees in the x axis and change the view vector. In the third pic I go rotate back 0.5 degrees in the x axis and change the view vector. I use my implementation of quaternions to rotate the view vector. As you can see on the top left of the screen, I don't get the same values back from the first pic. Heres some relevant code: quaternion.h
#ifndef GQUATERNION_H
#define GQUATERNION_H

#include "GVector.h"

//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
class GQuaternion {
public:
GQuaternion() { Init(0.0f, GVector(0.0f, 0.0f, 0.0f)); }
GQuaternion(float aW, GVector aV) { Init(aW, aV); }
GQuaternion(float aW, float aX, float aY, float aZ) { Init(aW, aX, aY, aZ); }
~GQuaternion();
float Length() const { return sqrt(w()*w() + x()*x() + y()*y() + z()*z()); }
GQuaternion Normalize() { float l = Length(); return GQuaternion(w()/l, x()/l, y()/l, z()/l); }
GQuaternion Conjugate() { return GQuaternion(mW, -mV); }
GQuaternion& operator*=(const GQuaternion &mQ);
GQuaternion operator*(const GQuaternion &mQ) { return GQuaternion(*this) *= mQ; }
static GQuaternion FromAxisAngle(float aAngle, GVector aAxis);
static void ToAxisAngle(float *aAngle, float aVector);
float w() const { return mW; }
float x() const { return mV.x(); }
float y() const { return mV.y(); }
float z() const { return mV.z(); }
void SetW(float aW) { mW = aW; }
void SetX(float aX) { mV.v[_X] = aX; }
void SetY(float aY) { mV.v[_Y] = aY; }
void SetZ(float aZ) { mV.v[_Z] = aZ; }
//void RotateX(float aAngle, const GVector &mV);
void Rotate(float aAngle, const GVector &mV);
protected:
void Init(float aW, GVector aV) { mW = aW; mV = aV; }
void Init(float aW, float aX, float aY, float aZ) { mW = aW; mV.Set(aX, aY, aZ); }
protected:
float mW;
GVector mV;
};
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------

#endif


quaternion.cpp
#include "defines.h"
#include "GQuaternion.h"

//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
GQuaternion::~GQuaternion() {
}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
GQuaternion& GQuaternion::operator*=(const GQuaternion &aQ) {
mV.v[_X] = w()*aQ.x() + x()*aQ.w() + y()*aQ.z() - z()*aQ.y();
mV.v[_Y] = w()*aQ.y() - x()*aQ.z() + y()*aQ.w() + z()*aQ.x();
mV.v[_Z] = w()*aQ.z() + x()*aQ.y() - y()*aQ.x() + z()*aQ.w();
mW = w()*aQ.w() - x()*aQ.x() - y()*aQ.y() - z()*aQ.z();
return *this;
}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
GQuaternion GQuaternion::FromAxisAngle(float aAngle, GVector aAxis) {
return GQuaternion(
COS(aAngle/2.0f),
aAxis.x() * SIN(aAngle/2.0f),
aAxis.y() * SIN(aAngle/2.0f),
aAxis.z() * SIN(aAngle/2.0f)
);
}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
void GQuaternion::ToAxisAngle(float *aAngle, float aVector) {

}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
void GQuaternion::Rotate(float aAngle, const GVector &aVector) {
}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------


camera.h
#ifndef GCAMERA_H
#define GCAMERA_H

#include "GPoint.h"
#include "GVector.h"

class GCamera {
public:
GCamera();
~GCamera();

void Run();
void MoveForward();
void MoveBackward();
float GetPosX() { return mPosition.x(); }
float GetPosY() { return mPosition.y(); }
float GetPosZ() { return mPosition.z(); }
float GetAngleX() { return mAngleX; }
float GetAngleY() { return mAngleY; }
float GetAngleZ() { return mAngleZ; }

float GetViewX() { return mView.x(); }
float GetViewY() { return mView.y(); }
float GetViewZ() { return mView.z(); }
//float GetDirX() { return mDirection.x(); }
//float GetDirY() { return mDirection.y(); }
//float GetDirZ() { return mDirection.z(); }

void RotateCamera(float aAngle, GVector aAxis);
void RotateCamera();

void Reset() { mPosition.Set(0.0f, 0.0f, 0.0f); mView.Set(0.0f, 0.0f, -1.0f); mAngleX = mAngleY = mAngleZ = 0.0f; }

protected:
GVector mPosition;
GVector mView;
GVector mUp;
GVector mRight;
float mAngleX;
float mAngleY;
float mAngleZ;
float mAngleDX;
float mAngleDY;
float mAngleDZ;
float mVelocity;
};

#endif


camera.cpp
//#include <gl/gl.h>
//#include <gl/glu.h>
//
#include "GQuaternion.h"
#include "GCamera.h"

GCamera::GCamera() {

mAngleDX = mAngleX = 0.0f;
mAngleDY = mAngleY = 0.0f;
mAngleDZ = mAngleZ = 0.0f;
mVelocity = 0.0f;
mPosition.Set(0.0f, -10.0f,0.0f);
mView.Set(0.0f, 0.0f, -1.0f);
mUp.Set(0.0f, 1.0f, 0.0f);
mRight.Set(1.0f, 0.0f, 0.0f);

mView.RotateX(mAngleX);
}

GCamera::~GCamera() {
}

void GCamera::Run() {
}

void GCamera::MoveForward() {
mPosition -= mView;
}

void GCamera::MoveBackward() {
mPosition += mView;
}

mAngleX += aAngle;
if(mAngleX > 360.0f) mAngleX -= 360.0f;
if(mAngleX < 0.0f) mAngleX += 360.0f;
mAngleDX = aAngle;
}
mAngleY += aAngle;
if(mAngleY > 360.0f) mAngleY -= 360.0f;
if(mAngleY < 0.0f) mAngleY += 360.0f;
mAngleDY = aAngle;
}
mAngleZ += aAngle;
if(mAngleZ > 360.0f) mAngleZ -= 360.0f;
if(mAngleZ < 0.0f) mAngleZ += 360.0f;
mAngleDZ = aAngle;
}

void GCamera::RotateCamera() {
if(mAngleDX != 0)
RotateCamera(mAngleDX, mRight);
mAngleDX = 0;
}

void GCamera::RotateCamera(float aAngle, GVector aAxis) {
//if(aAngle == 0.0f) return;

GQuaternion temp;
GQuaternion view;

aAxis.Normalize();

temp.SetX(aAxis.x() * SIN(aAngle/2.0));
temp.SetY(aAxis.y() * SIN(aAngle/2.0));
temp.SetZ(aAxis.z() * SIN(aAngle/2.0));
temp.SetW(COS(aAngle/2.0));
temp.Normalize();

view.SetX(mView.x());
view.SetY(mView.y());
view.SetZ(mView.z());
view.SetW(0.0);
view.Normalize();

GQuaternion result = (temp.Conjugate()) * (temp * view);
result.Normalize();
mView.Set(result.x(), result.y(), result.z());
mView.Normalize();
//mView.Normalize();
//mView.Normalize();
}


somewhere in my main loop i have this
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(mCamera->GetAngleX(), 1.0f, 0.0f, 0.0f);
glRotatef(mCamera->GetAngleY(), 0.0f, 1.0f, 0.0f);
glRotatef(mCamera->GetAngleZ(), 0.0f, 0.0f, 1.0f);
glTranslatef(mCamera->GetPosX(), mCamera->GetPosY(), mCamera->GetPosZ());
mMap->Render();
glPopMatrix();
gGraphics->Enable2D();
char buf[300];
sprintf(buf, "position => (%f, %f, %f)", mCamera->GetPosX(), mCamera->GetPosY(), mCamera->GetPosZ());
gGraphics->OutString(10, gHeight-20, buf);
sprintf(buf, "angle    => (%f, %f, %f)", mCamera->GetAngleX(), mCamera->GetAngleY(), mCamera->GetAngleZ());
gGraphics->OutString(10, gHeight-40, buf);
sprintf(buf, "view => (%f, %f, %f)", mCamera->GetViewX(), mCamera->GetViewY(), mCamera->GetViewZ());
gGraphics->OutString(10, gHeight-60, buf);
glRasterPos2i(0,0);
glDrawPixels(gGame->GetBitmap(mBitmap)->GetWidth(), gGame->GetBitmap(mBitmap)->GetHeight(), GL_RGB, GL_UNSIGNED_BYTE, gGame->GetBitmap(mBitmap)->mBitmapData);
gGraphics->Disable2D();

// input
if(gInput->IsKeyPressed(VK_ESCAPE)) gGame->Exit();

if(gInput->IsKeyPressed('W'))
if(gInput->IsKeyPressed('S'))

if(gInput->IsKeyPressed('R')) {
mCamera->Reset();
}
gInput->ResetMouseChange();
mCamera->RotateCamera();

if(gInput->IsKeyPressed(VK_UP))
mCamera->MoveForward();

if(gInput->IsKeyPressed(VK_DOWN))
mCamera->MoveBackward();


Am I heading in the wrong direction and getting this quaternion thing all wrong or am I just missing something tiny?

##### Share on other sites
Didn't look at your code, but these look like normal rounding errors to me. Unfortunately, floating point operations do not have an infinite precision. Is it important for your application to have a higher precision than this?

Tom

##### Share on other sites
Not really, but the errors accumulate and after a while the view vector is completely off and I'm no longer heading in the direction I am supposed to be facing.

##### Share on other sites
Quote:
 Original post by gcmonkNot really, but the errors accumulate and after a while the view vector is completely off and I'm no longer heading in the direction I am supposed to be facing.

If your camera is controlled by the user, I think it's not really a problem. The user will get visual feedback on the rotation and will never be able to see the difference caused by the rounding errors.
If your camera is following some predefined path, then there may be a problem. However, this only the case if your rotations and positions are defined using relative values. Using absolute values makes it easy to remove any errors introduced by the interpolation...

Tom

Edit: spelling :)

[Edited by - dimebolt on July 25, 2005 10:45:29 AM]

1. 1
2. 2
Rutin
19
3. 3
4. 4
5. 5

• 9
• 9
• 9
• 14
• 12
• ### Forum Statistics

• Total Topics
633294
• Total Posts
3011242
• ### Who's Online (See full list)

There are no registered users currently online

×