rendering works :)

This commit is contained in:
Michael Zhang 2023-04-25 19:52:54 -05:00
parent 2100a9c221
commit ef22869e48
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
3 changed files with 321 additions and 26 deletions

View file

@ -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())

View file

@ -10,41 +10,72 @@
#include "shader.hpp" #include "shader.hpp"
#include "trimesh.hpp" #include "trimesh.hpp"
#include <cstring> // memcpy #include <cstring> // memcpy
#include <numeric>
// Constants // Constants
#define WIN_WIDTH 500 #define WIN_WIDTH 500
#define WIN_HEIGHT 500 #define WIN_HEIGHT 500
#define PI 3.1415926535
class Mat4x4 { class Mat4x4 {
public: public:
float m[16]; float m[16];
// Default: Identity
Mat4x4() {
// clang-format off // clang-format off
Mat4x4(){ // Default: Identity
m[0] = 1.f; m[4] = 0.f; m[8] = 0.f; m[12] = 0.f; 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[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[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; m[3] = 0.f; m[7] = 0.f; m[11] = 0.f; m[15] = 1.f;
}
// clang-format on // clang-format on
}
void make_identity() {
// clang-format off // clang-format off
void make_identity(){
m[0] = 1.f; m[4] = 0.f; m[8] = 0.f; m[12] = 0.f; 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[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[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; m[3] = 0.f; m[7] = 0.f; m[11] = 0.f; m[15] = 1.f;
}
// clang-format on // clang-format on
}
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 // clang-format off
void print(){
std::cout << m[0] << ' ' << m[4] << ' ' << m[8] << ' ' << m[12] << "\n"; 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[1] << ' ' << m[5] << ' ' << m[9] << ' ' << m[13] << "\n";
std::cout << m[2] << ' ' << m[6] << ' ' << m[10] << ' ' << m[14] << "\n"; std::cout << m[2] << ' ' << m[6] << ' ' << m[10] << ' ' << m[14] << "\n";
std::cout << m[3] << ' ' << m[7] << ' ' << m[11] << ' ' << m[15] << "\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) { void make_scale(float x, float y, float z) {
make_identity(); make_identity();
@ -52,6 +83,33 @@ public:
m[5] = y; m[5] = y;
m[10] = z; 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) { 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; GLuint verts_vbo[1], colors_vbo[1], normals_vbo[1], faces_ibo[1], tris_vao;
TriMesh mesh; 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 // Model, view and projection matrices, initialized to the identity
Mat4x4 model; // not used in this assignment; included for completeness only Mat4x4 model; // not used in this assignment; included for completeness only
Mat4x4 view; Mat4x4 view;
@ -90,27 +180,63 @@ static void key_callback(GLFWwindow *window, int key, int scancode, int action,
if (action == GLFW_PRESS) { if (action == GLFW_PRESS) {
switch (key) { switch (key) {
case GLFW_KEY_ESCAPE: case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(window, GL_TRUE);
break;
case GLFW_KEY_Q: case GLFW_KEY_Q:
glfwSetWindowShouldClose(window, GL_TRUE); glfwSetWindowShouldClose(window, GL_TRUE);
break; 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, static void framebuffer_size_callback(GLFWwindow *window, int width,
int height) { int height) {
Globals::win_width = float(width); using namespace Globals;
Globals::win_height = float(height); using namespace Globals::viewing_window;
Globals::aspect = Globals::win_width / Globals::win_height;
win_width = float(width);
win_height = float(height);
aspect = win_width / win_height;
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
// ToDo: update the perspective matrix as the window size changes // 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 // Function to set up geometry
void init_scene(); void init_scene();
@ -128,12 +254,19 @@ int main(int argc, char *argv[]) {
Globals::mesh.print_details(); Globals::mesh.print_details();
// Forcibly scale the mesh vertices so that the entire model fits within a // 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 // enable the entire model to be visible in the template app, before the
// student has defined the proper viewing and projection matrices This code // student has defined the proper viewing and projection matrices This code
// should eventually be replaced by the use of an appropriate projection // should eventually be replaced by the use of an appropriate projection
// matrix FYI: the model dimensions are: center = (0,0,0); height: 30.6; // matrix
// length: 40.3; width: 17.0 //
// 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 // 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 // model is known to be centered; a more complicated method would be required
// in the general case) // in the general case)
@ -154,6 +287,7 @@ int main(int argc, char *argv[]) {
else if (Globals::mesh.vertices[i][2] > max) else if (Globals::mesh.vertices[i][2] > max)
max = Globals::mesh.vertices[i][2]; max = Globals::mesh.vertices[i][2];
} }
// work with positive numbers // work with positive numbers
if (min < 0) if (min < 0)
min = -min; min = -min;
@ -164,6 +298,7 @@ int main(int argc, char *argv[]) {
else else
scale = 1 / min; scale = 1 / min;
/*
// scale the model vertices by brute force // scale the model vertices by brute force
Mat4x4 mscale; Mat4x4 mscale;
mscale.make_scale(scale, scale, scale); 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]; Globals::mesh.vertices[i] = mscale * Globals::mesh.vertices[i];
} }
// The above can be removed once a proper projection matrix is defined // The above can be removed once a proper projection matrix is defined
*/
// Set up the window variable // Set up the window variable
GLFWwindow *window; GLFWwindow *window;
@ -189,6 +325,9 @@ int main(int argc, char *argv[]) {
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// TODO: REMOVE THIS BEFORE TURNING IN
// glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
// Create the glfw window // Create the glfw window
Globals::win_width = WIN_WIDTH; Globals::win_width = WIN_WIDTH;
Globals::win_height = WIN_HEIGHT; Globals::win_height = WIN_HEIGHT;
@ -240,18 +379,24 @@ int main(int argc, char *argv[]) {
// Game loop // Game loop
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
// Clear the color and depth buffers // Clear the color and depth buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
update();
// Send updated info to the GPU // Send updated info to the GPU
{
// model transformation (always the identity matrix in this assignment)
glUniformMatrix4fv(shader.uniform("model"), 1, GL_FALSE, glUniformMatrix4fv(shader.uniform("model"), 1, GL_FALSE,
Globals::model.m); // model transformation (always the Globals::model.m);
// identity matrix in this assignment)
glUniformMatrix4fv(shader.uniform("view"), 1, GL_FALSE, // viewing transformation
Globals::view.m); // viewing transformation glUniformMatrix4fv(shader.uniform("view"), 1, GL_TRUE, Globals::view.m);
// projection matrix
glUniformMatrix4fv(shader.uniform("projection"), 1, GL_FALSE, glUniformMatrix4fv(shader.uniform("projection"), 1, GL_FALSE,
Globals::projection.m); // projection matrix Globals::projection.m);
}
// Draw // Draw
glDrawElements(GL_TRIANGLES, Globals::mesh.faces.size() * 3, glDrawElements(GL_TRIANGLES, Globals::mesh.faces.size() * 3,
@ -333,3 +478,126 @@ void init_scene() {
// Done setting data for the vao // Done setting data for the vao
glBindVertexArray(0); 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;
}
}

View file

@ -37,6 +37,7 @@
ninja ninja
pandoc pandoc
poppler_utils poppler_utils
renderdoc
texlive.combined.scheme-full texlive.combined.scheme-full
unzip unzip
zip zip