diff --git a/gloom-rs/src/draw.rs b/gloom-rs/src/draw.rs index 72341f5..c794319 100644 --- a/gloom-rs/src/draw.rs +++ b/gloom-rs/src/draw.rs @@ -57,17 +57,42 @@ pub enum Nodes { SceneRoot, } +pub struct ChaseCamera { + pub position: glm::Vec3, + pub target: glm::Vec3, + pub radius: f32, // set to big number to get normal camera + pub perspective: glm::Mat4, + pitch: f32, + yaw: f32 +} + +impl ChaseCamera { + pub fn new(radius: f32, perspective: glm::Mat4) -> Self { + ChaseCamera { + position: glm::vec3(100.0, 35.0, 0.0), + target: glm::vec3(0.0, 0.0, 0.0), + radius, + perspective, + pitch: 0.0, + yaw: 0.0 + } + } +} + pub struct World { pub nodes: HashMap>>>>, - pub anim_ctxs: Vec + pub anim_ctxs: Vec, + pub camera: ChaseCamera, + pub model_transformation: glm::Mat4 } impl World { - pub fn new() -> Self { + pub fn new(radius: f32, perspective: glm::Mat4) -> Self { let meshes = Self::load_models(); let nodes = Self::setup_scene_graph(&meshes); let anim_ctxs:Vec = Vec::new(); - World { nodes, anim_ctxs } + let camera = ChaseCamera::new(radius, perspective); + World { nodes, anim_ctxs, camera, model_transformation: glm::identity() } } fn load_models() -> HashMap { @@ -146,23 +171,49 @@ impl World { return nodes; } - pub fn update(&mut self, elapsed: f32, perspective: glm::Mat4, transformation: glm::Mat4, shader: &Shader) { - let transform_thus_far = perspective * transformation; + fn view_matrix(&self) -> glm::Mat4 { + glm::look_at( + &self.camera.position, + &self.camera.target, + &glm::vec3(0.0, 1.0, 0.0) + ) + } + + pub fn update(&mut self, elapsed: f32, shader: &Shader) { let rotor_speed = 60.0; + // update all helicopter positions for i in 0..self.nodes[&Nodes::HeliRoot].len() { - // let iter_heli_heading = toolbox::simple_heading_animation(elapsed + i as f32 * 1.6f32); - // let heli_root = &mut self.nodes.get_mut(&Nodes::HeliRoot).unwrap()[i]; - // heli_root.position.x = iter_heli_heading.x; - // heli_root.position.z = iter_heli_heading.z; - // heli_root.rotation.z = iter_heli_heading.roll; - // heli_root.rotation.y = iter_heli_heading.yaw; - // heli_root.rotation.x = iter_heli_heading.pitch; + let iter_heli_heading = toolbox::simple_heading_animation(elapsed + i as f32 * 1.6f32); + let heli_root = &mut self.nodes.get_mut(&Nodes::HeliRoot).unwrap()[i]; + heli_root.position.x = iter_heli_heading.x; + heli_root.position.y = 15.0; + heli_root.position.z = iter_heli_heading.z; + heli_root.rotation.z = iter_heli_heading.roll; + heli_root.rotation.y = iter_heli_heading.yaw; + heli_root.rotation.x = iter_heli_heading.pitch; self.nodes.get_mut(&Nodes::HeliMainRotor).unwrap()[i].rotation.y = elapsed * rotor_speed; self.nodes.get_mut(&Nodes::HeliTailRotor).unwrap()[i].rotation.x = elapsed * rotor_speed; } + // camera chase after target + let camera_target = &self.nodes[&Nodes::HeliRoot][0]; + self.camera.target = camera_target.position; + let distance = glm::distance(&self.camera.position, &self.camera.target); + let direction = glm::normalize(&(self.camera.target - self.camera.position)); + if distance > self.camera.radius { + self.camera.position += direction * (distance - self.camera.radius); + } + + // update camera angles + self.camera.yaw = direction.z.atan2(direction.x) + glm::half_pi::(); + let horizontal_distance = (direction.x * direction.x + direction.z * direction.z).sqrt(); + self.camera.pitch = direction.y.atan2(horizontal_distance); + + + let transform_thus_far = self.camera.perspective * self.view_matrix(); + // Build scene graph on the fly or store scene_root separately unsafe { draw_scene(&self.nodes[&Nodes::SceneRoot][0], &transform_thus_far, glm::identity(), &shader, elapsed); diff --git a/gloom-rs/src/main.rs b/gloom-rs/src/main.rs index faff8dd..cd1d8ed 100644 --- a/gloom-rs/src/main.rs +++ b/gloom-rs/src/main.rs @@ -91,22 +91,12 @@ fn main() { println!("GLSL\t: {}", util::get_gl_string(gl::SHADING_LANGUAGE_VERSION)); } - let mut transformation: glm::Mat4; - let perspective: glm::Mat4 = glm::perspective( + let mut world = draw::World::new(30.0, glm::perspective( window_aspect_ratio, 120.0f32, 1.0f32, 1000.0f32 - ); - - let mut world = draw::World::new(); - - let mut camera_position: glm::Vec3 = glm::vec3(0.0, 0.0, 0.0); - let translation_speed = 30.0f32; - let rotation_speed = 1.5f32; - - let mut yaw = 0.0f32; - let mut pitch = 0.0f32; + )); // == // Set up your shaders here @@ -135,9 +125,6 @@ fn main() { let delta_time = now.duration_since(previous_frame_time).as_secs_f32(); previous_frame_time = now; - let angle_speed = rotation_speed * delta_time; - let trans_speed: f32 = translation_speed * delta_time; - // Handle resize events if let Ok(mut new_size) = window_size.lock() { if new_size.2 { @@ -149,34 +136,10 @@ fn main() { } } - // Calculate forward vector, and right vector in x-z plane for relative yaw based translation. - let f_xz = glm::vec3(-yaw.sin(), yaw.cos(), 0.0); - let r_xz = glm::rotation2d(glm::half_pi()) * f_xz; - - let forward = glm::vec3(f_xz.x, f_xz.z, f_xz.y); - let right = glm::vec3(r_xz.x, r_xz.z, r_xz.y); // Handle keyboard input if let Ok(keys) = pressed_keys.lock() { for key in keys.iter() { match key { - VirtualKeyCode::W => { - camera_position += forward * trans_speed; - } - VirtualKeyCode::A => { - camera_position -= right * trans_speed; - } - VirtualKeyCode::S => { - camera_position -= forward * trans_speed; - } - VirtualKeyCode::D => { - camera_position += right * trans_speed; - } - VirtualKeyCode::Space => { - camera_position.y -= trans_speed; - } - VirtualKeyCode::LShift => { - camera_position.y += trans_speed; - } VirtualKeyCode::E => { let ptr = &world.nodes[&Nodes::HeliDoor][0]; @@ -196,27 +159,6 @@ fn main() { } } - VirtualKeyCode::Down => { - pitch += angle_speed; - pitch = pitch.clamp( - -std::f32::consts::FRAC_PI_2, - std::f32::consts::FRAC_PI_2 - ); - } - VirtualKeyCode::Up => { - pitch -= angle_speed; - pitch = pitch.clamp( - -std::f32::consts::FRAC_PI_2, - std::f32::consts::FRAC_PI_2 - ); - } - VirtualKeyCode::Right => { - yaw += angle_speed; - } - VirtualKeyCode::Left => { - yaw -= angle_speed; - } - _ => { } } } @@ -230,14 +172,6 @@ fn main() { *delta = (0.0, 0.0); // reset when done } - let yaw_matrix = glm::rotation(yaw, &glm::vec3(0.0, 1.0, 0.0)); - let pitch_matrix = glm::rotation(pitch, &glm::vec3(1.0, 0.0, 0.0)); - let translation_matrix = glm::translation(&(camera_position)); - - // apply yaw dependent pitch first. - let rotation_matrix = pitch_matrix * yaw_matrix; - transformation = rotation_matrix * translation_matrix; - unsafe { simple_shader.activate(); @@ -245,7 +179,7 @@ fn main() { gl::ClearColor(40.0f32 / 256.0f32, 42.0f32 / 256.0f32, 54.0f32 / 256.0f32, 1.0); // night sky gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT); - world.update(elapsed, perspective, transformation, &simple_shader); + world.update(elapsed, &simple_shader); // Display the new color buffer on the display context.swap_buffers().unwrap(); // we use "double buffering" to avoid artifacts