[help] problem with camera lib

Nibbie
Posts: 4
Joined: 2009.10
Post: #1
Hi, Mac developers!
I write camera in OpenGL for my game engine, I implement rotation matrix, but I can not see why after rotation camera begin to move in global Z axis (not local z axis)? So we look at local z, but move to global z Shock

Code:
#define M_PI2  M_PI / 2.0

enum event_t {
  mLEFT,
  mRIGHT,
  mFORWARD,
  mBACK,
  mUP,
  mDOWN,
  LEFT,
  RIGHT,
  UP,
  DOWN
};

typedef struct {
  float x, y, z;
} vec3_t;

typedef struct {
  vec3_t eye;      // global camera location
  vec3_t euler;    // global euler angles
  vec3_t c_eye;    // current delta camera coordinates
  vec3_t c_euler;    // current delta euler angles
} FLCamera;


#include <OpenGL/OpenGL.h>
#include <stdlib.h>
#include <math.h>
#include "libCamera.h"

FLCamera *newCamera(void)
{
  return malloc(sizeof(FLCamera));
}

void initCamera(FLCamera *theCamera,
        vec3_t thePos,
        vec3_t theEuler)
{
  theCamera->eye = thePos;
  theCamera->euler = theEuler;
}

void useCamera(FLCamera *theCamera)
{
  GLfloat m[16] = {0.0};  // opengl matrix
  GLfloat n[16] = {0.0};  // global matrix
  GLfloat f[16] = {0.0};  // current matrix
  
  vec3_t null = {0.0, 0.0, 0.0};
  
  GLfloat _x, _y, _z;
/*  
/////////////////////////////////////////////////
      calculate global matrix
/////////////////////////////////////////////////
*/  
  
  GLfloat sinx = sinf(theCamera->euler.x);
  GLfloat siny = sinf(theCamera->euler.y);
  GLfloat sinz = sinf(theCamera->euler.z);
  
  GLfloat cosx = cosf(theCamera->euler.x);
  GLfloat cosy = cosf(theCamera->euler.y);
  GLfloat cosz = cosf(theCamera->euler.z);
  
  
  n[0] = cosy * cosz;              n[4] = - cosy * sinz;            n[8] = siny;  
  n[1] = sinx * siny * cosz + cosx * sinz;  n[5] = cosx * cosz - sinx * siny * sinz;  n[9] = - sinx * cosy;  
  n[2] = sinx * sinz - cosx * siny * cosz;  n[6] = sinx * cosz + cosx * siny * sinz;  n[10] = cosx * cosy;            

/*  
/////////////////////////////////////////////////
      calculate current matrix
/////////////////////////////////////////////////
*/

  sinx = sinf(theCamera->c_euler.x);
  siny = sinf(theCamera->c_euler.y);
  sinz = sinf(theCamera->c_euler.z);
  
  cosx = cosf(theCamera->c_euler.x);
  cosy = cosf(theCamera->c_euler.y);
  cosz = cosf(theCamera->c_euler.z);
  
  f[0] = cosy * cosz;              f[4] = - cosy * sinz;            f[8] = siny;  
  f[1] = sinx * siny * cosz + cosx * sinz;  f[5] = cosx * cosz - sinx * siny * sinz;  f[9] = - sinx * cosy;  
  f[2] = sinx * sinz - cosx * siny * cosz;  f[6] = sinx * cosz + cosx * siny * sinz;  f[10] = cosx * cosy;
  
/*  
/////////////////////////////////////////////////
      calculate opengl matrix
/////////////////////////////////////////////////
*/
  
  m[0] = n[0] * f[0] + n[4] * f[1] + n[8] * f[2];
  m[1] = n[1] * f[0] + n[5] * f[1] + n[9] * f[2];
  m[2] = n[2] * f[0] + n[6] * f[1] + n[10] * f[2];
  
  m[4] = n[0] * f[4] + n[4] * f[5] + n[8] * f[6];
  m[5] = n[1] * f[4] + n[5] * f[5] + n[9] * f[6];
  m[6] = n[2] * f[4] + n[6] * f[5] + n[10] * f[6];
  
  m[8] = n[0] * f[8] + n[4] * f[9] + n[8] * f[10];
  m[9] = n[1] * f[8] + n[5] * f[9] + n[9] * f[10];
  m[10] = n[2] * f[8] + n[6] * f[9] + n[10] * f[10];
  
  _x = theCamera->eye.x += (theCamera->c_eye.x * (m[0] + m[4] + m[8]));
  _y = theCamera->eye.y += (theCamera->c_eye.y * (m[1] + m[5] + m[9]));
  _z = theCamera->eye.z += (theCamera->c_eye.z * (m[2] + m[6] + m[10]));
  
  m[12] = - (_x * m[0] + _y * m[4] + _z * m[8]);
  m[13] = - (_x * m[1] + _y * m[5] + _z * m[9]);
  m[14] = - (_x * m[2] + _y * m[6] + _z * m[10]);
  m[15] = 1.0;
  
  glLoadMatrixf(m);
  
  theCamera->c_eye = null;
  theCamera->c_euler = null;
  theCamera->euler = extractEuler(m, NULL);

  }

vec3_t extractEuler(float m[16], vec3_t *euler)
{
  vec3_t theta;
  
  theta.y = asinf(m[8]);
  if (theta.y < M_PI2) {
    if (theta.y > - M_PI2) {
      theta.x = atan2f(- m[9], m[10]);
      theta.z = atan2f(- m[4], m[0]);
    }
    else {
      theta.x = - atan2f(m[4], m[5]);
      theta.z = 0.0;
    }
  }
  else {
    theta.x = atan2f(m[4], m[5]);
    theta.z = 0.0;
  }
  
  return theta;
}
  
void moveCameraLeft(FLCamera *theCamera, float vel)
{
  theCamera->c_eye.x -= vel;
}

void moveCameraRight(FLCamera *theCamera, float vel)
{
  theCamera->c_eye.x += vel;
}

void moveCameraUp(FLCamera *theCamera, float vel)
{
  theCamera->c_eye.y -= vel;
}

void moveCameraDown(FLCamera *theCamera, float vel)
{
  theCamera->c_eye.y += vel;
}

void moveCameraForward(FLCamera *theCamera, float vel)
{
  theCamera->c_eye.z -= vel;
}

void moveCameraBack(FLCamera *theCamera, float vel)
{
  theCamera->c_eye.z += vel;
}

void rotCameraLeft(FLCamera *theCamera, float angle)
{
  theCamera->c_euler.y -= angle;
}

void rotCameraRight(FLCamera *theCamera, float angle)
{
  theCamera->c_euler.y += angle;
}

void rotCameraUp(FLCamera *theCamera, float angle)
{
  theCamera->c_euler.x -= angle;
}

void rotCameraDown(FLCamera *theCamera, float angle)
{
  theCamera->c_euler.x += angle;
}

void deleteCamera(FLCamera *theCamera)
{
  free(theCamera);
}
Quote this message in a reply
Member
Posts: 63
Joined: 2005.12
Post: #2
I see some issues (or at least potential issues) with your code, but regarding your specific question, this:

Code:
_x = theCamera->eye.x += (theCamera->c_eye.x * (m[0] + m[4] + m[8]));
  _y = theCamera->eye.y += (theCamera->c_eye.y * (m[1] + m[5] + m[9]));
  _z = theCamera->eye.z += (theCamera->c_eye.z * (m[2] + m[6] + m[10]));

Doesn't look correct to me. It looks like the objective here is to transform c_eye from local space to world space, but unless I'm missing something, you're not performing a full matrix-vector multiplication here. It seems to me that each of these lines of code should perform a full dot product, e.g.:

Code:
_x = theCamera->eye.x += (
    theCamera->c_eye.x * m[0] +
    theCamera->c_eye.y * m[4] +
    theCamera->c_eye.z * m[8]
);

And similarly for the other two lines.

I'd also recommend factoring out common mathematical operations such as the dot product, matrix multiplication, and so on, and making them separate functions (doing so will make your code easier to write, read, and debug). It also looks like you may be performing some Euler-angle conversions that aren't necessary; eliminating any such conversions would help simplify your code.
Quote this message in a reply
Moderator
Posts: 1,562
Joined: 2003.10
Nibbie
Posts: 4
Joined: 2009.10
Post: #4
_jyk_,
thank you for your answer

that would be look like:
Code:
// move left / right
_x = theCamera->eye.x += theCamera->c_eye.x * m[0]; // right vector
_y = theCamera->eye.y += theCamera->c_eye.y * m[1];
_z = theCamera->eye.z += theCamera->c_eye.z * m[2];

// move up / down
_x = theCamera->eye.x += theCamera->c_eye.x * m[4]; // up vector
_y = theCamera->eye.y += theCamera->c_eye.y * m[5];
_z = theCamera->eye.z += theCamera->c_eye.z * m[6];

// move forward / back
_x = theCamera->eye.x += theCamera->c_eye.x * m[8]; // forward vector
_y = theCamera->eye.y += theCamera->c_eye.y * m[9];
_z = theCamera->eye.z += theCamera->c_eye.z * m[10];

but it is just short; maybe my way is incorrect, I think, but there are no examples how to implement camera based on Euler;
by the way I prefer to compute complex matrix because it faster than "true" math function in general case;

ThemsAllTook,
thank you for link
Quote this message in a reply
Post Reply