Sign in to follow this  
leggyguy

3rd person Camera (Space/flight sim style)?

Recommended Posts

Hi. I can implement a 3rd person camera for a project where the character will always run along the floor, thanks to a tutorial from gametutorials.com But now I wish to implement a 3rd person camera for a spaceship game, so the camera needs to rotate not just left and right around the character, but also up and down. This means altering the "up" vector of the camera, which none of the 3rd person tuts I have seen before cover. I don't suppose anyone has seen such a tutorial, anywhere? I am creating a space game, and am discovering new challenges all the time. But I can't find any space game projects through google or similar with open source code or with accompanying tutorials, and I find that odd. Would have been a popular thing, I think.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I'm doing something similar with a 3rd-person helicopter game. I use two angles for the camera: a heading (360 degrees horizontal) and an elevation (-90 to + 90). The camera orbits around the vehicle, its position determined by those two angles. Basically:
camera x = dist * cos(heading) * cos(elevation)
camera y = dist * sin(elevation)
camera z = dist * sin(heading) * cos(elevation)

if you're using glut, thos equations can give you coordinates for a gluLookAt call.

if you're not then you can just transform the modelview matrix
glRotatef(heading,0.0,1.0,0.0);
glRotatef(elevation,1.0,0.0,0.0);
glTranslatef(0.0,0.0,-dist);

which will place the camera at the right spot, if the last object drawn before the transforms is the vehicle.

now I have a question for you: are you using the mouse to control this? If so: how do you allow the mouse to move off the edges of the screen? Mine always stops at the screen edge, meaning I can't turn any further, which is very annoying.

Cheers
Tetracanth

Share this post


Link to post
Share on other sites
simple, just recenter the mouse pointer every frame and work out the relative motion for every frame.

to do that just add the folowing line to your code
SetCursorPos(300,300);
this sets the mouse position to 300,300
after that you better read the cursor pos with GetCursorPos imediatly to resolve some issues.

you need to have included windows.h for it to work.

so to repeat myself, it's read, set and then read again to calibrate the mouse.
then compare the first read with the last one from the previous frame.


[Edited by - lc_overlord on April 1, 2005 10:42:07 AM]

Share this post


Link to post
Share on other sites
Here's the code for my 3rd person camera (it may be of use to you)

(The code needs to be placed into different files)

/*

A simple 3rd person camera class

Basic usage:

void Init()
{
// Set up defaults:

CVector pointOfInterest(0,0,0);
float radius = 6.0; // distance between camera and point of interest
float elevation = 45;
float yaw = 45;
camera->SetDefaults(pointOfInterest, radius, yaw, elevation);
}

void DrawScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

camera->focalPoint.Set(0,0,0); // the point of interest where the camera revolves around
camera->LoadMatrix();
}

void DoKeyLeft()
{
camera->IncYaw(-1.0); // decrease yaw by 1 degree
}

void DoKeyUp()
{
camera->IncElev(-1.0); // decrease elev by 1 degree
}


*/



//---------------------------------------------------------------------------
// Camera.h
//---------------------------------------------------------------------------

#ifndef GameX_Camera_H
#define GameX_Camera_H

#include "CVector.h"

// A pretty Simple camera 3rd person camera
//
// Focal point == the point of interest. i.e. the point that
// the camera will revolve around


class Camera
{
public:
Camera(CVector origin0, float R0, float Elev0, float Yaw0);
virtual ~Camera();

void LoadMatrix();
void Reset();
void SetDefaults(CVector origin0, float R0, float Elev0, float Yaw0);
const float& Elev() {return elev; }
const float& Yaw() {return yaw; }
void IncR(float dr);
void IncElev(float change);
void IncYaw(float change);
void SetR(float r);
void SetYaw(float yaw);
void SetElev(float elev);

public:
CVector focalPoint;

protected:
float elev;
float yaw;
float r;
float r0, elev0, yaw0;
CVector origin0;
};

#endif


//---------------------------------------------------------------------------
// Camera.cpp
//---------------------------------------------------------------------------
#include <windows.h>
#include <gl/gl.h>

#include "Camera.h"

Camera::Camera(CVector Origin0, float R0, float Elev0, float Yaw0)
{
SetDefaults(Origin0, R0, Elev0, Yaw0);
}

Camera::~Camera()
{
}

void
Camera::SetDefaults(CVector Origin0, float R0, float Elev0, float Yaw0)
{
origin0 = Origin0;
elev0 = Elev0;
yaw0 = Yaw0;
r0 = R0; // Distance from focalPoint
Reset();
}


void
Camera::Reset()
{
elev = elev0;
yaw = yaw0;
r = r0;
focalPoint = origin0;
}

void
Camera::LoadMatrix()
{
// Set up the axis to that
// Z is up
// Y is forward
// Z is right
glRotatef(-90,1,0,0);

glTranslatef(0, r , 0);
glRotatef(elev, 1,0,0);
glRotatef(-yaw, 0,0,1);

glTranslatef(-focalPoint.x, -focalPoint.y, -focalPoint.z);
}

void
Camera::IncR(float dr)
{
SetR(r+dr);
}
void
Camera::IncElev(float change)
{
SetElev(elev + change);
}

void
Camera::IncYaw(float change)
{
SetYaw(yaw+change);
}

void
Camera::SetR(float r_)
{
r = r_;
if (r < 1) r = 1;
if (r > 50) r = 50;
}

void
Camera::SetYaw(float yaw_)
{
yaw = yaw_;
if (yaw >= 180.0) yaw -= 360;
if (yaw < -180.0) yaw += 360;
}

void
Camera::SetElev(float elev_)
{
elev = elev_;
if (elev > 90) elev = 90;
if (elev < -90) elev = -90;
}


//---------------------------------------------------------------------------
// CVector.h
//---------------------------------------------------------------------------

#ifndef CVECTOR_H
#define CVECTOR_H

#include "mem.h" // for memset
#include "math.h"

class CVector;
class CMatrix;

class CVector
{
public:
union
{
struct
{
float x;
float y;
float z;
float w;
};
float v[4];
};

inline CVector() {}
inline CVector(const float &xx, const float &yy, const float &zz, const float &ww = 1);

inline void Set(const float &xx, const float &yy, const float &zz, const float &ww = 1);
inline void Set(const float *pv);
inline CVector& operator = (const CVector &v);

inline CVector& operator += (const CVector &v);
inline CVector& operator -= (const CVector &v);

inline CVector operator + (const CVector &v) const;
inline CVector operator - (const CVector &v) const;

inline void Scale(const float &a);
inline CVector operator * (const float &a) const;
inline CVector operator / (const float &a) const;
inline void operator *= (const float &a);
inline void operator /= (const float &a);

inline float Dot(const CVector &a) const;
inline CVector Cross (const CVector &a) const;

inline float Modulus() const;
inline CVector UnitVec() const;
inline void Normalise();
inline void SetLength(const float &len);

inline void RotateX(float ang);
inline void RotateY(float ang);
inline void RotateZ(float ang);
inline void Rotate(float theta, CVector v);

inline void Lerp(const CVector &v1, const CVector &v2, float k);

// Cast to float
inline operator float*() { return v; }

private:
friend class CMatrix;

};

/*
===============================================================================
Class: CMatrix
===============================================================================
*/


class CMatrix
{
public:
union
{
float m[16];
struct
{
float m11, m21, m31, m41; // Stored like opengl matrix
float m12, m22, m32, m42; // Indices are (row, column)
float m13, m23, m33, m43;
float m14, m24, m34, m44;
};
};

inline CMatrix();
inline void LoadIdentity();
CVector operator * (const CVector &v) const;
CMatrix operator * (const CMatrix &In);

inline void GetBasis(CVector &X, CVector &Y, CVector &Z) const;
inline void GetInverseBasis(CVector &X, CVector &Y, CVector &Z) const;

inline void SetBasis(CVector &X, CVector &Y, CVector &Z);
inline void SetInverseBasis(CVector &X, CVector &Y, CVector &Z);

inline void Transpose();

private:
friend class CVector;

};


// Define CVertex to the be the same as CVector

typedef class CVector CVertex;


#include "CVector.inl"

#endif // CVECTOR_H

//---------------------------------------------------------------------------
// CVector.inl
//---------------------------------------------------------------------------

/*
===============================================================================
Inlines for Class: CVector
===============================================================================
*/


inline
CVector::CVector(const float &xx, const float &yy, const float &zz, const float &ww)
{
x = xx;
y = yy;
z = zz;
w = ww;
}

inline
void
CVector::Set(const float &xx, const float &yy, const float &zz, const float &ww)
{
x = xx;
y = yy;
z = zz;
}

inline
void
CVector::Set(const float *pv)
{
x = pv[0];
y = pv[1];
z = pv[2];
}

inline
CVector& CVector::operator = (const CVector &v)
{
x = v.x;
y = v.y;
z = v.z;
return *this;
}


inline
CVector&
CVector::operator += (const CVector &v)
{
x += v.x;
y += v.y;
z += v.z;
return *this;
}

inline
CVector&
CVector::operator -= (const CVector &v)
{
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}

inline
CVector
CVector::operator + (const CVector &v) const
{
return CVector(x + v.x, y + v.y, z + v.z);
}

inline
CVector
CVector::operator - (const CVector &v) const
{
return CVector(x - v.x, y - v.y, z - v.z);
}


inline
void
CVector::Scale(const float &a)
{
x *= a;
y *= a;
z *= a;
}

inline
CVector
CVector::operator * (const float &a) const // Scale
{
return CVector (x*a, y*a, z*a);
}

inline
CVector
CVector::operator / (const float &a) const
{
return CVector(x/a, y/a, z/a);
}

inline
void
CVector::operator *= (const float &a)
{
x *= a;
y *= a;
z *= a;
}

inline
void
CVector::operator /= (const float &a)
{
x /= a;
y /= a;
z /= a;
}

inline
float
CVector::Dot(const CVector &a) const
{
return (a.x * x) + (a.y * y) + (a.z * z);
}

inline
CVector
CVector::Cross (const CVector &a) const
{
return CVector(y*a.z - z*a.y,
z*a.x - x*a.z,
x*a.y - y*a.x);
}

inline
float
CVector::Modulus() const
{
return sqrt(x*x + y*y + z*z);
}

inline
CVector
CVector::UnitVec() const
{
float R = Modulus();
if (R == 0.0)
{
return CVector(0,0,0);
}
else
{
return CVector(x/R, y/R, z/R);
}
}

inline
void
CVector:: Normalise()
{
float R = Modulus();
if (R != 0.0)
{
x /= R;
y /= R;
z /= R;
}
}

inline
void
CVector::SetLength(const float &len)
{
Normalise();
x *= len;
y *= len;
z *= len;
}

inline
void
CVector::RotateZ(float ang)
{
float COS = cos(ang);
float SIN = sin(ang);

float oldx = x;
x = oldx*COS - y*SIN;
y = y*COS + oldx*SIN;
}

inline
void
CVector::RotateX(float ang)
{
float COS = cos(ang);
float SIN = sin(ang);

float oldy = y;
y = oldy*COS - z*SIN;
z = z*COS + oldy*SIN;
}

inline
void
CVector::RotateY(float ang)
{
float COS = cos(ang);
float SIN = sin(ang);

float oldz = z;
z = oldz*COS - x*SIN;
x = x*COS + oldz*SIN;
}

inline
void
CVector::Rotate(float theta, CVector v)
{
v.Normalise();
float COS = cos(theta);

// Borrowed this formula from Diana Gruber, FastGraph
// (but needs optimising to reduce constructor calls!)

*this = (*this)*COS + v*((v.Dot(*this))*(1-COS)) - (this->Cross(v))*sin(theta);
}

inline
void
CVector::Lerp(const CVector &v1, const CVector &v2, float t)
{
float s = 1-t;
x = v1.x*s + v2.x*t;
y = v1.y*s + v2.y*t;
z = v1.z*s + v2.z*t;
}

