Advertisement

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

Started by March 28, 2005 08:09 AM
2 comments, last by TheFatGecko 19 years, 5 months ago
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.
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
Advertisement
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]
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 aroundclass 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(){}voidCamera::SetDefaults(CVector Origin0, float R0, float Elev0, float Yaw0){    origin0 = Origin0;    elev0 = Elev0;    yaw0 = Yaw0;    r0 = R0;           // Distance from focalPoint    Reset();}voidCamera::Reset(){    elev = elev0;    yaw = yaw0;    r = r0;    focalPoint = origin0;}voidCamera::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);}voidCamera::IncR(float dr){    SetR(r+dr);}voidCamera::IncElev(float change){    SetElev(elev + change);}voidCamera::IncYaw(float change){    SetYaw(yaw+change);}voidCamera::SetR(float r_){    r = r_;    if (r < 1) r = 1;    if (r > 50) r = 50;}voidCamera::SetYaw(float yaw_){    yaw = yaw_;    if (yaw >= 180.0) yaw -= 360;    if (yaw < -180.0) yaw += 360;}voidCamera::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 CVectortypedef class CVector CVertex;#include "CVector.inl"#endif // CVECTOR_H//---------------------------------------------------------------------------// CVector.inl//---------------------------------------------------------------------------/*===============================================================================    Inlines for Class: CVector===============================================================================*/inlineCVector::CVector(const float &xx, const float &yy, const float &zz, const float &ww){    x = xx;    y = yy;    z = zz;    w = ww;}inlinevoidCVector::Set(const float &xx, const float &yy, const float &zz, const float &ww){    x = xx;    y = yy;    z = zz;}inlinevoidCVector::Set(const float *pv){    x = pv[0];    y = pv[1];    z = pv[2];}inlineCVector& CVector::operator = (const CVector &v){    x = v.x;    y = v.y;    z = v.z;    return *this;}inlineCVector&CVector::operator += (const CVector &v){    x += v.x;    y += v.y;    z += v.z;    return *this;}inlineCVector&CVector::operator -= (const CVector &v){    x -= v.x;    y -= v.y;    z -= v.z;    return *this;}inlineCVectorCVector::operator + (const CVector &v) const{    return CVector(x + v.x, y + v.y, z + v.z);}inlineCVectorCVector::operator - (const CVector &v) const{    return CVector(x - v.x, y - v.y, z - v.z);}inlinevoidCVector::Scale(const float &a){    x *= a;    y *= a;    z *= a;}inlineCVectorCVector::operator * (const float &a) const      // Scale{    return CVector (x*a, y*a, z*a);}inlineCVectorCVector::operator / (const float &a) const{    return CVector(x/a, y/a, z/a);}inlinevoidCVector::operator *= (const float &a){    x *= a;    y *= a;    z *= a;}inlinevoidCVector::operator /= (const float &a){    x /= a;    y /= a;    z /= a;}inlinefloatCVector::Dot(const CVector &a) const{    return (a.x * x) + (a.y * y) + (a.z * z);}inlineCVectorCVector::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);}inlinefloatCVector::Modulus() const{    return sqrt(x*x + y*y + z*z);}inlineCVectorCVector::UnitVec() const{    float R = Modulus();    if (R == 0.0)    {        return CVector(0,0,0);    }    else    {        return CVector(x/R, y/R, z/R);    }}inlinevoidCVector:: Normalise(){    float R = Modulus();    if (R != 0.0)    {        x /= R;        y /= R;        z /= R;    }}inlinevoidCVector::SetLength(const float &len){    Normalise();    x *= len;    y *= len;    z *= len;}inlinevoidCVector::RotateZ(float ang){  float COS = cos(ang);  float SIN = sin(ang);  float oldx = x;  x = oldx*COS - y*SIN;  y = y*COS + oldx*SIN;}inlinevoidCVector::RotateX(float ang){  float COS = cos(ang);  float SIN = sin(ang);  float oldy = y;  y = oldy*COS - z*SIN;  z = z*COS + oldy*SIN;}inlinevoidCVector::RotateY(float ang){  float COS = cos(ang);  float SIN = sin(ang);  float oldz = z;  z = oldz*COS - x*SIN;  x = x*COS + oldz*SIN;}inlinevoidCVector::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);}inlinevoidCVector::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===============================================================================*/inlineCMatrix::CMatrix(){    LoadIdentity();}inlinevoidCMatrix::LoadIdentity(){    memset(this,0,sizeof(m));    m11 = 1.0;    m22 = 1.0;    m33 = 1.0;    m44 = 1.0;}inlineCVectorCMatrix::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;}inlineCMatrixCMatrix::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;}inlinevoidCMatrix::GetBasis(CVector &X, CVector &Y, CVector &Z) const{    X.Set(m11, m12, m13);    Y.Set(m21, m22, m23);    Z.Set(m31, m32, m33);}inlinevoidCMatrix::GetInverseBasis(CVector &X, CVector &Y, CVector &Z) const{    X.Set(m11, m21, m31);    Y.Set(m12, m22, m32);    Z.Set(m13, m23, m33);}inlinevoidCMatrix::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;}inlinevoidCMatrix::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;}inlinevoidCMatrix::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);}
______________________________________________________The problem with designing something completely foolproof is tounderestimate the ingenuity of a complete fool. - Douglas AdamsEmail: thefatgecko@yahoo.co.ukhttp://www.geocities.com/thefatgecko

This topic is closed to new replies.

Advertisement