Public Group

# OpenGL Camera

This topic is 5006 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hello! I'm planing to implement a camera in a OpenGL program. But I can't get I right. I want to move where the camera is currently pointing. This's what I've done so fare. I think I must rotate the vector, which represent the way I want to move. I found a matrix which should do it in a book: [ cos(a) 0 -sin(a) 0 ] [ 0 1 0 0 ] [sin(a) 0 cos(a) 0 ] [ 0 0 0 1 ] Then I applicate it one my vector (x, y, z) and get a new one: (cos(a)*x - sin(a)*z, y, sin(a)*x + cos(a)*y) I really think I ought to post some code too. You must excuse that my OpenGL skills aren't exactly the best.
void draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glTranslatef(0.0f, 0.0f, -6.0f);
drawCube(0.0f, 0.0f);

glMatrixMode(GL_PROJECTION);
gluPerspective(45.0f, 640/480, 0.1f, 100.0f);

glRotatef(playerAngle, 0.0f, 1.0f, 0.0f);

y = playerPosY;
glTranslatef(x, y, z);

glMatrixMode(GL_MODELVIEW);

SDL_GL_SwapBuffers();
}



##### Share on other sites
First of all you have certain key fundamentals about openGL wrong.
Certain things have to be done in the right order, such as setting up the
projection matrix, clearing the buffer setting up the model matrix then
drawing, etc ...

void draw(){    glMatrixMode(GL_PROJECTION);                        // Setting up the projection    glLoadIdentity();                                   // doesn't have to be done    gluPerspective(45.0f, 640/480, 0.1f, 100.0f);       // each frame. Instead                                                        // move it to a GLInit() procedure    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    glMatrixMode(GL_MODELVIEW);    glLoadIdentity();    float radius = 6.0;     // (New) The distance from the eye to the point of interest    glTranslatef(0.0f, 0.0f, -radius);    drawCube(0.0f, 0.0f);    glRotatef(playerAngle, 0.0f, 1.0f, 0.0f);        GLfloat x,y,z,radians;    radians = playerAngle * 0.017;    x = radius*cos(radians) * playerPosX - radius*sin(radians) * playerPosZ;    y = playerPosY;    z = radius*sin(radians) * playerPosX + radius*cos(radians) * playerPosY;    glTranslatef(x, y, z);        SDL_GL_SwapBuffers();}

See if that works. Note the inclusion of a radius variable. Before you weren't multiplying
the cos and sin terms by the distance from the eye to the point of interest

##### Share on other sites
No, it isn't working. And I cannot understand the function of the radius variable. I also thought one should manipulate the projection matrix to get the camera effect. I'm, as I told you, quite new to this.

Edit: BTW, I do think I must set up the perspective in every frame, for I must call glIdentity and then one's perspective settings go away, right?

##### Share on other sites
I would break the camera up into its own class. It'll have it's own position, velocity, and rotational vectors, a function that will pass time (change position based on velocity, velocity based on friction), functions to move/rotate, and a function to apply the translations and rotations to the rest of the world (which will be called each frame).

You don't have to manipulate the projection matrix to get this to work. I find it much simpler to play with the modelview matrix, though I don't know if that copmlicates things if you have another player with its own camera (never done anything like that).

Also, what is it doing that you say it's not working?

##### Share on other sites
With the new code I cannot move at all! BTW, I don't see how I can get I work with only the modelview matrix.

##### Share on other sites
First of all, a camera system can be very hard to make if you're not familiar with some necesary math and your API (OpenGL).

I would recommend, to perhaps simplify things, that you use the function gluLookAt(). It will take 9 floats. The first three are your position, next three are the point which you look at and the last 3 is your up vector (The axis that's up, duh! [grin]). You will still need some math if you're trying to implement an FPS style camera, but at least you can boil it down to some simple cos/sin equations. Have you read about finding x and y force of a diagonal force, using cos and sin?
If you have, can you come up with a formula to make a point rotate about a center? Can you now make it so a point in a 3D space can rotate about a center? If you've reached this far, you should have little trouble figuring out how to use that knowledge with gluLookAt() (hint: look at point rotates about camera center...).

Another way, the one you're after, is by using matrices. That requires a lot more math since you have to do all translations/rotation/concatenations/inverses/... ( ..i don't what there is to it [grin]) that gluLookAt() will do for you.

When you've studied some more matrix math, perhaps then you can write a camera system that works entierly out of matrices, but take it easy at the start [smile]

Hope it helps!

##### Share on other sites
This is my 3rd person camera system. Hopefully this should get you started
in understanding how to implement a camera (i'm sure some people will also
tell you it not how to implement a camera).

There are a number of files place the code into right file and the camera

/*  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);}

##### Share on other sites
Hmm. Scary indeed.
Can you check if I get the diagonal force thingie right, please?
void Camera::Move(GLfloat x, GLfloat y, GLfloat z){    posX += cos(0.017f * angle) * x  - sin(0.017f * angle) * z;    posY += y;    posZ += sin(0.017f * angle) * x + cos(0.017f * angle) * y;}

EDIT: Maybe worth saying: this is intend to be yaw-rotation.

##### Share on other sites
Heh, what a pain it is when you realize you have forgot basic math, and need to re-learn it [grin]

Well, your formula looks almost correct. There should be a Z on the end of the last row, but i bet you knew that already.

What i can't figure out is how you have your camera set up. Using these formulas you will rotate a vector around an axis based from it's last point.

Quote:
 void Camera::Move(GLfloat x, GLfloat y, GLfloat z){ posX += cos(0.017f * angle) * x - sin(0.017f * angle) * z; posY += y; posZ += sin(0.017f * angle) * x + cos(0.017f * angle) * y;}

I guess i just get stuck with you calling the function move since that's not at all what you do...you rotate your LookAt point, for example...

I would rather do something like this [smile]
// this is what you call once you rotate the cameravoid Camera::OnRotate(){   this->rot += 5.0f;}// You need a function to move, ignore the math ;)void Camera::OnMove(){   this->moveVec.x = this->view.x;   this->moveVec.z = this->view.z;}// This should be called every frame, or every time the camera needs to be updatedvoid Camera::Update(){   if(this->moveVec.x != 0 || this->moveVec.z != 0)   {      this->pos.x += moveVec.x;      this->pos.z += moveVec.z;   }   if(this->rot != 0)   {      const float cosTheta = cos(this->rot);      const float sinTheta = sin(this->rot);      this->view.x = cosTheta * x - sinTheta * z;      this->view.z = sinTheta * x + cosTheta * z;      this->rot = 0;   }}// and last, something that "draw" or place the cameravoid Camera::Draw(){   gluLookAt(this->pos.x, this->pos.y, this->pos.z,             this->pos.x + this->view.x, this->pos.y + this->view.z, this->pos.z + this->view.z,             0, 1, 0);}

Don't trust that code, i didn't think much when writing it, and it hasn't been tested, but it should be enough to give you something to work with. I havn't bothered about the up-vector since you only do yaw rotations, but it's really easy to add in.

If you want to read further about the formulas used to rotate, they're called addition and subtraction formulas for cosine and sinus...or something like that. [smile]

1. 1
2. 2
Rutin
17
3. 3
4. 4
5. 5

• 13
• 26
• 10
• 11
• 9
• ### Forum Statistics

• Total Topics
633735
• Total Posts
3013597
×

## Important Information

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!