Allegro.cc Forums » Programming Questions » First person camera using transformations

Credits go to Edgar Reynaldo for helping out!
 This thread is locked; no one can reply to it.
 First person camera using transformations
 DontKnow3D Member #16,883 July 2018 i have tried to implement a first person camera, but as you might guess: It don't work. everything works fine in the whole 3d department of my code, except for the camera. if you look forwards everything works, but if you look 90 degrees to the side instead of the camera looking up and down when you move the mouse it spins in a circle and if you look 180 degrees behind yourself the camera is inverted. how do i fix this? i have tried many different formulas but none of them work.mouse processing: #SelectExpand 1switch (ev.type) { 2 case ALLEGRO_EVENT_MOUSE_AXES: 3 p.m.x += ev.mouse.dx; 4 p.m.y += ev.mouse.dy; 5 p.m.ax = p.m.x / MOUSE_SPEED;//angle x: 1 rotation = 2*PI 6 p.m.ay = p.m.y / -MOUSE_SPEED;//angle y: goes from -PI/2 to PI/2 7 al_set_mouse_xy(display, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2); 8 if (p.m.ay > PI / 2) { 9 p.m.ay = PI / 2; 10 p.m.y = ((PI / 2)*-MOUSE_SPEED); 11 } 12 if (p.m.ay < -PI / 2) { 13 p.m.ay = -PI / 2; 14 p.m.y = ((-PI / 2)*-MOUSE_SPEED); 15 } 16//------------------------------------------------ 17//----------calculate camera rotation------------- 18//------------------------------------------------ 19//-------------how do i do this?------------------ 20//------------------------------------------------ 21 p.m.cax = p.m.ay; 22 p.m.cay = p.m.ax; 23 p.m.caz = 0; 24 25 /*p.m.cax = cos(p.m.ax) * cos(p.m.ay)*PI; 26 p.m.cay = sin(p.m.ay)*PI; 27 p.m.caz = sin(p.m.ax) * cos(p.m.ay)*PI;*/ 28 break; camera transformation code:#SelectExpand 1 al_identity_transform(&tra); 2 al_translate_transform_3d(&tra, p.x, p.y, p.z); 3 al_rotate_transform_3d(&tra, 1, 0, 0, p.m.cax); 4 al_rotate_transform_3d(&tra, 0, 1, 0, p.m.cay); 5 al_rotate_transform_3d(&tra, 0, 0, 1, p.m.caz); 6 al_perspective_transform(&tra, -SCREEN_WIDTH / 2, -SCREEN_HEIGHT / 2, 1000, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 100000); 7 al_use_projection_transform(&tra); 8 9 al_flip_display(); whole code:#SelectExpand 1#include 2#include 3#include 4#include 5#include 6#include 7#include 8 9 10#define LOOP(var,max) for(var=0;var PI / 2) { 159 p.m.ay = PI / 2; 160 p.m.y = ((PI / 2)*-MOUSE_SPEED); 161 } 162 if (p.m.ay < -PI / 2) { 163 p.m.ay = -PI / 2; 164 p.m.y = ((-PI / 2)*-MOUSE_SPEED); 165 } 166//------------------------------------------------ 167//----------calculate camera rotation------------- 168//------------------------------------------------ 169//-------------how do i do this?------------------ 170//------------------------------------------------ 171 p.m.cax = p.m.ay; 172 p.m.cay = p.m.ax; 173 p.m.caz = 0; //ev.mouse.z / 100.; 174 175 /*p.m.cax = cos(p.m.ax) * cos(p.m.ay)*PI; 176 p.m.cay = sin(p.m.ay)*PI; 177 p.m.caz = sin(p.m.ax) * cos(p.m.ay)*PI;*/ 178 179 break; 180 case ALLEGRO_EVENT_TIMER: 181 //key input 182 process_keyboard(p); 183 184 //clear display 185 al_clear_to_color(al_map_rgb_f(0.5, 0.5, 0.5)); 186 al_clear_depth_buffer(10000); 187 188 //draw the normalized angles (floating text around you) (2*PI = 1) 189 al_identity_transform(&tra); 190 al_translate_transform_3d(&tra, -p.x, -p.y, -p.z - 2000); 191 al_use_transform(&tra); 192 LOOP(j, 12) { 193 al_rotate_transform_3d(&tra, 0, 1, 0, PI / 6); 194 LOOP(i, 12) { 195 al_rotate_transform_3d(&tra, 1, 0, 0, PI / 6); 196 al_use_transform(&tra); 197 al_draw_multiline_textf(font, al_map_rgb_f(0, 1, 0.5), 50, 50, 0, 0, 0, "ax_%.4f ay_%.4f cax_%.4f cay_%.4f caz_%.4f", p.m.ax / PI / 2, p.m.ay / PI / 2, p.m.cax / PI / 2, p.m.cay / PI / 2, p.m.caz / PI / 2); 198 } 199 } 200 //draw the ground 201 al_identity_transform(&tra); 202 al_scale_transform_3d(&tra, 10, 0, 10); 203 al_translate_transform_3d(&tra, 0, 6000, 0); 204 al_use_transform(&tra); 205 al_draw_prim(ground, NULL, image, 0, 6, ALLEGRO_PRIM_TRIANGLE_LIST); 206 207 //draw the 5 floating cubes 208 al_identity_transform(&tra); 209 al_translate_transform_3d(&tra, 0, 0, -4000); 210 al_use_transform(&tra); 211 al_draw_prim(cube, NULL, NULL, 0, sizeof(cube) / sizeof(cube[0]), ALLEGRO_PRIM_TRIANGLE_LIST); 212 al_translate_transform_3d(&tra, 0, 5000, 0); 213 al_use_transform(&tra); 214 al_draw_prim(cube, NULL, NULL, 0, sizeof(cube) / sizeof(cube[0]), ALLEGRO_PRIM_TRIANGLE_LIST); 215 al_translate_transform_3d(&tra, 5000, -5000, 5000); 216 al_use_transform(&tra); 217 al_draw_prim(cube, NULL, NULL, 0, sizeof(cube) / sizeof(cube[0]), ALLEGRO_PRIM_TRIANGLE_LIST); 218 al_translate_transform_3d(&tra, -5000, -5000, 5000); 219 al_use_transform(&tra); 220 al_draw_prim(cube, NULL, NULL, 0, sizeof(cube) / sizeof(cube[0]), ALLEGRO_PRIM_TRIANGLE_LIST); 221 al_translate_transform_3d(&tra, -5000, 5000, 5000); 222 al_use_transform(&tra); 223 al_draw_prim(cube, NULL, NULL, 0, sizeof(cube) / sizeof(cube[0]), ALLEGRO_PRIM_TRIANGLE_LIST); 224 225 //do the camera transforms 226 al_identity_transform(&tra); 227 al_translate_transform_3d(&tra, p.x, p.y, p.z); 228 al_rotate_transform_3d(&tra, 1, 0, 0, p.m.cax); 229 al_rotate_transform_3d(&tra, 0, 1, 0, p.m.cay); 230 al_rotate_transform_3d(&tra, 0, 0, 1, p.m.caz); 231 al_perspective_transform(&tra, -SCREEN_WIDTH / 2, -SCREEN_HEIGHT / 2, 1000, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 100000); 232 al_use_projection_transform(&tra); 233 234 al_flip_display(); 235 break; 236 } 237 } 238} (and i also cant manage to figure out how to draw a 'hud' or just simple things right on the display after the transformations)
 Edgar Reynaldo Major Reynaldo May 2007 You have to understand there are two matrices involved. The projection matrix, and the view matrix. You're mixing the two, and you still aren't even trying to do what I showed you in the other thread.https://www.allegro.cc/forums/thread/617512/1038669#targetAlso, you are mixing 2D and 3D drawing without resetting your projection matrices properly.You should read over the manual entry for transformations.https://liballeg.org/a5docs/trunk/transformations.htmlSpecifically, look at the docs for al_build_camera_transform , al_orthographic_transform, and al_perspective_transform.For 2D you use the orthographic transform for the projection matrix. For 3D you use the perspective transform for the projection matrix. For 2D view matrix, all you need is the identity. For 3D, you need to apply a camera transform to the view matrix.First, see https://liballeg.org/a5docs/trunk/transformations.html#al_use_projection_transform for the difference between 2D and 3D projection matrices.Second, see https://liballeg.org/a5docs/trunk/transformations.html#al_build_camera_transform for how to set up your camera. As I told you before, you need to use a forward, right, and up vector to define the orientation of the camera. You also need a position for the camera. Then the lookAt parameter becomes camera.position + forward_vector.EDITYou can also 'cheat' and calculate the look vector yourself using a little trig.The compass heading becomes the rotation around the y-axis on the xz plane. ``` +Y -Z | / | / | / -X_____|/____ +X /| / | / | +Z -Y ``` And then the pitch become the rotation around the right vector. ```double heading = atan2(-dz,dx); double pitch = acos((dist(xz)/dist(xyz)); ``` I think that's right but I'm tired.
 DontKnow3D Member #16,883 July 2018 OK so; I have majorly rewritten how everything about my perspective/transformation/drawing works. I now first generate 1 mesh, where everything 3d is stored and then draw all of that at once to the screen. 2d operations work now too and i think i have gotten a much better grasp on how the perspective transformations work. i now also use the camera transformation. the only thing that doesent work now is: the camera. I think I'm using the camera correctly, but apparently I'm not. and if you see anything I'm doing wrong now with the transformations, pleas tell me.#SelectExpand 1#include 2#include 3#include 4#include 5#include 6#include 7#include 8#include 9#include 10 11#define FOV (PI/2) //90 degrees (vertical not horizontal) 12 13#define KD(keycode) al_key_down(&key,ALLEGRO_KEY_##keycode) 14#define LOOP(var,max) for(var=0;var PI / 2) { 211 p.m.ay = PI / 2; 212 p.m.y = ((PI / 2)*-MOUSE_SPEED); 213 } 214 if (p.m.ay < -PI / 2) { 215 p.m.ay = -PI / 2; 216 p.m.y = ((-PI / 2)*-MOUSE_SPEED); 217 }*/ 218 219//--------------camera calculations---------------- 220 p.m.cax = cos(p.m.ay)*sin(p.m.ax); 221 p.m.cay = cos(p.m.ay)*cos(p.m.ax); 222 p.m.caz = sin(p.m.ay); 223 224 std::cout << "cax=" << p.m.cax << '\t' << "cay=" << p.m.cay << '\t' << "caz=" << p.m.caz << '\t' << std::endl; 225 break; 226 case ALLEGRO_EVENT_TIMER: 227 //key input 228 process_keyboard(p); 229 230 curprotra = *al_get_current_projection_transform(); 231 setup_3d_projection(); 232 233 al_clear_to_color(al_map_rgb_f(0.5, 0.5, 0.5)); 234 al_set_render_state(ALLEGRO_DEPTH_TEST, 1); 235 al_clear_depth_buffer(1); 236 237// ----------------camera transform--------------- 238 al_build_camera_transform(&cam, p.x, p.y, p.z, 239 p.x + p.m.cax, p.y + p.m.cay, p.z + p.m.caz, 240 0, 1, 0); 241 al_use_transform(&cam); 242 //draw 3d things 243 al_draw_prim(mesh.mesh, NULL, NULL, 0, mesh.size_of_mesh, ALLEGRO_PRIM_TRIANGLE_LIST); 244 245 //restore projection 246 al_identity_transform(&tra); 247 al_use_transform(&tra); 248 al_use_projection_transform(&curprotra); 249 al_set_render_state(ALLEGRO_DEPTH_TEST, 0); 250 251 //draw 2d things 252 al_draw_multiline_textf(font, al_map_rgb_f(0.8, 0.1, 0.2), 50, 50, 0, 0, 0, "normalized(2PI=1) ax_%.4f ay_%.4f not_normalized cax_%.4f cay_%.4f caz_%.4f", p.m.ax / PI / 2, p.m.ay / PI / 2, p.m.cax, p.m.cay, p.m.caz); 253 al_flip_display(); 254 break; 255 } 256 } 257}
 Edgar Reynaldo Major Reynaldo May 2007 I think your formula is just a bit off. You have z and y reversed. It should be :``` fw.x = cos(pitch)*cos(yaw); fw.z = cos(pitch)*-sin(yaw); fw.y = sin(pitch); ``` {"name":"611674","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/4\/94b598fff0562e56a5c7bf072c62b984.png","w":800,"h":600,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/4\/94b598fff0562e56a5c7bf072c62b984"}Or you can build your forward vector using transforms : #SelectExpand 1 void RebuildTransform() { 2 fw = Vec(0,0,-1); 3 rt = Vec(1,0,0); 4 up = Vec(0,1,0); 5 /// Apply yaw 6 ALLEGRO_TRANSFORM t1; 7 al_identity_transform(&t1); 8 al_rotate_transform(&t1 , up.x , up.y , up.z , yaw); 9 al_transform_coordinates(&t1 , &rt.x , &rt.y , &rt.z); 10 al_transform_coordinates(&t1 , &fw.x , &fw.y , &fw.z); 11 12 /// Apply pitch 13 al_identity_transform(&t1); 14 al_rotate_transform(&t1 , rt.x , rt.y , rt.z , yaw); 15 al_transform_coordinates(&t1 , &up.x , &up.y , &up.z); 16 al_transform_coordinates(&t1 , &fw.x , &fw.y , &fw.z); 17 18 /// Apply roll 19 //... 20 Vec look = pos + fw; 21 al_build_camera_transform(&t , pos.x , pos.y , pos.z , look.x , look.y , look.z , up.x , up.y , up.z); 22 }
 DontKnow3D Member #16,883 July 2018 ok thank you! you've been a great help in all of this. there is just 1 more thing id like to figure out. in my code right after i use the camera transformation, i draw the whole map mesh. now i would like to also draw other things and use transformations on them. but if i trie to do that, it doesent really work. the things i draw after the new transformations move with the camera rotation. how would i fix that? #SelectExpand 1// ----------------camera transform--------------- 2 al_build_camera_transform(&cam, p.x, p.y, p.z, 3 p.x + p.m.cax, p.y + p.m.cay, p.z + p.m.caz, 4 0, 1, 0); 5 al_use_transform(&cam); 6 7 //draw 3d things 8 al_draw_prim(mesh.mesh, NULL, NULL, 0, mesh.size_of_mesh, ALLEGRO_PRIM_TRIANGLE_LIST);//drawing the mesh as before 9 10//now draw an extra cube 3 units below 0,0,0 11 ALLEGRO_TRANSFORM copy_of_cam, transform; 12 al_identity_transform(&transform); 13 al_copy_transform(©_of_cam, &cam); 14 15 al_translate_transform_3d(&transform,0, -3, 0); 16 al_compose_transform(©_of_cam, &transform); 17 al_use_transform(©_of_cam); 18 19 al_draw_prim(cube, NULL, NULL, 0, std::size(cube), ALLEGRO_PRIM_TRIANGLE_LIST); 20 21 //restore projection 22 //...
 Edgar Reynaldo Major Reynaldo May 2007 You need to transform your objects first, before applying the camera transform.Do the same thing, but swap the order.```ALLEGRO_TRANSFORM t; al_identity_transform(&t); al_translate_transform(&t , 0 , -3 , 0); al_compose_transform(&t , &cam); al_use_transform(&t); ```
 DontKnow3D Member #16,883 July 2018 thank you! you've been a great help!if anybody wants the full source code:https://github.com/dontknow3d/fps-camera-using-allegro-5
 Go to: Allegro Development Installation, Setup & Configuration Allegro.cc Comments Off-Topic Ordeals The Depot Game Design & Concepts Programming Questions Recent Threads