Advertisement

Universal Camera! Lesson #49

Started by June 02, 2006 03:44 AM
0 comments, last by AKrotkov 18 years, 5 months ago
Hi, I am trying to make an opengl game where the user can rotate in *any* direction and then move in the direction he is pointing. In other words, a game where the user *is* the camera, as in a first person shooter, but where the user can rotate on any axis fully (and not with just the usual limiation of 180 degrees on the y-axis and 0 degrees on the z-axis). I have done some research which seems to indicate that the best way this is to use quaternions so that the camera avoids gimbal lock. I have read various articles on how to create a quaternion camera. But I think it would be *very* useful if there were a basic tutorial on the Nehe site which explained how to do this properly. I have talked to a half dozen different people who have wanted to implement this, and *theoretically* know how to do it, but have never taken the time to do it because it was not explained in a simple way with good *working* code to help guide them. Anyhow, it seems like it would be a perfect tutorial for the Nehe site, and would inspire many programmers. It's seems like it might even be a simple extension to the ArcBall lesson-- I'm sure there are lots of people who could whip a tutorial up in a couple of hours. You will be famous and revered if you make these lessons described below! *Lesson 49A* As an example the lesson could have a spaceship/camera flying through space, where there is no limiting concept of up or down. Six keys on the keyboard could map to rotating the camera on the x, y, and z axes. The space bar could "thrust" the spaceship/camera in the direction he is facing toward different planets or whatever. *Lesson 49B* Also, a good and I think important example (and probably a simple one for someone who knows what they are doing!) would be to have a camera/user be facing a particular point (say, the origin) and have keys on the keyboard mapped to rotating/orbiting the camera to the left/right and up/down directions *around a sphere* at some distance from the origin. Two other keys could control the distance toward or away from the center of sphere (the origin). In this example, the camera would *always* be facing the origin, and the camera would always be oribiting/rotating on the surface of a sphere. I would be grateful if this lesson existed, and if it does actually exist somewhere, please direct me to it! Also, if I described the lessons unclearly let me know. -spiral_jetty
Oooh, very interesting challenge. Spent a bit of time on it, but eventually I whipped out a way to track the camera mathematically, before I realized I can just retrieve the matrix stored by OGL (d'oh!).

Here's my version, which stores a matrix corresponding to the axis of the camera, and moving forward just takes an arbitrary vector (0 0 1 1) to move forward by, and moves the position.

The class has a function rotatef(double, double, double, double) which works just as the normal glRotatef functions - call it as rotatef(90,0,1,0) and it will rotate the camera 90 degrees on the y-axis.

The move(double) function will move the camera that many units in the direction the camera is currently pointing.

And yes, all this can be easily optimized.

MATH_Structures.h:
#ifndef MATH_STRUCTURES#define MATH_STRUCTURES#include <math.h>const double piover180 = 0.017453292519943295769236907684886;	class MPoint{public:	double x;	double y;	double z;	double t;	MPoint operator+(const MPoint c);	MPoint operator-(const MPoint c);	MPoint operator*(const double c);	MPoint operator ~(); /* Normalize */	double operator !(); /* length */	double& operator[](const int i);	MPoint();};#endif


MATH_Object.h:
#ifndef MATHOBJECT#define MATHOBJECT#include "MATH_Structures.h"#include <math.h>typedef enum { IDENTITY, ROTATE } tType;class MTransformation{public:	double data[16];	MTransformation(); // Initialize to I_4	MTransformation(tType type, double a = 0.0, double b = 0.0, double c = 0.0, double d = 0.0);	MPoint apply(MPoint a); // Apply transformation to point	MTransformation apply(MTransformation A);	// Apply transformation to transformation										// if this is B, result is BA	double& operator[](const int i);};class MObject{public:	MPoint position;	MTransformation axis;	MPoint direction();	MPoint upvector();	MPoint rightvector();	void move(double t);	void rotate(double degrees, double x, double y, double z);};#endif


MATH_Structures.cpp
#include "Math_Structures.h"MPoint::MPoint(){	x = 0;	y = 0;	z = 0;	t = 1;}MPoint MPoint::operator +(const MPoint c){	MPoint p;	p.x = x + c.x;	p.y = y + c.y;	p.z = z + c.z;	return p;}MPoint MPoint::operator -(const MPoint c){	MPoint p;	p.x = x - c.x;	p.y = y - c.y;	p.z = z - c.z;	return p;}MPoint MPoint::operator *(const double c){	MPoint p;	p.x = x * c;	p.y = y * c;	p.z = z * c;	return p;}MPoint MPoint::operator ~(){	MPoint p;	MPoint c = *this;	double l = c.x * c.x + c.y * c.y + c.z * c.z;	l = sqrt(l);	p.x = c.x / l;	p.y = c.y / l;	p.z = c.z / l;	return p;}double MPoint::operator ! (){	double l = x * x + y * y + z * z;	l = sqrt(l);	return l;}double& MPoint::operator [](int i){	if (i == 0)		return x;	if (i == 1)		return y;	if (i == 2)		return z;	return t;}


MATH_Object.cpp:
#include "MATH_Object.h"MTransformation::MTransformation(){	for (int i = 0; i < 16; i++)	{		data = ((i % 4) == (i / 4));	}}MTransformation::MTransformation(tType type, double a, double b, double c, double d){	if (type == IDENTITY)	{		for (int i = 0; i < 16; i++)		{			data = ((i % 4) == (i / 4));		}	}	else if (type == ROTATE)	{		double cD = cos(a);		double sD = sin(a);		double x = b;		double y = c;		double z = d;		data[0] = cD + (1 - cD) * x * x;		data[1] = (1 - cD) * x * y - sD * z;		data[2] = (1 - cD) * x * z + sD * y;		data[3] = 0;		data[4] = (1 - cD) * y * x + sD * z;		data[5] = cD + (1 - cD) * y * y;		data[6] = (1 - cD) * y * z - sD * x;		data[7] = 0;		data[8] = (1 - cD) * z * x - sD * y;		data[9] = (1 - cD) * z * y + sD * x;		data[10] = cD + (1 - cD) * z * z;		data[11] = 0;		data[12] = 0;		data[13] = 0;		data[14] = 0;		data[15] = 1;	}}double& MTransformation::operator [](int i){	return data;}MPoint MTransformation::apply(MPoint a){	MPoint m;	m[0] =	data[0] * a[0] + data[1] * a[1] +			data[2] * a[2] + data[3] * a[3];	m[1] =	data[4] * a[0] + data[5] * a[1] +			data[6] * a[2] + data[7] * a[3];	m[2] =	data[8] * a[0] + data[9] * a[1] +			data[10] * a[2] + data[11] * a[3];	m[3] =	data[12] * a[0] + data[13] * a[1] +			data[14] * a[2] + data[15] * a[3];	return m;}MTransformation MTransformation::apply(MTransformation A){	MTransformation m;	m[0] = data[0] * A[0] + data[1] * A[4] + data[2] * A[8] + data[3] * A[12];	m[1] = data[0] * A[1] + data[1] * A[5] + data[2] * A[9] + data[3] * A[13];	m[2] = data[0] * A[2] + data[1] * A[6] + data[2] * A[10] + data[3] * A[14];	m[3] = data[0] * A[3] + data[1] * A[7] + data[2] * A[11] + data[3] * A[15];	m[4] = data[4] * A[0] + data[5] * A[4] + data[6] * A[8] + data[7] * A[12];	m[5] = data[4] * A[1] + data[5] * A[5] + data[6] * A[9] + data[7] * A[13];	m[6] = data[4] * A[2] + data[5] * A[6] + data[6] * A[10] + data[7] * A[14];	m[7] = data[4] * A[3] + data[5] * A[7] + data[6] * A[11] + data[7] * A[15];		m[8] = data[8] * A[0] + data[9] * A[4] + data[10] * A[8] + data[11] * A[12];	m[9] = data[8] * A[1] + data[9] * A[5] + data[10] * A[9] + data[11] * A[13];	m[10] = data[8] * A[2] + data[9] * A[6] + data[10] * A[10] + data[11] * A[14];	m[11] = data[8] * A[3] + data[9] * A[7] + data[10] * A[11] + data[11] * A[15];	m[12] = data[12] * A[0] + data[13] * A[4] + data[14] * A[8] + data[15] * A[12];	m[13] = data[12] * A[1] + data[13] * A[5] + data[14] * A[9] + data[15] * A[13];	m[14] = data[12] * A[2] + data[13] * A[6] + data[14] * A[10] + data[15] * A[14];	m[15] = data[12] * A[3] + data[13] * A[7] + data[14] * A[11] + data[15] * A[15];	return m;}void MObject::move(double t){	MPoint forward;	forward[2] = 1.0;	forward = axis.apply(forward);	position = position + (forward * t);}void MObject::rotate(double degrees, double x, double y, double z){	MTransformation t(ROTATE, degrees * piover180, x,y,z);	axis = axis.apply(t);}MPoint MObject::direction(){	MPoint forward;	forward[2] = 1.0;	forward = axis.apply(forward);	return forward;}MPoint MObject::upvector(){	MPoint forward;	forward[1] = 1.0;	forward = axis.apply(forward);	return forward;}MPoint MObject::rightvector(){	MPoint forward;	forward[0] = 1.0;	forward = axis.apply(forward);	return forward;}

This topic is closed to new replies.

Advertisement