Vectors and Matrices
Thomas Fjellstrom

Ok. I've hacked together a little GL program (attached), my goal is to be able to "fly" around the "world" I've created, freely. Right now I'm stuck moving in tracks. I have only a basic understanding of the Matrix math included ("borrowed" it from a program of George Foot's).

I "think" I can get the movement I want by including the "vel" vector into the matrix equations somehow, but I'm not exactly sure how.

to build the program,
in unix: ./cbuild.c
in mingw: gcc cbuild.c -o cbuild.exe && cbuild.exe

It requires the latest AllegroGL CVS, and Allegro 4.2+.

edit, hmm, I realize some here may be a little lazy, so I'll post some of the relavant code:
Camera Class:

 1 class Camera { 2 public: 3 static Vector pos; 4 static Vector vel; 5 static Vector front; 6 static Vector right; 7 static Vector up; 8 9 static Camera *Instance() 10 { 11 if(!instance) { 12 instance = new Camera(); 13 } 14 return instance; 15 } 16 17 static void setup(); 18 static void Camera::move (double dx, double dy, double dz); 19 static void Camera::roll (double dz); 20 static void Camera::pitch (double dy); 21 static void Camera::yaw (double dx); 22 23 protected: 24 Camera() { } 25 Camera(const Camera&) {}; 26 Camera& operator= (const Camera&){}; 27 28 private: 29 static Camera *instance; 30 31 }; 32 Camera *Camera::instance = 0; 33 34 Vector Camera::pos = Vector(1,1,4); 35 Vector Camera::vel = Vector(0.001,0,0.001); 36 Vector Camera::front = Vector(1,0,0); 37 Vector Camera::up = Vector(0,1,0); 38 Vector Camera::right = Vector(0,0,1); 39 40 void Camera::setup() 41 { 42 Camera *cam = Instance(); 43 44 //Camera::pos += Camera::vel; //cam->right + cam->up + cam->vel; 45 46 glMatrixMode(GL_PROJECTION); 47 glLoadIdentity(); 48 gluPerspective((float)fov, aspect * 1.333333, 1.0, 1200.0); 49 glMatrixMode(GL_MODELVIEW); 50 glLoadIdentity(); 51 52 // Camera::front.Normalize(); 53 // Camera::right = Camera::front.Cross(Camera::up); 54 // Camera::up = Camera::right.Cross(Camera::front); 55 // Camera::up.Normalize(); 56 57 pos += vel; 58 59 /* Note: you have to write matrices transposed in C, for passing to OpenGL */ 60 GLfloat m = { 61 0, up.x, front.x, 0, 62 0, up.y, front.y, 0, 63 0, up.z, front.z, 0, 64 0, 0, 0, 1 65 }; 66 67 /* The right vector is the cross product of front with up -- store 68 * the result in the first row of the matrix. */ 69 cross_product_f ( 70 front.x, front.y, front.z, 71 up.x, up.y, up.z, 72 &m, &m, &m 73 ); 74 75 /* Assume MODELVIEW matrix already selected, and load our rotation */ 76 glLoadMatrixf (m); 77 /* Compose with the inverse of the translation to the camera's pos */ 78 79 glTranslatef (-pos.x, -pos.y, -pos.z); 80 } 81 82 /* Steer left/right (+ve = right) */ 83 void Camera::yaw (double dx) 84 { 85 /* Get rotation about the up vector, and apply it to the front vector */ 86 MATRIX_f m; 87 float v; /* temporary storage for result */ 88 get_vector_rotation_matrix_f (&m, up.x, up.y, up.z, -dx); 89 apply_matrix_f (&m, front.x, front.y, front.z, &v, &v, &v); 90 front.x = v; front.y = v; front.z = v; 91 } 92 93 94 /* Steer up/down (+ve = up) */ 95 void Camera::pitch (double dy) 96 { 97 /* Get rotation about the right vector, and apply it to both the others */ 98 MATRIX_f m; 99 /* v is doubling up as somewhere to store the right vector now */ 100 float v = { 101 up.z * front.y - up.y * front.z, 102 up.x * front.z - up.z * front.x, 103 up.y * front.x - up.x * front.y 104 }; 105 get_vector_rotation_matrix_f (&m, v, v, v, dy); 106 apply_matrix_f (&m, front.x, front.y, front.z, &v, &v, &v); 107 front.x = v; front.y = v; front.z = v; 108 109 apply_matrix_f (&m, up.x, up.y, up.z, &v, &v, &v); 110 up.x = v; up.y = v; up.z = v; 111 } 112 113 114 /* Twist (+ve = right/clockwise) */ 115 void Camera::roll (double dz) 116 { 117 /* Get rotation about the front vector, and apply it to the up vector */ 118 MATRIX_f m; 119 float v; /* temporary storage for result */ 120 get_vector_rotation_matrix_f (&m, front.x, front.y, front.z, dz); 121 apply_matrix_f (&m, up.x, up.y, up.z, &v, &v, &v); 122 up.x = v; up.y = v; up.z = v; 123 } 124 125 126 127 /* Move the camera. This is really simple now that we have front and up 128 * vectors already calculated. */ 129 void Camera::move (double dx, double dy, double dz) 130 { 131 right.x = up.z * front.y - up.y * front.z; 132 right.y = up.x * front.z - up.z * front.x; 133 right.z = up.y * front.x - up.x * front.y; 134 135 pos.x += dx*right.x + dy*up.x + dz*front.x; 136 pos.y += dx*right.y + dy*up.y + dz*front.y; 137 pos.z += dx*right.z + dy*up.z + dz*front.z; 138 }

Keyboard/Movement:

 1 double mod1 = 0.0015; 2 double mod2 = 0.15; 3 4 int do_keyboard() 5 { 6 Camera *cam = Camera::Instance(); 7 8 if(key[KEY_LEFT]) { 9 cam->vel -= Vector(0, 0, mod1);//.Normalize(); 10 } 11 if(key[KEY_RIGHT]) { 12 cam->vel += Vector(0, 0, mod1);//.Normalize(); 13 } 14 if(key[KEY_DOWN]) { 15 cam->vel += Vector(mod1, 0, 0);//.Normalize(); 16 } 17 if(key[KEY_UP]) { 18 cam->vel -= Vector(mod1, 0, 0);//.Normalize(); 19 } 20 21 22 if(key[KEY_W]) { 23 Camera::pitch(-mod2); 24 } 25 if(key[KEY_S]) { 26 Camera::pitch(mod2); 27 } 28 if(key[KEY_A]) { 29 Camera::yaw(-mod2); 30 } 31 if(key[KEY_D]) { 32 Camera::yaw(mod2); 33 } 34 35 36 if (key[KEY_1]) { 37 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); 38 } 39 if(key[KEY_2]) 40 { 41 glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); 42 } 43 return 0; 44 }

Now, it could be just me, but theres got to be a way to include the "pos+vel" into the matrix calculations in Camera::setup.

edit2, 5+ hours and nothing? Thanks guys.

Archon

Is this camera rotation or camera movement? Perhaps you could use sin/cos when you rotate the camera.

I have to go out now but perhaps drawing what you want to happen then connecting the patterns would help you form an idea of what you need to do.
Though do the example using only 2 dimensions first.

^ Disregard that if it doesn't help you at all. Thomas Fjellstrom

Thanks Archon. Its both really.

I want to properly move through a 3d environment with all 360 degrees of freedom.

I've attempted to modify my camera update to the following, but it seems I've got something totally wrong about the gl matrices:

 1 void Camera::setup() 2 { 3 Camera *cam = Instance(); 4 5 //Camera::pos += Camera::vel; //cam->right + cam->up + cam->vel; 6 7 glMatrixMode(GL_PROJECTION); 8 glLoadIdentity(); 9 gluPerspective((float)fov, aspect * 1.333333, 1.0, 1200.0); 10 glMatrixMode(GL_MODELVIEW); 11 glLoadIdentity(); 12 13 // Camera::front.Normalize(); 14 // Camera::right = Camera::front.Cross(Camera::up); 15 // Camera::up = Camera::right.Cross(Camera::front); 16 // Camera::up.Normalize(); 17 18 pos += vel; 19 pos.Normalize(); 20 21 /* The right vector is the cross product of front with up -- store 22 * the result in the first row of the matrix. */ 23 24 right = front.Cross(up); 25 26 /* Note: you have to write matrices transposed in C, for passing to OpenGL */ 27 GLfloat mat1 = { 28 right.x, up.x, front.x, 0, 29 right.y, up.y, front.y, 0, 30 right.z, up.z, front.z, 0, 31 0, 0, 0, 1 32 }; 33 34 GLfloat mat2 = { 35 1, 0, 0, pos.x, 36 0, 1, 0, pos.y, 37 0, 0, 1, pos.z, 38 0, 0, 0, 1 39 }; 40 41 GLfloat mat = { 42 0, 0, 0, 0, 43 0, 0, 0, 0, 44 0, 0, 0, 0, 45 0, 0, 0, 0 46 }; 47 48 #define MAT(m,r,c) (m)[(c)*4+(r)] 49 #define MMUL(a,b,c,d) (MAT(mat1, a, b) * MAT(mat2, c, d)) 50 51 52 MAT(mat, 0, 0) = MMUL(0, 0, 0, 0) + MMUL(0, 1, 1, 0) + MMUL(0, 2, 2, 0) + MMUL(0, 3, 3, 0); 53 MAT(mat, 0, 1) = MMUL(0, 0, 0, 1) + MMUL(0, 1, 1, 1) + MMUL(0, 2, 2, 1) + MMUL(0, 3, 3, 1); 54 MAT(mat, 0, 2) = MMUL(0, 0, 0, 2) + MMUL(0, 1, 1, 2) + MMUL(0, 2, 2, 2) + MMUL(0, 3, 3, 2); 55 MAT(mat, 0, 3) = MMUL(0, 0, 0, 3) + MMUL(0, 1, 1, 3) + MMUL(0, 2, 2, 3) + MMUL(0, 3, 3, 3); 56 57 MAT(mat, 1, 0) = MMUL(1, 0, 0, 0) + MMUL(1, 1, 1, 0) + MMUL(1, 2, 2, 0) + MMUL(1, 3, 3, 0); 58 MAT(mat, 1, 1) = MMUL(1, 0, 0, 1) + MMUL(1, 1, 1, 1) + MMUL(1, 2, 2, 1) + MMUL(1, 3, 3, 1); 59 MAT(mat, 1, 2) = MMUL(1, 0, 0, 2) + MMUL(1, 1, 1, 2) + MMUL(1, 2, 2, 2) + MMUL(1, 3, 3, 2); 60 MAT(mat, 1, 3) = MMUL(1, 0, 0, 3) + MMUL(1, 1, 1, 3) + MMUL(1, 2, 2, 3) + MMUL(1, 3, 3, 3); 61 62 MAT(mat, 2, 0) = MMUL(2, 0, 0, 0) + MMUL(2, 1, 1, 0) + MMUL(2, 2, 2, 0) + MMUL(2, 3, 3, 0); 63 MAT(mat, 2, 1) = MMUL(2, 0, 0, 1) + MMUL(2, 1, 1, 1) + MMUL(2, 2, 2, 1) + MMUL(2, 3, 3, 1); 64 MAT(mat, 2, 2) = MMUL(2, 0, 0, 2) + MMUL(2, 1, 1, 2) + MMUL(2, 2, 2, 2) + MMUL(2, 3, 3, 2); 65 MAT(mat, 2, 3) = MMUL(2, 0, 0, 3) + MMUL(2, 1, 1, 3) + MMUL(2, 2, 2, 3) + MMUL(2, 3, 3, 3); 66 67 MAT(mat, 3, 0) = MMUL(3, 0, 0, 0) + MMUL(3, 1, 1, 0) + MMUL(3, 2, 2, 0) + MMUL(3, 3, 3, 0); 68 MAT(mat, 3, 1) = MMUL(3, 0, 0, 1) + MMUL(3, 1, 1, 1) + MMUL(3, 2, 2, 1) + MMUL(3, 3, 3, 1); 69 MAT(mat, 3, 2) = MMUL(3, 0, 0, 2) + MMUL(3, 1, 1, 2) + MMUL(3, 2, 2, 2) + MMUL(3, 3, 3, 2); 70 MAT(mat, 3, 3) = MMUL(3, 0, 0, 3) + MMUL(3, 1, 1, 3) + MMUL(3, 2, 2, 3) + MMUL(3, 3, 3, 3); 71 72 //glTranslatef (-pos.x, -pos.y, -pos.z); 73 glLoadMatrixf (mat); 74 75 /* Assume MODELVIEW matrix already selected, and load our rotation */ 76 77 }

What exactly am I doing wrong? I want the camera to be able to fly around as if it were, say a space ship, or a plane, in and arround the cubes and whatnot.

edit, KittyCat has given me one fix:

```  GLfloat mat2 = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
pos.x, pos.y, pos.z, 1
};
```

It helps a little, but now the arrow keys cause the camera's position to slowly rotate around its pos.

edit2, I've commended the pos.Normalize(); and its going better.

edit3, Now, the camera doesn't move in the direction of the direction vectors...

Tobias Dammers

I usually store both rotation and position together in a struct (a class actually), and each as a vector, where the rotation vector indicates axis (the vector's direction) and angle (its length). This "position" struct can be used both for objects and for cameras. To activate it as a drawing offset (as an object position), do a glRotate() first, then a glTranslate(). To use as a camera, you do the translate first and with opposite signs, then the rotate, also with opposite signs.
To make the camera move, you'll need the front vector, which is a bit trickier using this approach. You can use the matrix sample code that comes with the gl documentation, or rip code from allegro, to convert the rotation angle into a matrix. Then all you need to do is use the appropriate row (or column? can't seem to remember) as front vector.
You won't need to know a lot more about matrix math than this, but it helps to think of a matrix as a local coordinate system with 4 vectors (x, y, z, w), that describe 3 axes and an origin (w). Multiplying a vector by a matrix means taking a local vector and calculating its position in absolute (real-world) space. Matrix multiplication means nesting several of these coordinate systems, and the resulting matrix can be used to transform directly from the innermost coordinate system to world-space.