From 78b8585093ff1c19fabf0667e1a82822840234a3 Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Wed, 21 Sep 2022 17:39:37 +0200 Subject: [PATCH] Added some useful info on perspective transformations based on research. Also added a math source file with a custom rotation matrix routine, which isn't quite working as it should yet. --- CMakeLists.txt | 3 ++- main.c | 41 +++++++++++++++++++++++------------------ qmath.c | 34 ++++++++++++++++++++++++++++++++++ qmath.h | 8 ++++++++ 4 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 qmath.c create mode 100644 qmath.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 41d2d32..025b001 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,8 @@ project( HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk" ) -psn00bsdk_add_executable(template STATIC main.c) +file(GLOB _sources *.c) +psn00bsdk_add_executable(template STATIC ${_sources}) psn00bsdk_target_incbin(template PRIVATE mdl_player player.ps1mdl) psn00bsdk_target_incbin(template PRIVATE tim_player_f player_f.tim) diff --git a/main.c b/main.c index 3b1e2d5..9e538a4 100644 --- a/main.c +++ b/main.c @@ -25,6 +25,7 @@ #include #include #include "ps1mdl.h" +#include "qmath.h" #define OTLEN 1024 @@ -213,7 +214,7 @@ void init(void) FntLoad(960, 0); // Open up a test font text stream of 100 characters - FntOpen(0, 8, 320, 224, 0, 100); + FntOpen(0, 8, SCREENWIDTH, SCREENHEIGHT, 0, 200); nextpri = primbuff[0]; @@ -229,9 +230,13 @@ void init(void) loadModel(mdl_quaddama, &quadModel); loadSkin(tim_quaddama_f, tim_quaddama_b, &quadSkin); + // Perspective calculations are quite simple, with Go = GeomOffset and Gs = GeomScreen, view coordinates are transformed to screen coordinates as such: + // x' = vx * Gs / vz + Go.x + // y' = vy * Gs / vz + Go.y + // z' = (vz - 1) / 4 (depth does not appear to be affected by any parameters) InitGeom(); gte_SetGeomOffset(SCREENWIDTH >> 1, SCREENHEIGHT >> 1); - gte_SetGeomScreen(180); // Screen depth for FOV control. Essentially the Z position of the vanishing point. + gte_SetGeomScreen(180); // Screen depth for FOV control. Determines the distance of the camera to the near plane. // Set texture page for the entire drawing environment. Nice in some cases perhaps, but not what we need. //draw[0].tpage = getTPage(playerFrontTex.mode & 0x3, 0, playerFrontTex.prect->x, playerFrontTex.prect->y); @@ -415,7 +420,7 @@ void drawModel(MATRIX *view_matrix, ps1mdl_t *model, ps1skin_t *skin, int frameC // Model world position and rotation MATRIX model_mtx; - RotMatrix(&model->rotation, &model_mtx); + RotMatrixQ(&model->rotation, &model_mtx); TransMatrix(&model_mtx, &model->position); // Adjust light direction by the model's rotation relative to the world @@ -525,13 +530,6 @@ void drawStuff(int counter) { ClearOTagR(ot[db], OTLEN); - FntPrint(-1, "Image x %d y %d w %d h %d mode 0x%x\n", playerSkin.front.prect.x, playerSkin.front.prect.y, playerSkin.front.prect.w, playerSkin.front.prect.h, playerSkin.front.mode); - FntPrint(-1, "Model: %d tris, %d verts\n", playerModel.header->triangleCount, playerModel.header->vertexCount); - FntPrint(-1, "Trsf: (%d, %d, %d)\n", outPos.vx, outPos.vy, outPos.vz); - - // Draw the last created text stream - FntFlush(-1); - gte_SetBackColor(48, 48, 48); // Ambient light color gte_SetColorMatrix(&light_cols); // Light color (up to three different lights) @@ -541,7 +539,7 @@ void drawStuff(int counter) MATRIX view_matrix; SVECTOR trot = { -cam_rot.vx, -cam_rot.vy, -cam_rot.vz, 0 }; // Inverse camera rotation (in Quake coordinates) VECTOR tpos = { -cam_pos.vx, -cam_pos.vy, -cam_pos.vz }; // Inverse camera position (in Quake coordinates) - RotMatrix(&trot, &view_matrix); // Set camera rotation part of the view matrix + RotMatrixQ(&trot, &view_matrix); // Set camera rotation part of the view matrix ApplyMatrixLV(&view_matrix, &tpos, &tpos); // Apply camera rotation to camera position TransMatrix(&view_matrix, &tpos); // Apply transformed position to the translation part of the view matrix @@ -552,6 +550,13 @@ void drawStuff(int counter) drawModel(&view_matrix, &shamblerModel, &shamblerSkin, counter >> 2); //drawModel(&view_matrix, &ogreModel, &ogreSkin, counter >> 2); drawModel(&view_matrix, &quadModel, &quadSkin, 0); + + FntPrint(-1, "Camera pos = (%d, %d, %d) rot = (%d, %d, %d)\n", cam_pos.vx, cam_pos.vy, cam_pos.vz, cam_rot.vx, cam_rot.vy, cam_rot.vz); + FntPrint(-1, "Model: %d tris, %d verts\n", playerModel.header->triangleCount, playerModel.header->vertexCount); + FntPrint(-1, "Trsf: (%d, %d, %d)\n", outPos.vx, outPos.vy, outPos.vz); + + // Draw the last created text stream + FntFlush(-1); } void handleInput() @@ -566,19 +571,19 @@ void handleInput() // Determine direction vectors of the camera MATRIX cam_mtx; - RotMatrix(&cam_rot, &cam_mtx); + RotMatrixQ(&cam_rot, &cam_mtx); u_short buttons = *((u_short*)(padBuffer[0]+2)); if (!(buttons & PAD_UP)) { - // Move forward + // Move forward (+Y) cam_pos.vx += (cam_mtx.m[0][1] * moveSpeed) >> 12; cam_pos.vy += (cam_mtx.m[1][1] * moveSpeed) >> 12; cam_pos.vz += (cam_mtx.m[2][1] * moveSpeed) >> 12; } if (!(buttons & PAD_DOWN)) { - // Move backward + // Move backward (-Y) cam_pos.vx -= (cam_mtx.m[0][1] * moveSpeed) >> 12; cam_pos.vy -= (cam_mtx.m[1][1] * moveSpeed) >> 12; cam_pos.vz -= (cam_mtx.m[2][1] * moveSpeed) >> 12; @@ -595,28 +600,28 @@ void handleInput() } if (!(buttons & PAD_TRIANGLE)) { - // Move up + // Move up (+Z) cam_pos.vx += (cam_mtx.m[0][2] * moveSpeed) >> 12; cam_pos.vy += (cam_mtx.m[1][2] * moveSpeed) >> 12; cam_pos.vz += (cam_mtx.m[2][2] * moveSpeed) >> 12; } if (!(buttons & PAD_CROSS)) { - // Move down + // Move down (-Z) cam_pos.vx -= (cam_mtx.m[0][2] * moveSpeed) >> 12; cam_pos.vy -= (cam_mtx.m[1][2] * moveSpeed) >> 12; cam_pos.vz -= (cam_mtx.m[2][2] * moveSpeed) >> 12; } if (!(buttons & PAD_L1)) { - // Strafe left + // Strafe left (-X) cam_pos.vx -= (cam_mtx.m[0][0] * moveSpeed) >> 12; cam_pos.vy -= (cam_mtx.m[1][0] * moveSpeed) >> 12; cam_pos.vz -= (cam_mtx.m[2][0] * moveSpeed) >> 12; } if (!(buttons & PAD_R1)) { - // Strafe right + // Strafe right (+X) cam_pos.vx += (cam_mtx.m[0][0] * moveSpeed) >> 12; cam_pos.vy += (cam_mtx.m[1][0] * moveSpeed) >> 12; cam_pos.vz += (cam_mtx.m[2][0] * moveSpeed) >> 12; diff --git a/qmath.c b/qmath.c new file mode 100644 index 0000000..13e8b55 --- /dev/null +++ b/qmath.c @@ -0,0 +1,34 @@ +#include "qmath.h" + +MATRIX *RotMatrixQ(SVECTOR *r, MATRIX *m) +{ + short s[3],c[3]; + MATRIX tm[3]; + + s[0] = isin(r->vx); s[1] = isin(r->vy); s[2] = isin(r->vz); + c[0] = icos(r->vx); c[1] = icos(r->vy); c[2] = icos(r->vz); + + // mY (roll) + m->m[0][0] = c[1]; m->m[0][1] = 0; m->m[0][2] = s[1]; + m->m[1][0] = 0; m->m[1][1] = ONE; m->m[1][2] = 0; + m->m[2][0] = -s[1]; m->m[2][1] = 0; m->m[2][2] = c[1]; + + // mX (pitch) + tm[0].m[0][0] = ONE; tm[0].m[0][1] = 0; tm[0].m[0][2] = 0; + tm[0].m[1][0] = 0; tm[0].m[1][1] = c[0]; tm[0].m[1][2] = -s[0]; + tm[0].m[2][0] = 0; tm[0].m[2][1] = s[0]; tm[0].m[2][2] = c[0]; + + // mZ (yaw) + tm[1].m[0][0] = c[2]; tm[1].m[0][1] = -s[2]; tm[1].m[0][2] = 0; + tm[1].m[1][0] = s[2]; tm[1].m[1][1] = c[2]; tm[1].m[1][2] = 0; + tm[1].m[2][0] = 0; tm[1].m[2][1] = 0; tm[1].m[2][2] = ONE; + + PushMatrix(); + + MulMatrix0( m, &tm[1], &tm[2] ); + MulMatrix0( &tm[2], &tm[0], m ); + + PopMatrix(); + + return m; +} diff --git a/qmath.h b/qmath.h new file mode 100644 index 0000000..ec4c4dc --- /dev/null +++ b/qmath.h @@ -0,0 +1,8 @@ +#ifndef __QMATH_H__ +#define __QMATH_H__ + +#include + +MATRIX *RotMatrixQ(SVECTOR *r, MATRIX *m); + +#endif // __QMATH_H__