From ef22869e48f5cc403cb05d6f8f84be11db966228 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Tue, 25 Apr 2023 19:52:54 -0500 Subject: [PATCH] rendering works :) --- assignment-2b/make_statements.py | 26 +++ assignment-2b/src/main.cpp | 320 ++++++++++++++++++++++++++++--- flake.nix | 1 + 3 files changed, 321 insertions(+), 26 deletions(-) create mode 100644 assignment-2b/make_statements.py diff --git a/assignment-2b/make_statements.py b/assignment-2b/make_statements.py new file mode 100644 index 000000000..356c7ff --- /dev/null +++ b/assignment-2b/make_statements.py @@ -0,0 +1,26 @@ +def mkslot(m, i, j): + ij = j + i * 4 + return f"{m}[{ij}]" + # return m + "xyzw"[i] + str(j + 1) + +def mm(leftcalled = "l", rightcalled = "r"): + stmts = [] + + for i in range(4): + for j in range(4): + res = mkslot("m", i, j) + terms = [] + + for k in range(4): + left = mkslot(leftcalled, i, k) + right = mkslot(rightcalled, k, j) + + term = f"{left} * {right}" + terms.append(term) + + stmt = f"{res} = {' + '.join(terms)};" + stmts.append(stmt) + + return "\n".join(stmts) + +print(mm()) diff --git a/assignment-2b/src/main.cpp b/assignment-2b/src/main.cpp index 4e21f3c..0b5f50f 100755 --- a/assignment-2b/src/main.cpp +++ b/assignment-2b/src/main.cpp @@ -10,41 +10,72 @@ #include "shader.hpp" #include "trimesh.hpp" #include // memcpy +#include // Constants #define WIN_WIDTH 500 #define WIN_HEIGHT 500 +#define PI 3.1415926535 class Mat4x4 { public: float m[16]; - // clang-format off - Mat4x4(){ // Default: Identity + // Default: Identity + Mat4x4() { + // clang-format off m[0] = 1.f; m[4] = 0.f; m[8] = 0.f; m[12] = 0.f; m[1] = 0.f; m[5] = 1.f; m[9] = 0.f; m[13] = 0.f; m[2] = 0.f; m[6] = 0.f; m[10] = 1.f; m[14] = 0.f; m[3] = 0.f; m[7] = 0.f; m[11] = 0.f; m[15] = 1.f; + // clang-format on } - // clang-format on - // clang-format off - void make_identity(){ + void make_identity() { + // clang-format off m[0] = 1.f; m[4] = 0.f; m[8] = 0.f; m[12] = 0.f; m[1] = 0.f; m[5] = 1.f; m[9] = 0.f; m[13] = 0.f; m[2] = 0.f; m[6] = 0.f; m[10] = 1.f; m[14] = 0.f; m[3] = 0.f; m[7] = 0.f; m[11] = 0.f; m[15] = 1.f; + // clang-format on } - // clang-format on - // clang-format off - void print(){ + void zero() { + // clang-format off + m[0] = 0.0; m[4] = 0.0; m[8] = 0.0; m[12] = 0.0; + m[1] = 0.0; m[5] = 0.0; m[9] = 0.0; m[13] = 0.0; + m[2] = 0.0; m[6] = 0.0; m[10] = 0.0; m[14] = 0.0; + m[3] = 0.0; m[7] = 0.0; m[11] = 0.0; m[15] = 0.0; + // clang-format on + } + + void transpose() { + // 0 1 2 3 + // 4 5 6 7 + // 8 9 10 11 + // 12 13 14 15 + swap(&m[1], &m[4]); + swap(&m[2], &m[8]); + swap(&m[3], &m[12]); + swap(&m[6], &m[9]); + swap(&m[7], &m[13]); + swap(&m[11], &m[14]); + } + + static void swap(float *a, float *b) { + float tmp = *a; + *a = *b; + *b = tmp; + } + + void print() { + // clang-format off std::cout << m[0] << ' ' << m[4] << ' ' << m[8] << ' ' << m[12] << "\n"; std::cout << m[1] << ' ' << m[5] << ' ' << m[9] << ' ' << m[13] << "\n"; std::cout << m[2] << ' ' << m[6] << ' ' << m[10] << ' ' << m[14] << "\n"; std::cout << m[3] << ' ' << m[7] << ' ' << m[11] << ' ' << m[15] << "\n"; + // clang-format on } - // clang-format on void make_scale(float x, float y, float z) { make_identity(); @@ -52,6 +83,33 @@ public: m[5] = y; m[10] = z; } + + inline Mat4x4 operator*(const Mat4x4 &right) { + Mat4x4 result; + auto l = this->m; + auto r = right.m; + auto m = result.m; + + // Generated by make_statements.py + m[0] = l[0] * r[0] + l[1] * r[4] + l[2] * r[8] + l[3] * r[12]; + m[1] = l[0] * r[1] + l[1] * r[5] + l[2] * r[9] + l[3] * r[13]; + m[2] = l[0] * r[2] + l[1] * r[6] + l[2] * r[10] + l[3] * r[14]; + m[3] = l[0] * r[3] + l[1] * r[7] + l[2] * r[11] + l[3] * r[15]; + m[4] = l[4] * r[0] + l[5] * r[4] + l[6] * r[8] + l[7] * r[12]; + m[5] = l[4] * r[1] + l[5] * r[5] + l[6] * r[9] + l[7] * r[13]; + m[6] = l[4] * r[2] + l[5] * r[6] + l[6] * r[10] + l[7] * r[14]; + m[7] = l[4] * r[3] + l[5] * r[7] + l[6] * r[11] + l[7] * r[15]; + m[8] = l[8] * r[0] + l[9] * r[4] + l[10] * r[8] + l[11] * r[12]; + m[9] = l[8] * r[1] + l[9] * r[5] + l[10] * r[9] + l[11] * r[13]; + m[10] = l[8] * r[2] + l[9] * r[6] + l[10] * r[10] + l[11] * r[14]; + m[11] = l[8] * r[3] + l[9] * r[7] + l[10] * r[11] + l[11] * r[15]; + m[12] = l[12] * r[0] + l[13] * r[4] + l[14] * r[8] + l[15] * r[12]; + m[13] = l[12] * r[1] + l[13] * r[5] + l[14] * r[9] + l[15] * r[13]; + m[14] = l[12] * r[2] + l[13] * r[6] + l[14] * r[10] + l[15] * r[14]; + m[15] = l[12] * r[3] + l[13] * r[7] + l[14] * r[11] + l[15] * r[15]; + + return result; + } }; static inline const Vec3f operator*(const Mat4x4 &m, const Vec3f &v) { @@ -71,6 +129,38 @@ float aspect; GLuint verts_vbo[1], colors_vbo[1], normals_vbo[1], faces_ibo[1], tris_vao; TriMesh mesh; +// In world coordinates +Vec3f eye_pos(0., 0., 0.); +Vec3f eye_dir; +float view_angle = 0.0f; +Vec3f up_dir(0., -1., 0.); + +namespace viewing_window { + +// - center = (0,0,0) +// - height: 30.6 +// - length: 40.3 +// - width: 17.0 +float val = 50.0; +float near = -1000.0, far = val; +float left = -val, right = val; +float bottom = -val, top = val; + +const auto WIDTH_ZOOM = 1.0 / 30.0, HEIGHT_ZOOM = 1.0 / 30.0; +const float MOVE_BY = 0.25; // 0.75 is actually really fast? +const float ANGLE_BY = 0.05; + +float horizontal_fov = 1.0, vertical_fov = 1.0; + +} // namespace viewing_window + +namespace controls { +bool is_left_held = false, is_right_held = false, is_up_held = false, + is_down_held = false; +bool is_raise_held = false, is_lower_held = false; +bool is_spin_left_held = false, is_spin_right_held = false; +} // namespace controls + // Model, view and projection matrices, initialized to the identity Mat4x4 model; // not used in this assignment; included for completeness only Mat4x4 view; @@ -90,27 +180,63 @@ static void key_callback(GLFWwindow *window, int key, int scancode, int action, if (action == GLFW_PRESS) { switch (key) { case GLFW_KEY_ESCAPE: - glfwSetWindowShouldClose(window, GL_TRUE); - break; case GLFW_KEY_Q: glfwSetWindowShouldClose(window, GL_TRUE); break; - // ToDo: update the viewing transformation matrix according to key presses } } + + { + using namespace Globals::controls; + if (key == GLFW_KEY_W) + is_up_held = action == GLFW_PRESS || action == GLFW_REPEAT; + + if (key == GLFW_KEY_A) + is_left_held = action == GLFW_PRESS || action == GLFW_REPEAT; + + if (key == GLFW_KEY_S) + is_down_held = action == GLFW_PRESS || action == GLFW_REPEAT; + + if (key == GLFW_KEY_D) + is_right_held = action == GLFW_PRESS || action == GLFW_REPEAT; + + if (key == GLFW_KEY_LEFT_BRACKET) + is_raise_held = action == GLFW_PRESS || action == GLFW_REPEAT; + + if (key == GLFW_KEY_RIGHT_BRACKET) + is_lower_held = action == GLFW_PRESS || action == GLFW_REPEAT; + + if (key == GLFW_KEY_J || key == GLFW_KEY_LEFT) + is_spin_left_held = action == GLFW_PRESS || action == GLFW_REPEAT; + + if (key == GLFW_KEY_L || key == GLFW_KEY_RIGHT) + is_spin_right_held = action == GLFW_PRESS || action == GLFW_REPEAT; + } } static void framebuffer_size_callback(GLFWwindow *window, int width, int height) { - Globals::win_width = float(width); - Globals::win_height = float(height); - Globals::aspect = Globals::win_width / Globals::win_height; + using namespace Globals; + using namespace Globals::viewing_window; + + win_width = float(width); + win_height = float(height); + aspect = win_width / win_height; glViewport(0, 0, width, height); // ToDo: update the perspective matrix as the window size changes + // printf("Updated viewport to %d %d.\n", width, height); + + left = WIDTH_ZOOM * -width / 2.0; + right = WIDTH_ZOOM * width / 2.0; + + top = HEIGHT_ZOOM * height / 2.0; + bottom = HEIGHT_ZOOM * -height / 2.0; } +void update(); + // Function to set up geometry void init_scene(); @@ -128,12 +254,19 @@ int main(int argc, char *argv[]) { Globals::mesh.print_details(); // Forcibly scale the mesh vertices so that the entire model fits within a - // (-1,1) volume: the code below is a temporary measure that is needed to + // (-1, 1) volume: the code below is a temporary measure that is needed to // enable the entire model to be visible in the template app, before the // student has defined the proper viewing and projection matrices This code // should eventually be replaced by the use of an appropriate projection - // matrix FYI: the model dimensions are: center = (0,0,0); height: 30.6; - // length: 40.3; width: 17.0 + // matrix + // + // FYI: the model dimensions are: + // + // - center = (0,0,0) + // - height: 30.6 + // - length: 40.3 + // - width: 17.0 + // // find the extremum of the vertex locations (this approach works because the // model is known to be centered; a more complicated method would be required // in the general case) @@ -154,6 +287,7 @@ int main(int argc, char *argv[]) { else if (Globals::mesh.vertices[i][2] > max) max = Globals::mesh.vertices[i][2]; } + // work with positive numbers if (min < 0) min = -min; @@ -164,6 +298,7 @@ int main(int argc, char *argv[]) { else scale = 1 / min; + /* // scale the model vertices by brute force Mat4x4 mscale; mscale.make_scale(scale, scale, scale); @@ -171,6 +306,7 @@ int main(int argc, char *argv[]) { Globals::mesh.vertices[i] = mscale * Globals::mesh.vertices[i]; } // The above can be removed once a proper projection matrix is defined + */ // Set up the window variable GLFWwindow *window; @@ -189,6 +325,9 @@ int main(int argc, char *argv[]) { glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + // TODO: REMOVE THIS BEFORE TURNING IN + // glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + // Create the glfw window Globals::win_width = WIN_WIDTH; Globals::win_height = WIN_HEIGHT; @@ -240,18 +379,24 @@ int main(int argc, char *argv[]) { // Game loop while (!glfwWindowShouldClose(window)) { - // Clear the color and depth buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + update(); + // Send updated info to the GPU - glUniformMatrix4fv(shader.uniform("model"), 1, GL_FALSE, - Globals::model.m); // model transformation (always the - // identity matrix in this assignment) - glUniformMatrix4fv(shader.uniform("view"), 1, GL_FALSE, - Globals::view.m); // viewing transformation - glUniformMatrix4fv(shader.uniform("projection"), 1, GL_FALSE, - Globals::projection.m); // projection matrix + { + // model transformation (always the identity matrix in this assignment) + glUniformMatrix4fv(shader.uniform("model"), 1, GL_FALSE, + Globals::model.m); + + // viewing transformation + glUniformMatrix4fv(shader.uniform("view"), 1, GL_TRUE, Globals::view.m); + + // projection matrix + glUniformMatrix4fv(shader.uniform("projection"), 1, GL_FALSE, + Globals::projection.m); + } // Draw glDrawElements(GL_TRIANGLES, Globals::mesh.faces.size() * 3, @@ -333,3 +478,126 @@ void init_scene() { // Done setting data for the vao glBindVertexArray(0); } + +void update() { + { + using namespace Globals; + using namespace Globals::controls; + + Vec3f move_by(0.0, 0.0, 0.0); + + bool move = true; + float move_angle_delta; + + // Lol too lazy to get this to be more concise + if (is_left_held && is_up_held) + move_angle_delta = 3 * PI / 4; + else if (is_left_held && is_down_held) + move_angle_delta = PI / 4; + else if (is_right_held && is_up_held) + move_angle_delta = -3 * PI / 4; + else if (is_right_held && is_down_held) + move_angle_delta = -PI / 4; + else if (is_left_held) + move_angle_delta = PI / 2; + else if (is_right_held) + move_angle_delta = -PI / 2; + else if (is_up_held) + move_angle_delta = PI; + else if (is_down_held) + move_angle_delta = 0.0; + else + move = false; + + const float move_angle = view_angle + move_angle_delta; + + if (move) { + move_by[0] = sin(move_angle) * viewing_window::MOVE_BY; + move_by[2] = cos(move_angle) * viewing_window::MOVE_BY; + } + + if (is_raise_held) + move_by[1] = viewing_window::MOVE_BY; + else if (is_lower_held) + move_by[1] = -viewing_window::MOVE_BY; + + if (is_up_held || is_down_held || is_left_held || is_right_held || + is_raise_held || is_lower_held) { + eye_pos += move_by; + printf("Move by (%.2f, %.2f, %.2f) to (%.2f, %.2f, %.2f)\n", move_by[0], + move_by[1], move_by[2], eye_pos[0], eye_pos[1], eye_pos[2]); + } + + if (is_spin_left_held) + view_angle -= viewing_window::ANGLE_BY; + else if (is_spin_right_held) + view_angle += viewing_window::ANGLE_BY; + } + + // Set up normalization matrix + { + using namespace Globals::viewing_window; + Globals::projection.zero(); + auto m = Globals::projection.m; + + // 0 1 2 3 + // 4 5 6 7 + // 8 9 10 11 + // 12 13 14 15 + m[0] = (2.0 * near) / (right - left); + m[5] = (2.0 * near) / (top - bottom); + m[2] = (right + left) / (right - left); + m[6] = (top + bottom) / (top - bottom); + m[10] = -(far + near) / (far - near); + m[11] = -2.0 * far * near / (far - near); + m[14] = -1.0; + } + + // Set up view matrix + { + using namespace Globals; + + Globals::view.zero(); + auto m = Globals::view.m; + auto eye = Globals::eye_pos; + + eye_dir[0] = sin(view_angle); + eye_dir[2] = cos(view_angle); + + Vec3f n = eye_dir * -1.0f; + n.normalize(); + + // Up direction is (0, 1, 0) + Vec3f u = Globals::up_dir.cross(n); + u.normalize(); + + // v = n x u + Vec3f v = n.cross(u); + v.normalize(); + + Vec3f d(-eye.dot(u), -eye.dot(v), -eye.dot(n)); + + // 0 1 2 3 + // 4 5 6 7 + // 8 9 10 11 + // 12 13 14 15 + + m[0] = u.data[0]; + m[1] = u.data[1]; + m[2] = u.data[2]; + + m[4] = v.data[0]; + m[5] = v.data[1]; + m[6] = v.data[2]; + + m[8] = n.data[0]; + m[9] = n.data[1]; + m[10] = n.data[2]; + + m[3] = d.data[0]; + m[7] = d.data[1]; + m[11] = d.data[2]; + + m[15] = 1.0; + } +} diff --git a/flake.nix b/flake.nix index e5fff00..7aaf5ff 100644 --- a/flake.nix +++ b/flake.nix @@ -37,6 +37,7 @@ ninja pandoc poppler_utils + renderdoc texlive.combined.scheme-full unzip zip