gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Troubles building a simple camera class

#46643 - connor9 - Tue Jun 28, 2005 4:08 pm

I'm trying to build a simple camera class. It's a simple camera that you can tell to move forward along it's viewing direction, roll, pitch and yaw along it's respective axes. The problem I'm running into is that as you use the camera the view volume becomes skewed, as if the directions that specify viewing direction, up and right are becoming non orthogonal. Printing out the dot product of each of these vectors confirms that the camera is slowly ruining it's vectors.

I assume it's a problem of data precision and that I'm probably using fixed point numbers completely incorrectly.

Here's the code to the simple camera class:

Code:

void Camera::setModelViewMatrix() {
    m4x4 viewMatrix;
   
    viewMatrix.m[0] = u[0];   
    viewMatrix.m[1] = v[0];
    viewMatrix.m[2] = n[0];
    viewMatrix.m[3] = CAM0;
    viewMatrix.m[4] = u[1];
    viewMatrix.m[5] = v[1];
    viewMatrix.m[6] = n[1];
    viewMatrix.m[7] = CAM0;
    viewMatrix.m[8] = u[2];
    viewMatrix.m[9] = v[2];
    viewMatrix.m[10] = n[2];
    viewMatrix.m[11] = CAM0;
    viewMatrix.m[12] = -dotf32(eye,u);
    viewMatrix.m[13] = -dotf32(eye,v);
    viewMatrix.m[14] = -dotf32(eye,n);
    viewMatrix.m[15] = CAM1;
   
    glLoadMatrix4x4(&viewMatrix);
}

void Camera::setView(f32 eye_in[3], f32 look_in[3], f32 up_in[3]) {
    eye[0] = eye_in[0];
    eye[1] = eye_in[1];
    eye[2] = eye_in[2];

    n[0] = eye[0] - look_in[0];
    n[1] = eye[1] - look_in[1];
    n[2] = eye[2] - look_in[2];
   
    crossf32(up_in,n,u);
    normalizef32(n);
    normalizef32(u);
   
    crossf32(n,u,v);
    setModelViewMatrix();
}


Set view is called to initialize the camera. Sort of an initial gluLookAt. Each frame various camera.roll(angle), camera.moveForward(distance) actions are called and the the matrix is loaded by calling camera.setModelViewMatrix(); Oh, it's not shown in the camera class but before setModelViewMatrix() is called the matrix stack is set to model view.

The following is only the roll implementation. As you roll the camera the dot product of u and v becomes non-zero.
Code:

void Camera::roll(int angle) {
    f32 sine = SIN[angle &  LUT_MASK];
    //f32 cosine = sqrtf32((CAM1 - sine2));   
    f32 cosine = COS[angle & LUT_MASK];

    f32 t[3];

    t[0] = u[0];
    t[1] = u[1];
    t[2] = u[2];
           
    u[0] = mulf32(cosine,t[0]) - mulf32(sine,v[0]);
    u[1] = mulf32(cosine,t[1]) - mulf32(sine,v[1]);
    u[2] = mulf32(cosine,t[2]) - mulf32(sine,v[2]);
       
    v[0] = mulf32(sine,t[0]) + mulf32(cosine,v[0]);
    v[1] = mulf32(sine,t[1]) + mulf32(cosine,v[1]);
    v[2] = mulf32(sine,t[2]) + mulf32(cosine,v[2]);
}

void Camera::moveForward(f32 distance) {    

    eye[0] += mulf32(distance,n[0]);
    eye[1] += mulf32(distance,n[1]);
    eye[2] += mulf32(distance,n[2]);

}


LUT_MASK is defined in camera.h
Code:

#define LUT_MASK (0x1FF)

CAM0 and CAM1 are defined as the 1.0 and 0.0 in a fixed point f32 number.

My question is how can I make this class work without warping the viewing parameters. Or what is a better method of implementing a camera class on the DS that still gives me easy access to my camera's current position and view vector?

Thanks!

#47066 - LunarCrisis - Mon Jul 04, 2005 7:11 pm

Although the imprecisions of the matrix variables is often negligible, as you repeatedly perform more and more operations on the matrix (as you are doing every time you move the camera), the error in the matrix elements keeps getting bigger, and you start getting these wierd effects. The only solution I can think of is to keep track of the position and angles (vertical, lateral, and roll) yourself and recalculate the matrix from scratch each time any of them changes.
_________________
If a tree falls in the forest and no one is there to hear it, why the heck do you care?

#47067 - tepples - Mon Jul 04, 2005 7:18 pm

Or you can do this occasionally:
  1. Calculate the forward and up vectors from the matrix.
  2. Make the forward vector into a unit vector.
  3. Make the up vector orthogonal by calculating the projection of the up vector onto the forward vector (which equals forward times (forward dot up)) and subtracting this from the up vector.
  4. Make the up vector into a unit vector.
  5. Calculate the matrix from the forward and up vectors.

_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#47072 - connor9 - Mon Jul 04, 2005 7:36 pm

Thanks tepples! That sent me on the right direction and I've got it fixed now.

Basically I reorthogonalize the matrix when the error reaches a certain threashhold. This value can be set.

Thanks for the help. Now that I've got this working I'll put it up here for anyone to modify and use. This is a basic camera class that let's you specify camera movement through the use of simple commands like pitch, yaw, and roll. Perfect for a flight simulator game which I noticed someone was interested in making.

http://connor.completelyfreehosting.com/tf/camera.zip

The camera class itself is fairly neat but the added matrix functions I made are really messy but they work. They just don't have good naming conventions or consistent use of returning a value through a pointer or as the return type. But it works well and could be of use to other people who want a simple class to drop in and fly about their world.

#47233 - corsec - Wed Jul 06, 2005 5:59 pm

connor9 wrote:
Perfect for a flight simulator game which I noticed someone was interested in making.


That would be me, and I will definitly look at your code.

However, I am currently working on the sprites, because that is a bit easier.
_________________
Currently working on a flight simulator set in 1916.
http://ucsub.colorado.edu/~hustvedt/ds.html