//== CODE ======================================================
//======== based on Lesson 01 ==================================
//I call, in DrawGLScene():
//---
// c is the CCamera class below
if (keys[VK_NUMPAD8])
c.Rotate(1, 0, 0, -0.02);
if (keys[VK_NUMPAD2])
c.Rotate(1, 0, 0, 0.02);
if (keys[VK_NUMPAD1])
c.Rotate(0, 1, 0, 0.02);
if (keys[VK_NUMPAD3])
c.Rotate(0, 1, 0, -0.02);
if (keys[VK_NUMPAD4])
c.Rotate(0, 0, 1, 0.02);
if (keys[VK_NUMPAD6])
c.Rotate(0, 0, 1, -0.02);
if (keys[VK_ADD])
c.Translate(0, 0, -0.1);
if (keys[VK_SUBTRACT])
c.Translate(0, 0, 0.1);
// ...
c.Apply()
//---
//And the related definitions:
//---
// CCamera.h
// Header file for CCamera.cpp
#ifndef CCAMERA_H
#define CCAMERA_H
#include "CVector3.h"
#include "CQuat.h"
class CCamera {
private:
CQuaternion m_q; // Rotation
CVector3 m_pos; // Position
CVector3 m_ia, m_ja, m_ka; // Unit Axes
static const CVector3 I_AXIS, J_AXIS, K_AXIS;
static const double PI;
inline double RadToDeg(double) const;
public:
CCamera(); // Constructor
// Transformations
void Rotate(double, double, double, double); // Rotate about a vector
void Translate(double, double, double, bool = false); // Translate orthogonally
// Effect changes
void Apply() const; // Apply changes
void LookAt(double, double, double) const; // Look at a point
};
inline double CCamera::RadToDeg(double angle) const
{
return angle * 180 / PI;
}
#endif // CCAMERA_H
-----------------------------------------
// CCamera.cpp
// Camera control in OpenGL
#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <math.h>
#include "CVector3.h"
#include "CQuat.h"
#include "CCamera.h"
const CVector3 CCamera::I_AXIS(1, 0, 0);
const CVector3 CCamera::J_AXIS(0, 1, 0);
const CVector3 CCamera::K_AXIS(0, 0, 1);
const double CCamera::PI = 3.141592653589793238462643383279502884197;
CCamera::CCamera()
{
m_q = CQuaternion(1, 0, 0, 0);
m_pos = CVector3(0, 0, 0);
m_ia = I_AXIS;
m_ja = J_AXIS;
m_ka = K_AXIS;
}
void CCamera::Rotate(double i, double j, double k, double angle)
{
m_q = m_q * CQuaternion(CVector3(i, j, k), angle);
m_ia = m_q.Rotate(I_AXIS);
m_ja = m_q.Rotate(J_AXIS);
m_ka = m_q.Rotate(K_AXIS);
}
void CCamera::Translate(double i, double j, double k, bool global)
{
if (global)
m_pos = m_pos + CVector3(i, j, k);
else
m_pos = m_pos + m_ia * i + m_ja * j + m_ka * k;
}
void CCamera::Apply() const
{
double dSinHalf = sqrt(1 - (m_q.s) * (m_q.s));
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotated(RadToDeg(-acos(m_q.s)) * 2, m_q.i / dSinHalf, m_q.j / dSinHalf, m_q.k / dSinHalf);
glTranslated(-m_pos.i, -m_pos.j, -m_pos.k);
}
void CCamera::LookAt(double i, double j, double k) const
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(m_pos.i, m_pos.j, m_pos.k, i, j, k, m_ja.i, m_ja.j, m_ja.k);
}
---------------------------------------
/********************************
CVector3 and CQuaternion are just
basic 3d vectors and quaternions
********************************/
// CVector3.h
// Header file for CVector3.cpp
#ifndef CVECTOR3_H
#define CVECTOR3_H
class CVector3
{
public:
double i, j, k; // Components
CVector3(); // Zero Vector
CVector3(double, double, double); // Vector
const CVector3 operator + (const CVector3&) const; // Addition
const CVector3 operator - (const CVector3&) const; // Subtraction
const double operator * (const CVector3&) const; // Dot product
const CVector3 operator % (const CVector3&) const; // Cross product
const CVector3 operator * (const double&) const; // Scalar Product
const CVector3 operator / (const double&) const; // Scalar Division
const double Norm() const; // Norm
const CVector3 Unit() const; // Unit Vector
};
#endif // CVECTOR3_H
-----------------------------------------
// CVector3.cpp
// Three-dimensional vector
#include <math.h>
#include "CVector3.h"
CVector3::CVector3()
{
i = j = k = 0.0;
}
CVector3::CVector3(double i, double j, double k)
{
this->i = i;
this->j = j;
this->k = k;
}
const CVector3 CVector3::operator + (const CVector3 &v) const
{
return CVector3(i + v.i, j + v.j, k + v.k);
}
const CVector3 CVector3::operator - (const CVector3 &v) const
{
return CVector3(i - v.i, j - v.j, k - v.k);
}
const double CVector3::operator * (const CVector3 &v) const
{
return i * v.i + j * v.j + k * v.k;
}
const CVector3 CVector3::operator % (const CVector3 &v) const
{
return CVector3(j * v.k - k * v.j, k * v.i - i * v.k, i * v.j - j * v.i);
}
const CVector3 CVector3::operator * (const double &d) const
{
return CVector3(i * d, j * d, k * d);
}
const CVector3 CVector3::operator / (const double &d) const
{
return CVector3(i / d, j / d, k / d);
}
const double CVector3::Norm() const
{
return sqrt(i * i + j * j + k * k);
}
const CVector3 CVector3::Unit() const
{
return *this / this->Norm();
}
-----------------------------------------
// CQuat.h
// Header file for CQuat.cpp
#ifndef CQUAT_H
#define CQUAT_H
#include "CVector3.h"
class CQuaternion
{
public:
double s, i, j, k; // Components
CQuaternion(); // Multiplicative Identity
CQuaternion(double, double, double, double); // Direct initialisation
CQuaternion(double, CVector3); // Initialise with scalar and vector
CQuaternion(CVector3, double); // Rotation about unit vector
const CQuaternion operator + (const CQuaternion&) const; // Addition
const CQuaternion operator - (const CQuaternion&) const; // Subtraction
const CQuaternion operator * (const CQuaternion&) const; // Multiplication
const CQuaternion operator / (const CQuaternion&) const; // Division
const CQuaternion operator * (const double&) const; // Scalar Multiplication
const CQuaternion operator / (const double&) const; // Scalar Division
const double Norm() const; // Norm
const CQuaternion Conjugate() const; // Conjugate
const CQuaternion Inverse() const; // Inverse
const CVector3 Rotate(const CVector3) const; // Rotate a point
};
#endif // CQUAT_H
-----------------------------------------
// CQuat.cpp
// A quaternion
#include <math.h>
#include "CVector3.h"
#include "CQuat.h"
CQuaternion::CQuaternion()
{
s = 1;
i = j = k = 0;
}
CQuaternion::CQuaternion(double s, double i, double j, double k)
{
this->s = s;
this->i = i;
this->j = j;
this->k = k;
}
CQuaternion::CQuaternion(double s, CVector3 v)
{
this->s = s;
i = v.i;
j = v.j;
k = v.k;
}
CQuaternion::CQuaternion(CVector3 v, double angle)
{
CVector3 uv = v.Unit();
double dSinHalf = (double) sin(angle / 2);
s = (double) cos(angle / 2);
i = uv.i * dSinHalf;
j = uv.j * dSinHalf;
k = uv.k * dSinHalf;
}
const CQuaternion CQuaternion::operator + (const CQuaternion &q) const
{
return CQuaternion(s + q.s, i + q.i, j + q.j, k + q.k);
}
const CQuaternion CQuaternion::operator - (const CQuaternion &q) const
{
return CQuaternion(s - q.s, i - q.i, j - q.j, k - q.k);
}
const CQuaternion CQuaternion::operator * (const CQuaternion &q) const
{
return CQuaternion(
s * q.s - i * q.i - j * q.j - k * q.k,
s * q.i + i * q.s + j * q.k - k * q.j,
s * q.j - i * q.k + j * q.s + k * q.i,
s * q.k + i * q.j - j * q.i + k * q.s);
}
const CQuaternion CQuaternion::operator / (const CQuaternion &q) const
{
return (*this) * q.Inverse();
}
const CQuaternion CQuaternion::operator * (const double &d) const
{
return CQuaternion(s * d, i * d, j * d, k * d);
}
const CQuaternion CQuaternion::operator / (const double &d) const
{
return CQuaternion(s / d, i / d, j / d, k / d);
}
const double CQuaternion::Norm() const
{
return (double) sqrt(s * s + i * i + j * j + k * k);
}
const CQuaternion CQuaternion::Inverse() const
{
return this->Conjugate() / (this->Norm() * this->Norm());
}
const CQuaternion CQuaternion::Conjugate() const
{
return CQuaternion(s, -i, -j, -k);
}
const CVector3 CQuaternion::Rotate(const CVector3 pt) const
{
CQuaternion q = (*this) * CQuaternion(0, pt) * this->Conjugate();
return CVector3(q.i, q.j, q.k);
}
===========================================================
Sorry if I am wordy but the code is long
Thanks in advance
[edited by - singulab on January 7, 2004 5:11:50 AM]
[edited by - singulab on January 7, 2004 9:20:42 AM]
Desperate Quaternions
I have recently written a quaternion implementation due to the fact that the tutorials here do not allow rotation about any vector. I don't know if it indeed works because there is a warning that says I should not multiply quats with different coordinate systems but that, I think, is precisely what I did but it seemed to run well! I have the code below; could anyone please evaluate?
By the way, I would like to ask if there is any good camera classes available? I would very much like to know about it before I start my first project.
Hey I don''t have time to look at this now, but when posing code its nice if you put it between some [*source] [*/source] (dont use the *''s.
Following an afterthought this is proposed:
Please kindly evaluate it and tell me which one is correct.
Thanks
// global: true if rotating in global coordinate systemvoid CCamera::Rotate(double i, double j, double k, double angle, bool global){ if (global) m_q = m_q * CQuaternion(CVector3(i, j, k), angle); else m_q = m_q * CQuaternion(m_ia * i + m_ja * j + m_ka * k, angle); m_ia = m_q.Rotate(I_AXIS); m_ja = m_q.Rotate(J_AXIS); m_ka = m_q.Rotate(K_AXIS);}
Please kindly evaluate it and tell me which one is correct.
Thanks
One thing you are missing in your multiply code is the normalisation of the quaternion. You need to make sure that you keep the quaternion normalised at all times otherwise the quaternion is not representing a rotation(you are allowing an extra Degree of freedom which is eliminated by keeping the quaternion as a unit quaternion).
James
James
Actually my quat is clever enough to convert all vectors to unit ones . cf.
CQuaternion::CQuaternion(CVector3 v, double angle){ CVector3 uv = v.Unit(); double dSinHalf = (double) sin(angle / 2); s = (double) cos(angle / 2); i = uv.i * dSinHalf; j = uv.j * dSinHalf; k = uv.k * dSinHalf;}
quote:Original post by singulab
Actually my quat is clever enough to convert all vectors to unit ones . cf.
CQuaternion::CQuaternion(CVector3 v, double angle){ CVector3 uv = v.Unit(); double dSinHalf = (double) sin(angle / 2); s = (double) cos(angle / 2); i = uv.i * dSinHalf; j = uv.j * dSinHalf; k = uv.k * dSinHalf;}
But that''s not the constructor you are using to create the result of the product is it? I would suggest that you modify the constructor that taks 4 doubles to normalize the result i.e. divide each of the components by the sqrt of the sum of the squares of the components (your Norm() function). I think you''ll find that this is where the quaternions are becoming denormalised and hence not representing the rotations you''d expect.
jamessharpe,
I hope I understand that you mean I should have unit quaternions instead of unit vectors? See below; the problem seems to persist.
I have another point to make. If you have a flight simulator (I have only one by the name of Orbiter), the result of using global is like what you would normally expect when flying, but I expect it to be like rotating always w.r.t. the three global axes. If global is false then after you pitch a bit then bank, the camera will trace out a mystical curve and keeps rolling. Don't know what caused it; high school math does not include quaternions.
It is hard to impress on the effect unless with an executable. Maybe you can try http://personal.nbnet.nb.ca/daveg/opengl/quatdemo/index.html, I believe the effect is similar to the rotations without quats - very unsmooth with pauses and rolls, not at all like an aircraft.
Please refer to:
singulab
[edited by - singulab on January 10, 2004 7:59:30 AM]
I hope I understand that you mean I should have unit quaternions instead of unit vectors? See below; the problem seems to persist.
I have another point to make. If you have a flight simulator (I have only one by the name of Orbiter), the result of using global is like what you would normally expect when flying, but I expect it to be like rotating always w.r.t. the three global axes. If global is false then after you pitch a bit then bank, the camera will trace out a mystical curve and keeps rolling. Don't know what caused it; high school math does not include quaternions.
It is hard to impress on the effect unless with an executable. Maybe you can try http://personal.nbnet.nb.ca/daveg/opengl/quatdemo/index.html, I believe the effect is similar to the rotations without quats - very unsmooth with pauses and rolls, not at all like an aircraft.
Please refer to:
CQuaternion::CQuaternion(CVector3 v, double angle){ CVector3 uv = v.Unit(); double dSinHalf = (double) sin(angle / 2); s = (double) cos(angle / 2); i = uv.i * dSinHalf; j = uv.j * dSinHalf; k = uv.k * dSinHalf; *this = this->Unit();}const CQuaternion CQuaternion::Unit() const{ return *this / this->Norm();}void CCamera::Rotate(double i, double j, double k, double angle, bool global){ if (global) m_q = m_q * CQuaternion(CVector3(i, j, k), angle); else m_q = m_q * CQuaternion(m_ia * i + m_ja * j + m_ka * k, angle); m_ia = m_q.Rotate(I_AXIS); m_ja = m_q.Rotate(J_AXIS); m_ka = m_q.Rotate(K_AXIS);}
singulab
[edited by - singulab on January 10, 2004 7:59:30 AM]
Actually, should the code be like
It is just a wild guess that doesn''t work but something similar may work.
void CCamera::Rotate(double i, double j, double k, double angle, bool global){ if (global) m_q = m_q * CQuaternion(m_ia * i + m_ja * j + m_ka * k, angle); else { CVector3 v(i, j, k); // rotate the internal vector to global representation // IMPORTANT: I don''t know how to do this. The only method I have // is to solve 3 simultaneous equations, which I cannot handle. v = m_q.Conjugate().Rotate(v); // Maybe it should be // v = m_q.Inverse().Rotate(v); m_q = m_q * CQuaternion(v, angle); } m_ia = m_q.Rotate(I_AXIS); m_ja = m_q.Rotate(J_AXIS); m_ka = m_q.Rotate(K_AXIS);}
It is just a wild guess that doesn''t work but something similar may work.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement