Archived

This topic is now archived and is closed to further replies.

brekehan

quaternion based camera

Recommended Posts

I have a working matrix based camera, but I am trying to use quaternions since they are more efficient. Currently there is a phenomena where if i rotate upwards, than left, than downwards, then right, repeatedly, the camera seems to unexpectly start rolling on the z axis each time I wonder if anyone has source for a 6DOF quaternion based camera I can look at? All examples on the net seem to be FPS type that won't let you rotate 360 degrees up and down. and or alternativly maybe someone can find the problem in my source:
#ifndef CAMERA_H
#define CAMERA_H
//-----------------------------------------------------------------------------------------------

// camera.h

//

// a quaternion based camera

//

// Christopher Pisz

// 03/14/04

//-----------------------------------------------------------------------------------------------

#include <d3dx9.h>

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

	D3DXMATRIX * Update();			         	            // Updates the camera position

	void Rotate(D3DXVECTOR3& axis, float angle);        	// Rotates the camera

	void Translate(float distance, D3DXVECTOR3& direction); // Translates the camera position along a 6DOF vector


private:
	D3DXVECTOR3    m_position;                 // Position of camera within world space

	D3DXQUATERNION m_rotation;				   // Rotation quaternion

	D3DXMATRIX     m_view;                     // The view matrix

};

#endif // CAMERA_H


//-----------------------------------------------------------------------------------------------

// camera.cpp

//

// a quaternion based camera

//

// Christopher Pisz

// 03/14/04

//-----------------------------------------------------------------------------------------------

#include "camera.h"
#include <stdio.h>

Camera::Camera()
{
	m_position = D3DXVECTOR3(0.0f, 0.0f, -5.0f);
	D3DXQuaternionIdentity(&m_rotation);					   
	D3DXMatrixIdentity(&m_view);                     
}
	
Camera::~Camera()
{
}

//-----------------------------------------------------------------------------------------------

void Camera::Rotate(D3DXVECTOR3& axis, float angle)
{
	D3DXQUATERNION rotation_new;            // The new rotation


	// Build a new rotation quaternion

	D3DXQuaternionIdentity(&rotation_new);
	D3DXQuaternionRotationAxis(&rotation_new, &axis, angle);

	// Add the effects of the new rotation to our old rotation

	D3DXQuaternionMultiply(&m_rotation, &rotation_new, &m_rotation);

	Update();
}

//-----------------------------------------------------------------------------------------------

void Camera::Translate(float distance, D3DXVECTOR3& direction)
{
    D3DXVECTOR3 axis_x, axis_y, axis_z, amount;

	D3DXVec3Normalize(&direction, &direction);
	amount = direction * distance;

	// Move in the X direction

	axis_x.x = m_view._11; 
    axis_x.y = m_view._21;
    axis_x.z = m_view._31;

	axis_x  *= amount.x;
    
	m_position.x += axis_x.x;
    m_position.y += axis_x.y;
    m_position.z += axis_x.z;

	// Move in the Y direction

	axis_y.x = m_view._12; 
    axis_y.y = m_view._22;
    axis_y.z = m_view._32;

	axis_y  *= amount.y;
    
	m_position.x += axis_y.x;
    m_position.y += axis_y.y;
    m_position.z += axis_y.z;

	// Move in the Z direction

	axis_z.x = m_view._13; 
    axis_z.y = m_view._23;
    axis_z.z = m_view._33;

	axis_z  *= amount.z;
    
	m_position.x += axis_z.x;
    m_position.y += axis_z.y;
    m_position.z += axis_z.z;

	Update();
}

//-----------------------------------------------------------------------------------------------

D3DXMATRIX * Camera::Update()
{
	// Build a new view matrix	

	D3DXMATRIX translation;
	D3DXMatrixTranslation(&translation, -m_position.x, -m_position.y, -m_position.z);

	D3DXMATRIX rotation;
	D3DXMatrixRotationQuaternion(&rotation, &D3DXQUATERNION(-m_rotation.x, -m_rotation.y, -m_rotation.z, m_rotation.w));

	D3DXMatrixMultiply(&m_view, &translation, &rotation);

	return &m_view;
}

[edited by - brekehan on March 29, 2004 12:37:02 AM]

Share this post


Link to post
Share on other sites
Here is attempt #7 from tutorials on the net. This one is from the "ultimate game programming" site and I can''t get it to work either. I so wish people would stop making fps cameras that use mice! not one 6dof space sim type camera out there

Anyway,the problem with this one is the up and down rotations reverse themselves depending what side of the world''s origin you are on and the "roll" doesn''t work at all.

Here is the code:

#ifndef CAMERA_H
#define CAMERA_H

#include <cmath>
#include <d3dx9.h>

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

void SetCamera(D3DXVECTOR3 position, D3DXVECTOR3 lookat, D3DXVECTOR3 up);
void MoveCamera(float speed);
void Strafe(float speed);
void Rotate(float angle, D3DXVECTOR3 axis);

D3DXMATRIX Update();

private:
D3DXVECTOR3 m_position, // Camera position.

m_lookat, // Look at position.

m_up, // Up direction.

m_strafe; // Strafe direction.


float currentRotationAngle; // Keeps us from going too far up or down.



};

#endif CAMERA_H


#include "camera.h"

Camera::Camera()
{
// Initialize variables

m_position = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
m_lookat = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
m_up = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
m_strafe = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
}

Camera::~Camera()
{
}

void Camera::SetCamera(D3DXVECTOR3 position, D3DXVECTOR3 lookat, D3DXVECTOR3 up)
{
// Here we set the camera to the values sent in to us. This is mostly used to set up a

// default position.

m_position = position;
m_lookat = lookat;
m_up = up;
}

void Camera::MoveCamera(float speed)
{
D3DXVECTOR3 look_direction(0.0f, 0.0f, 0.0f);

look_direction = m_lookat - m_position;

D3DXVec3Normalize(&look_direction, &look_direction);

// Move the camera on the X and Z axis. Notice I commented out the yPos and yView

// updates. This is because without them we can keep the camera on the ground in

// the simple camera tutorials without having to alter them afterwards.

m_position.x += look_direction.x * speed;
m_position.y += look_direction.y * speed;
m_position.z += look_direction.z * speed;

// Move the view along with the position

m_lookat.x += look_direction.x * speed;
m_lookat.y += look_direction.y * speed;
m_lookat.z += look_direction.z * speed;
}

void Camera::Strafe(float speed)
{
D3DXVECTOR3 direction(0.0f, 0.0f, 0.0f),
cross (0.0f, 0.0f, 0.0f);

// Strafing is just like moving the camera forward and backward. First we will get the

// direction we are looking.

direction = m_lookat - m_position;

// Normalize the direction.

D3DXVec3Normalize(&direction, &direction);

// Now if we were to call UpdateCamera() we will be moving the camera foward or backwards.

// We don''t want that here. We want to strafe. To do so we have to get the cross product

// of our direction and Up direction view. The up was set in SetCamera to be 1 positive

// y. That is because anything positive on the y is considered up. After we get the

// cross product we can save it to the strafe variables so that can be added to the

// camera using UpdateCamera().


// Get the cross product of the direction we are looking and the up direction.

D3DXVec3Cross(&cross, &direction, &m_up);

// Save our strafe (cross product) values in xStrafe, yStrafe, and zStrafe.

m_strafe = cross;

// Then add it to the camera''s position

m_position.x += m_strafe.x * speed;
m_position.y += m_strafe.y * speed;
m_position.z += m_strafe.z * speed;

// Move the view along with the position

m_lookat.x += m_strafe.x * speed;
m_lookat.y += m_strafe.y * speed;
m_lookat.z += m_strafe.z * speed;
}

// angle in radians please

void Camera::Rotate(float angle, D3DXVECTOR3 axis)
{
D3DXQUATERNION rotation,
conjugate,
view,
view_new;

// Normalize the axis

D3DXVec3Normalize(&axis, &axis);

// Create the rotation quaternion based on the axis we are rotating on

D3DXQuaternionRotationAxis(&rotation, &axis, angle);

// Normalize the quaternion

D3DXQuaternionNormalize(&rotation, &rotation);

// Create the view quaternion. This will be the direction of the view and position

view.x = m_lookat.x - m_position.x;
view.y = m_lookat.y - m_position.y;
view.z = m_lookat.z - m_position.z;
view.w = 0;

// Create the resulting quaternion by multiplying the rotation quat by the view quat

// then multiplying that by the conjugate of the rotation quat

D3DXQuaternionConjugate(&conjugate, &rotation);
view_new = (rotation * view) * conjugate;

// Update the view information by adding the position to the resulting quaternion.

m_lookat.x = m_position.x + view_new.x;
m_lookat.y = m_position.y + view_new.y;
m_lookat.z = m_position.z + view_new.z;
}

D3DXMATRIX Camera::Update()
{
// This will be used to set the view ("camera") matrix.

D3DXMATRIX view;

// Set all the values this matrix will need to know (position, look at point, etc).

D3DXMatrixLookAtLH(&view, &m_position, &m_lookat, &m_up);

return view;
}


The entire engine project is zipped and can be downloaded from my ftp site if anyone wants to take a look at the exec to see what I am speaking of. The address is ftp://68.204.11.42

Thanx,
Christopher

Share this post


Link to post
Share on other sites
and another attempt today. I am getting close I guess. All the movements are as desired. All the rotations are consistant and as expected except that it is rotating in world space instead of camera space. I am all out of ideas and the net is out of articles. Please if any of you a a breath of compassion in you take a look at the code at my ftp site and tell me how to fix this thing. End the 2 week nightmare!

the new code is at:

ftp://68.204.11.42

look at demo02

Thank you,
Christopher


#ifndef CAMERA_H
#define CAMERA_H

#include <cmath>
#include <d3dx9.h>

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

void Set(D3DXVECTOR3 position, D3DXVECTOR3 lookat, D3DXVECTOR3 up);
void Move(float distance, D3DXVECTOR3 axis);
void Rotate(float angle, D3DXVECTOR3 axis);

D3DXMATRIX Update();

private:
D3DXVECTOR3 m_position, // Camera position.

m_lookat, // Look at position.

m_up; // Up direction.


D3DXMATRIX m_view; // the view matrix

};

#endif CAMERA_H



#include "camera.h"

Camera::Camera()
{
// Initialize default position

Set(D3DXVECTOR3( 0.0f, 0.0f, -5.0f),
D3DXVECTOR3( 0.0f, 0.0f, 0.0f),
D3DXVECTOR3( 0.0f, 1.0f, 0.0f));
}

Camera::~Camera()
{
}

void Camera::Set(D3DXVECTOR3 position, D3DXVECTOR3 lookat, D3DXVECTOR3 up)
{
// Set up a default position.

m_position = position;
m_lookat = lookat;
m_up = up;
}

void Camera::Move(float distance, D3DXVECTOR3 axis)
{
D3DXVECTOR3 u, // will hold the camera''s right vector

v, // will hold the camera''s up vector

n; // will hold the camera''s view direction vector


// Normalize the axis that we are moving on in camera space

D3DXVec3Normalize(&axis, &axis);

// Get the Camera''s up vector

v = m_up;
D3DXVec3Normalize(&v, &v);

// Get the camera''s viewing direction vector

n = m_lookat - m_position;
D3DXVec3Normalize(&n, &n);

// Get the camera''s right vector

D3DXVec3Cross(&u, &v, &n);
D3DXVec3Normalize(&u, &u);

// Move the Camera

m_position.x += (n.x * distance * axis.z) + (v.x * distance * axis.y) + (u.x * distance * axis.x);
m_position.y += (n.y * distance * axis.z) + (v.y * distance * axis.y) + (u.y * distance * axis.x);
m_position.z += (n.z * distance * axis.z) + (v.z * distance * axis.y) + (u.z * distance * axis.x);

// Move the view along with the position

m_lookat.x += (n.x * distance * axis.z) + (v.x * distance * axis.y) + (u.x * distance * axis.x);
m_lookat.y += (n.y * distance * axis.z) + (v.y * distance * axis.y) + (u.y * distance * axis.x);
m_lookat.z += (n.z * distance * axis.z) + (v.z * distance * axis.y) + (u.z * distance * axis.x);
}

void Camera::Rotate(float angle, D3DXVECTOR3 axis)
{
D3DXVECTOR3 vec[2]; // camera''s view vector is element 0

// camera''s up vector is element 1


D3DXQUATERNION quat_old, // quaternion built from a camera vector

quat_new, // new quanternion after the rotation

quat_rot, // rotation quaternion

quat_conj; // conjugate of the rotation quaternion


float sine = sin(angle/2); // calculation used to build a quaternion


// Get the camera''s viewing direction vector

vec[0] = m_lookat - m_position;
D3DXVec3Normalize(&vec[0], &vec[0]);

// Get the Camera''s up vector

vec[1] = m_up;
D3DXVec3Normalize(&vec[1], &vec[1]);

// Normalize the axis that we are rotating on in camera space

D3DXVec3Normalize(&axis, &axis);

// Build the rotation quaternion

quat_rot.x = axis.x * sine;
quat_rot.y = axis.y * sine;
quat_rot.z = axis.z * sine;
quat_rot.w = cos(angle/2);

// Build the conjugate of the rotation quaternion

D3DXQuaternionConjugate(&quat_conj, &quat_rot);

for(int i = 0; i < 2; i++)
{
// Build the quaternion from the camera vector

quat_old.x = vec[i].x;
quat_old.y = vec[i].y;
quat_old.z = vec[i].z;
quat_old.w = 0;

// Perform the rotation

quat_new = quat_rot * quat_old * quat_conj;

// Get the new view vector

vec[i].x = quat_new.x;
vec[i].y = quat_new.y;
vec[i].z = quat_new.z;
}

// Save the vectors

m_lookat = vec[0] + m_position;
m_up = vec[1];
}

D3DXMATRIX Camera::Update()
{
// Set all the values this matrix will need to know (position, look at point, etc).

D3DXMatrixLookAtLH(&m_view, &m_position, &m_lookat, &m_up);

return m_view;
}


Share this post


Link to post
Share on other sites
bleh. Looks like my first try was correct. I had to have someone explian to me that if you take your hand and spread your fingers out palm down, then rotate it along its y axis, x axis and then y again, you will see that it lays on its side.

I''ll just have to make two cameras, one for space style and one for fps style where up is always up.

Now I''m just gonna optimize the code some and then I''ll post it on my site at http://68.204.11.42

Share this post


Link to post
Share on other sites
Early in my days with quaternions, I made a "rotation cube", a 1" cube of cardboard with different rotational axes written on each face. I still find it indispensable when my brain''s not working quite right with respect to rotations (i.e. most of the time).


"Sneftel is correct, if rather vulgar." --Flarelocke

Share this post


Link to post
Share on other sites