/*
===============================================================================
Inlines for Class: CMatrix
===============================================================================
*/


inline
CMatrix::CMatrix()
{
LoadIdentity();
}

inline
void
CMatrix::LoadIdentity()
{
memset(this,0,sizeof(m));
m11 = 1.0;
m22 = 1.0;
m33 = 1.0;
m44 = 1.0;
}

inline
CVector
CMatrix::operator * (const CVector &v) const
{
// Should probably change this to a for-loop

CVector Out;

Out.x = (m11 * v.x) + (m12 * v.y) + (m13 * v.z) + m14;
Out.y = (m21 * v.x) + (m22 * v.y) + (m23 * v.z) + m24;
Out.z = (m31 * v.x) + (m32 * v.y) + (m33 * v.z) + m34;
Out.w = 1;

return Out;
}

inline
CMatrix
CMatrix::operator * (const CMatrix &In)
{
// Should probably change this to a for-loop

CMatrix Out;

Out.m11 = (m11 * In.m11) + (m12 * In.m21) + (m13 * In.m31) + (m14 * In.m41);
Out.m21 = (m21 * In.m11) + (m22 * In.m21) + (m23 * In.m31) + (m24 * In.m41);
Out.m31 = (m31 * In.m11) + (m32 * In.m21) + (m33 * In.m31) + (m34 * In.m41);
Out.m41 = 0;

Out.m12 = (m11 * In.m12) + (m12 * In.m22) + (m13 * In.m32) + (m14 * In.m42);
Out.m22 = (m21 * In.m12) + (m22 * In.m22) + (m23 * In.m32) + (m24 * In.m42);
Out.m32 = (m31 * In.m12) + (m32 * In.m22) + (m33 * In.m32) + (m34 * In.m42);
Out.m42 = 0;

Out.m13 = (m11 * In.m13) + (m12 * In.m23) + (m13 * In.m33) + (m14 * In.m43);
Out.m23 = (m21 * In.m13) + (m22 * In.m23) + (m23 * In.m33) + (m24 * In.m43);
Out.m33 = (m31 * In.m13) + (m32 * In.m23) + (m33 * In.m33) + (m34 * In.m43);
Out.m43 = 0;

Out.m14 = (m11 * In.m14) + (m12 * In.m24) + (m13 * In.m34) + (m14 * In.m44);
Out.m24 = (m21 * In.m14) + (m22 * In.m24) + (m23 * In.m34) + (m24 * In.m44);
Out.m34 = (m31 * In.m14) + (m32 * In.m24) + (m33 * In.m34) + (m34 * In.m44);
Out.m44 = 1;

return Out;
}

inline
void
CMatrix::GetBasis(CVector &X, CVector &Y, CVector &Z) const
{
X.Set(m11, m12, m13);
Y.Set(m21, m22, m23);
Z.Set(m31, m32, m33);
}

inline
void
CMatrix::GetInverseBasis(CVector &X, CVector &Y, CVector &Z) const
{
X.Set(m11, m21, m31);
Y.Set(m12, m22, m32);
Z.Set(m13, m23, m33);
}

inline
void
CMatrix::SetBasis(CVector &X, CVector &Y, CVector &Z)
{
m11 = X.x; m12 = X.y; m13 = X.z;
m21 = Y.x; m22 = Y.y; m23 = Y.z;
m31 = Z.x; m32 = Z.y; m33 = Z.z;
}

inline
void
CMatrix::SetInverseBasis(CVector &X, CVector &Y, CVector &Z)
{
m11 = X.x; m21 = X.y; m31 = X.z;
m12 = Y.x; m22 = Y.y; m32 = Y.z;
m13 = Z.x; m23 = Z.y; m33 = Z.z;
}

#define SWAP(a, b, type) {type tmp = a; a = b; b = tmp;}

inline
void
CMatrix::Transpose()
{
SWAP(m12,m21, float);
SWAP(m13,m31, float);
SWAP(m14,m41, float);
SWAP(m23,m32, float);
SWAP(m24,m42, float);
SWAP(m34,m43, float);
}



Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this