Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Vectors and Matrices

This thread is locked; no one can reply to it. rss feed Print
Vectors and Matrices
Thomas Fjellstrom
Member #476
June 2000
avatar

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:

1class 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};
32Camera *Camera::instance = 0;
33 
34Vector Camera::pos = Vector(1,1,4);
35Vector Camera::vel = Vector(0.001,0,0.001);
36Vector Camera::front = Vector(1,0,0);
37Vector Camera::up = Vector(0,1,0);
38Vector Camera::right = Vector(0,0,1);
39 
40void 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[16] = {
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[0], &m[4], &m[8]
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) */
83void 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[3]; /* 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[0], &v[1], &v[2]);
90 front.x = v[0]; front.y = v[1]; front.z = v[2];
91}
92 
93 
94/* Steer up/down (+ve = up) */
95void 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[3] = {
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[0], v[1], v[2], dy);
106 apply_matrix_f (&m, front.x, front.y, front.z, &v[0], &v[1], &v[2]);
107 front.x = v[0]; front.y = v[1]; front.z = v[2];
108 
109 apply_matrix_f (&m, up.x, up.y, up.z, &v[0], &v[1], &v[2]);
110 up.x = v[0]; up.y = v[1]; up.z = v[2];
111}
112 
113 
114/* Twist (+ve = right/clockwise) */
115void 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[3]; /* 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[0], &v[1], &v[2]);
122 up.x = v[0]; up.y = v[1]; up.z = v[2];
123}
124 
125 
126 
127/* Move the camera. This is really simple now that we have front and up
128 * vectors already calculated. */
129void 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:

1double mod1 = 0.0015;
2double mod2 = 0.15;
3 
4int 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.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Archon
Member #4,195
January 2004
avatar

Is this camera rotation or camera movement? :)

[edit]
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
Member #476
June 2000
avatar

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:

1void 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[16] = {
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[16] = {
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[16] = {
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[16] = {
    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...

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Tobias Dammers
Member #2,604
August 2002
avatar

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.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Go to: