From 70f6812fb42e7e3b4d63ab59b02d33a038f997a1 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Mon, 15 Sep 2025 15:45:30 +0200 Subject: [PATCH 01/12] feat: add uniform transform matrix with modifiable elements in main.rs --- src/main.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.rs b/src/main.rs index 7df1d18..3e99a2a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -236,6 +236,8 @@ fn main() { .attach_file("./shaders/simple.frag") .link() }; + // get uniform location for the matrix (named `transform` in your vertex shader) + let transform_loc = unsafe { simple_shader.get_uniform_location("transform") }; // Used to demonstrate keyboard handling for exercise 2. let mut _arbitrary_number = 0.0; // feel free to remove @@ -298,6 +300,11 @@ fn main() { // == // Issue the necessary gl:: commands to draw your scene here simple_shader.activate(); + // build and send the transform matrix (start from identity) + let mut transform = glm::identity(); + // modify element (0,0) here; change indices to test a, b, c, d, e, f, etc. + transform[(0,0)] = elapsed.sin(); + gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform.as_ptr()); gl::BindVertexArray(my_vao); gl::DrawElements( gl::TRIANGLES, -- 2.51.2 From 179da917706916f95bf1a480a6addfa820c5442d Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Mon, 15 Sep 2025 15:46:30 +0200 Subject: [PATCH 02/12] fix: add type annotation to resolve ambiguous transform matrix type in main.rs --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 3e99a2a..4c333eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -301,7 +301,7 @@ fn main() { // == // Issue the necessary gl:: commands to draw your scene here simple_shader.activate(); // build and send the transform matrix (start from identity) - let mut transform = glm::identity(); + let mut transform: glm::Mat4 = glm::identity(); // modify element (0,0) here; change indices to test a, b, c, d, e, f, etc. transform[(0,0)] = elapsed.sin(); gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform.as_ptr()); -- 2.51.2 From ff9600071f878cf8636cccad2c82cd9e36cd63f9 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Mon, 15 Sep 2025 15:57:32 +0200 Subject: [PATCH 03/12] feat: cycle through transform matrix params a-f over time in main.rs uniform update --- src/main.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4c333eb..c592a97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -302,8 +302,19 @@ fn main() { simple_shader.activate(); // build and send the transform matrix (start from identity) let mut transform: glm::Mat4 = glm::identity(); - // modify element (0,0) here; change indices to test a, b, c, d, e, f, etc. - transform[(0,0)] = elapsed.sin(); + // cycle through each transform parameter (a,b,c,d,e,f) over time + let cycle_duration = 2.0; + let idx = ((elapsed / cycle_duration).floor() as usize) % 6; + let v = elapsed.sin(); + match idx { + 0 => transform[(0,0)] = v, // a + 1 => transform[(0,1)] = v, // b + 2 => transform[(0,3)] = v, // c + 3 => transform[(1,0)] = v, // d + 4 => transform[(1,1)] = v, // e + 5 => transform[(1,3)] = v, // f + _ => {} + } gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform.as_ptr()); gl::BindVertexArray(my_vao); gl::DrawElements( -- 2.51.2 From 64f04a8b4c4e34d701c6e30a81f6edef4551a49c Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Mon, 15 Sep 2025 16:36:59 +0200 Subject: [PATCH 04/12] vert --- shaders/simple.vert | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/shaders/simple.vert b/shaders/simple.vert index 2a10ade..7dad78c 100644 --- a/shaders/simple.vert +++ b/shaders/simple.vert @@ -3,17 +3,9 @@ in layout(location=0) vec3 position; in layout(location=1) vec4 aColor; out vec4 vColor; - -mat4 transform; +uniform mat4 transform; void main() { - transform = mat4( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - ); - gl_Position = transform * vec4(position, 1.0f); vColor = aColor; } -- 2.51.2 From 0400e0969da023d098a90037d1c26f6af5ccb419 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Wed, 17 Sep 2025 22:09:00 +0200 Subject: [PATCH 05/12] feat: bind transform uniform to location 0 in vertex shader for clarity --- shaders/simple.vert | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shaders/simple.vert b/shaders/simple.vert index 7dad78c..7eb80e9 100644 --- a/shaders/simple.vert +++ b/shaders/simple.vert @@ -3,7 +3,7 @@ in layout(location=0) vec3 position; in layout(location=1) vec4 aColor; out vec4 vColor; -uniform mat4 transform; +layout(location = 0) uniform mat4 transform; void main() { gl_Position = transform * vec4(position, 1.0f); -- 2.51.2 From b08a38ce74c1cd26f06a4c5076b092e2e3e815b9 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Wed, 17 Sep 2025 22:10:42 +0200 Subject: [PATCH 06/12] feat: apply translation and perspective projection to transform matrix before shader upload --- src/main.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.rs b/src/main.rs index c592a97..9b2b942 100644 --- a/src/main.rs +++ b/src/main.rs @@ -315,6 +315,13 @@ fn main() { 5 => transform[(1,3)] = v, // f _ => {} } + // move scene into viewable negative z range + let translation: glm::Mat4 = glm::translation(&glm::vec3(0.0, 0.0, -5.0)); + transform = translation * transform; + // apply perspective projection: (aspect, fovy radians, near, far) + let projection: glm::Mat4 = + glm::perspective(window_aspect_ratio, std::f32::consts::PI / 4.0, 1.0, 100.0); + transform = projection * transform; gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform.as_ptr()); gl::BindVertexArray(my_vao); gl::DrawElements( -- 2.51.2 From f6422f403e0390dfe677e9f869843900144a1dda Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Wed, 17 Sep 2025 22:27:23 +0200 Subject: [PATCH 07/12] feat: add camera position and orientation variables for tripod motion control --- src/main.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main.rs b/src/main.rs index 9b2b942..effc9a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -242,6 +242,11 @@ fn main() { // Used to demonstrate keyboard handling for exercise 2. let mut _arbitrary_number = 0.0; // feel free to remove + // camera position (x, y, z) and orientation (yaw, pitch) + let mut cam_pos: glm::Vec3 = glm::vec3(0.0, 0.0, 0.0); + let mut cam_yaw: f32 = 0.0; + let mut cam_pitch: f32 = 0.0; + // The main rendering loop let first_frame_time = std::time::Instant::now(); let mut previous_frame_time = first_frame_time; -- 2.51.2 From 861c6ebd62ae55897a7fb84cffd729c563d5eff0 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Wed, 17 Sep 2025 22:34:34 +0200 Subject: [PATCH 08/12] feat: add key handlers for tripod camera movement and rotation controls --- src/main.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index effc9a6..4ffcb8e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -270,19 +270,22 @@ fn main() { } } - // Handle keyboard input + // Handle keyboard input for camera movement and rotation if let Ok(keys) = pressed_keys.lock() { for key in keys.iter() { match key { - // The `VirtualKeyCode` enum is defined here: - // https://docs.rs/winit/0.25.0/winit/event/enum.VirtualKeyCode.html - VirtualKeyCode::A => { - _arbitrary_number += delta_time; - } - VirtualKeyCode::D => { - _arbitrary_number -= delta_time; - } - + // Movement: WASD + Space (up) + LShift (down) + VirtualKeyCode::W => { cam_pos.z -= delta_time; } + VirtualKeyCode::S => { cam_pos.z += delta_time; } + VirtualKeyCode::A => { cam_pos.x -= delta_time; } + VirtualKeyCode::D => { cam_pos.x += delta_time; } + VirtualKeyCode::Space => { cam_pos.y += delta_time; } + VirtualKeyCode::LShift => { cam_pos.y -= delta_time; } + // Rotation: arrow keys for yaw and pitch + VirtualKeyCode::Left => { cam_yaw -= delta_time; } + VirtualKeyCode::Right => { cam_yaw += delta_time; } + VirtualKeyCode::Up => { cam_pitch += delta_time; } + VirtualKeyCode::Down => { cam_pitch -= delta_time; } // default handler: _ => {} } -- 2.51.2 From de7cc20db317bc9ee8b387f09dbe35f2527be663 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Wed, 17 Sep 2025 22:38:35 +0200 Subject: [PATCH 09/12] fix: apply correct model, view, and projection matrices for camera motion each frame --- src/main.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4ffcb8e..0710d42 100644 --- a/src/main.rs +++ b/src/main.rs @@ -308,28 +308,34 @@ fn main() { // == // Issue the necessary gl:: commands to draw your scene here simple_shader.activate(); - // build and send the transform matrix (start from identity) - let mut transform: glm::Mat4 = glm::identity(); + // build Model matrix (start from identity) + let mut model: glm::Mat4 = glm::identity(); // cycle through each transform parameter (a,b,c,d,e,f) over time let cycle_duration = 2.0; let idx = ((elapsed / cycle_duration).floor() as usize) % 6; let v = elapsed.sin(); match idx { - 0 => transform[(0,0)] = v, // a - 1 => transform[(0,1)] = v, // b - 2 => transform[(0,3)] = v, // c - 3 => transform[(1,0)] = v, // d - 4 => transform[(1,1)] = v, // e - 5 => transform[(1,3)] = v, // f + 0 => model[(0,0)] = v, // a + 1 => model[(0,1)] = v, // b + 2 => model[(0,3)] = v, // c + 3 => model[(1,0)] = v, // d + 4 => model[(1,1)] = v, // e + 5 => model[(1,3)] = v, // f _ => {} } - // move scene into viewable negative z range - let translation: glm::Mat4 = glm::translation(&glm::vec3(0.0, 0.0, -5.0)); - transform = translation * transform; - // apply perspective projection: (aspect, fovy radians, near, far) + // model translation to initial view distance + let translation_model: glm::Mat4 = glm::translation(&glm::vec3(0.0, 0.0, -5.0)); + let model = translation_model * model; + // build View matrix: translate and rotate world relative to camera + let view_translation: glm::Mat4 = glm::translation(&(-cam_pos)); + let view_rot_y: glm::Mat4 = glm::rotation(-cam_yaw, &glm::vec3(0.0, 1.0, 0.0)); + let view_rot_x: glm::Mat4 = glm::rotation(-cam_pitch, &glm::vec3(1.0, 0.0, 0.0)); + let view: glm::Mat4 = view_rot_x * view_rot_y * view_translation; + // build Projection matrix let projection: glm::Mat4 = glm::perspective(window_aspect_ratio, std::f32::consts::PI / 4.0, 1.0, 100.0); - transform = projection * transform; + // final transform: Projection * View * Model + let transform: glm::Mat4 = projection * view * model; gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform.as_ptr()); gl::BindVertexArray(my_vao); gl::DrawElements( -- 2.51.2 From e3509a7ece35893cad1fab7c32caa8e494b3c965 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Thu, 18 Sep 2025 00:15:39 +0200 Subject: [PATCH 10/12] feat: move camera relative to its orientation and clamp pitch angle --- src/main.rs | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0710d42..638ee6f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -272,24 +272,36 @@ fn main() { // Handle keyboard input for camera movement and rotation if let Ok(keys) = pressed_keys.lock() { + // movement speed + let speed = 2.5 * delta_time; + // camera direction vectors based on yaw & pitch + let front = glm::vec3( + cam_yaw.sin() * cam_pitch.cos(), + cam_pitch.sin(), + -cam_yaw.cos() * cam_pitch.cos(), + ); + let right = glm::normalize(&glm::cross(&front, &glm::vec3(0.0, 1.0, 0.0))); + let up_vec = glm::normalize(&glm::cross(&right, &front)); for key in keys.iter() { match key { - // Movement: WASD + Space (up) + LShift (down) - VirtualKeyCode::W => { cam_pos.z -= delta_time; } - VirtualKeyCode::S => { cam_pos.z += delta_time; } - VirtualKeyCode::A => { cam_pos.x -= delta_time; } - VirtualKeyCode::D => { cam_pos.x += delta_time; } - VirtualKeyCode::Space => { cam_pos.y += delta_time; } - VirtualKeyCode::LShift => { cam_pos.y -= delta_time; } - // Rotation: arrow keys for yaw and pitch - VirtualKeyCode::Left => { cam_yaw -= delta_time; } - VirtualKeyCode::Right => { cam_yaw += delta_time; } - VirtualKeyCode::Up => { cam_pitch += delta_time; } - VirtualKeyCode::Down => { cam_pitch -= delta_time; } - // default handler: + // Move relative to camera orientation + VirtualKeyCode::W => { cam_pos += front * speed; } + VirtualKeyCode::S => { cam_pos -= front * speed; } + VirtualKeyCode::A => { cam_pos -= right * speed; } + VirtualKeyCode::D => { cam_pos += right * speed; } + VirtualKeyCode::Space => { cam_pos += up_vec * speed; } + VirtualKeyCode::LShift => { cam_pos -= up_vec * speed; } + // Rotation: adjust yaw and pitch + VirtualKeyCode::Left => { cam_yaw -= delta_time; } + VirtualKeyCode::Right => { cam_yaw += delta_time; } + VirtualKeyCode::Up => { cam_pitch += delta_time; } + VirtualKeyCode::Down => { cam_pitch -= delta_time; } _ => {} } } + // clamp pitch to avoid flipping + let pitch_limit = std::f32::consts::FRAC_PI_2 - 0.01; + cam_pitch = cam_pitch.clamp(-pitch_limit, pitch_limit); } // Handle mouse movement. delta contains the x and y movement of the mouse since last frame in pixels if let Ok(mut delta) = mouse_delta.lock() { -- 2.51.2 From 74342b5d1adbd097a7ffa2b631b11308136fe503 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Thu, 18 Sep 2025 10:47:02 +0200 Subject: [PATCH 11/12] feat: add camera-facing billboard quad rendering with rotation invariance --- src/main.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/main.rs b/src/main.rs index 638ee6f..d2a8c69 100644 --- a/src/main.rs +++ b/src/main.rs @@ -220,6 +220,24 @@ fn main() { let my_vao = unsafe { create_vao(&vertices, &colors, &indices) }; + let billboard_vertices = vec![ + -0.5, -0.5, 0.0, + -0.5, 0.5, 0.0, + 0.5, 0.5, 0.0, + 0.5, -0.5, 0.0, + ]; + let billboard_indices = vec![ + 0, 1, 2, + 0, 2, 3, + ]; + let billboard_colors = vec![ + 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, + ]; + let billboard_vao = unsafe { create_vao(&billboard_vertices, &billboard_colors, &billboard_indices) }; + // == // Set up your shaders here // Basic usage of shader helper: @@ -356,6 +374,21 @@ fn main() { gl::UNSIGNED_INT, std::ptr::null(), ); + + // Draw billboard (camera-facing quad) + let translation_bill = glm::translation(&glm::vec3(0.0, 0.0, -2.0)); + let inv_rot_y = glm::rotation(cam_yaw, &glm::vec3(0.0, 1.0, 0.0)); + let inv_rot_x = glm::rotation(cam_pitch, &glm::vec3(1.0, 0.0, 0.0)); + let model_billboard = translation_bill * inv_rot_y * inv_rot_x; + let transform_bill = projection * view * model_billboard; + gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform_bill.as_ptr()); + gl::BindVertexArray(billboard_vao); + gl::DrawElements( + gl::TRIANGLES, + billboard_indices.len() as i32, + gl::UNSIGNED_INT, + std::ptr::null(), + ); } // Display the new color buffer on the display -- 2.51.2 From 5d643ddb4efa2b5eb1cd8e123ef0dd59b85eed42 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Thu, 18 Sep 2025 10:53:44 +0200 Subject: [PATCH 12/12] feat: render a large grid of point-particles as billboards with program point size enabled --- src/main.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main.rs b/src/main.rs index d2a8c69..d739398 100644 --- a/src/main.rs +++ b/src/main.rs @@ -163,6 +163,7 @@ fn main() { gl::Disable(gl::MULTISAMPLE); gl::Enable(gl::BLEND); gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); + gl::Enable(gl::PROGRAM_POINT_SIZE); gl::Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS); gl::DebugMessageCallback(Some(util::debug_callback), ptr::null()); @@ -238,6 +239,22 @@ fn main() { ]; let billboard_vao = unsafe { create_vao(&billboard_vertices, &billboard_colors, &billboard_indices) }; + // Generate a grid of point‐particles + let grid_size = 200; + let mut particle_vertices = Vec::with_capacity(grid_size * grid_size * 3); + let mut particle_colors = Vec::with_capacity(grid_size * grid_size * 4); + for i in 0..grid_size { + for j in 0..grid_size { + let x = (i as f32 / grid_size as f32 - 0.5) * 20.0; + let y = (j as f32 / grid_size as f32 - 0.5) * 20.0; + let z = -5.0; + particle_vertices.extend_from_slice(&[x, y, z]); + particle_colors.extend_from_slice(&[1.0, 1.0, 1.0, 1.0]); + } + } + let particle_vao = unsafe { create_vao(&particle_vertices, &particle_colors, &Vec::new()) }; + let particle_count = (grid_size * grid_size) as i32; + // == // Set up your shaders here // Basic usage of shader helper: @@ -375,6 +392,12 @@ fn main() { std::ptr::null(), ); + // Draw point‐particles + let transform_particles = projection * view * glm::identity(); + gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform_particles.as_ptr()); + gl::BindVertexArray(particle_vao); + gl::DrawArrays(gl::POINTS, 0, particle_count); + // Draw billboard (camera-facing quad) let translation_bill = glm::translation(&glm::vec3(0.0, 0.0, -2.0)); let inv_rot_y = glm::rotation(cam_yaw, &glm::vec3(0.0, 1.0, 0.0)); -- 2.51.2