From 51a3f812fe731f3b593b1cd2f5fda153a7688a7a Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Thu, 12 Jun 2025 21:07:49 +0200 Subject: [PATCH] Migrate Camera Resource to Component --- src/core/render/primitives/camera.rs | 70 +++------------- src/core/render/primitives/transform.rs | 24 ------ src/core/render/primitives/velocity.rs | 2 +- src/game/scenes/main_scene.rs | 104 ++++++++++++++++++------ 4 files changed, 92 insertions(+), 108 deletions(-) diff --git a/src/core/render/primitives/camera.rs b/src/core/render/primitives/camera.rs index f25c41c..008ecac 100644 --- a/src/core/render/primitives/camera.rs +++ b/src/core/render/primitives/camera.rs @@ -1,6 +1,6 @@ -use std::{f32::consts::FRAC_PI_2, sync::Arc}; +use std::sync::Arc; -use bevy_ecs::resource::Resource; +use bevy_ecs::component::Component; use glam::{Mat4, Vec3, Vec4}; use vulkano::{ Validated, @@ -8,8 +8,6 @@ use vulkano::{ memory::allocator::StandardMemoryAllocator, }; -use crate::core::{input::InputManager, timer::Timer}; - use super::{AsUniformBuffer, mvp::Mvp}; // See docs/OPENGL_VULKAN_DIFF.md @@ -20,24 +18,25 @@ const OPENGL_TO_VULKAN_Y_AXIS_FLIP: Mat4 = Mat4 { w_axis: Vec4::new(0.0, 0.0, 0.0, 1.0), }; -#[derive(Resource)] +#[derive(Component)] pub struct Camera3D { projection: Mat4, - - position: Vec3, - rotation: Vec3, aspect_ratio: f32, fov: f32, near: f32, far: f32, } +#[derive(Component)] +pub struct Camera3DTransform { + pub position: Vec3, + pub rotation: Vec3, +} + impl Camera3D { pub fn new(aspect_ratio: f32, fov: f32, near: f32, far: f32) -> Self { Self { projection: Mat4::perspective_rh(fov, aspect_ratio, near, far), - position: Vec3::ZERO, - rotation: Vec3::ZERO, aspect_ratio, fov, near, @@ -45,42 +44,6 @@ impl Camera3D { } } - pub fn update( - &mut self, - input_manager: &InputManager, - timer: &Timer, - movement_speed: f32, - camera_sensitivity: f32, - ) { - // Process camera rotation - let camera_delta = camera_sensitivity * timer.delta_time(); - self.rotation += Vec3::new( - (input_manager.get_virtual_input_state("mouse_y") * camera_delta).to_radians(), - (input_manager.get_virtual_input_state("mouse_x") * camera_delta).to_radians(), - 0.0, - ); - - if self.rotation.x > FRAC_PI_2 { - self.rotation = Vec3::new(FRAC_PI_2, self.rotation.y, 0.0); - } - - if self.rotation.x < -FRAC_PI_2 { - self.rotation = Vec3::new(-FRAC_PI_2, self.rotation.y, 0.0); - } - - let movement_delta = movement_speed * timer.delta_time(); - - let (yaw_sin, yaw_cos) = self.rotation.y.sin_cos(); - let forward = Vec3::new(yaw_cos, 0.0, yaw_sin).normalize(); - let right = Vec3::new(-yaw_sin, 0.0, yaw_cos).normalize(); - - let tx = input_manager.get_virtual_input_state("move_right") * movement_delta; - self.position += tx * right; - - let tz = input_manager.get_virtual_input_state("move_forward") * movement_delta; - self.position += tz * forward; - } - pub fn update_projection(&mut self, window_aspect_ratio: f32) { if self.aspect_ratio != window_aspect_ratio { self.aspect_ratio = window_aspect_ratio; @@ -93,23 +56,16 @@ impl Camera3D { self.projection = projection; } - pub fn get_position(&self) -> Vec3 { - self.position - } - - pub fn get_rotation(&self) -> Vec3 { - self.rotation - } - pub fn create_buffer( &self, + transform: &Camera3DTransform, memory_allocator: &Arc, ) -> Result, Validated> { - let (sin_pitch, cos_pitch) = self.rotation.x.sin_cos(); - let (sin_yaw, cos_yaw) = self.rotation.y.sin_cos(); + let (sin_pitch, cos_pitch) = transform.rotation.x.sin_cos(); + let (sin_yaw, cos_yaw) = transform.rotation.y.sin_cos(); let view_matrix = Mat4::look_to_rh( - self.position, + transform.position, Vec3::new(cos_pitch * cos_yaw, sin_pitch, cos_pitch * sin_yaw).normalize(), Vec3::Y, ); diff --git a/src/core/render/primitives/transform.rs b/src/core/render/primitives/transform.rs index 85bd01b..9bbda47 100644 --- a/src/core/render/primitives/transform.rs +++ b/src/core/render/primitives/transform.rs @@ -46,30 +46,6 @@ impl Transform { } } - pub fn rotate(&mut self, rotation: Quat) { - self.rotation *= rotation; - } - - pub fn translate(&mut self, translation: Vec3) { - self.position += translation; - } - - pub fn scale(&mut self, scale: Vec3) { - self.scale *= scale; - } - - pub fn set_position(&mut self, position: Vec3) { - self.position = position; - } - - pub fn set_rotation(&mut self, rotation: Quat) { - self.rotation = rotation; - } - - pub fn set_scale(&mut self, scale: Vec3) { - self.scale = scale; - } - /// Get the transformation matrix (immutable - recalculates each time) pub fn matrix(&self) -> Mat4 { Mat4::from_translation(self.position) diff --git a/src/core/render/primitives/velocity.rs b/src/core/render/primitives/velocity.rs index 6e16db4..19899aa 100644 --- a/src/core/render/primitives/velocity.rs +++ b/src/core/render/primitives/velocity.rs @@ -1,7 +1,7 @@ use bevy_ecs::prelude::*; use glam::Vec3; -#[derive(Component, Debug, Clone)] +#[derive(Component, Debug, Clone, Default)] pub struct Velocity { pub linear: Vec3, pub angular: Vec3, diff --git a/src/game/scenes/main_scene.rs b/src/game/scenes/main_scene.rs index 45e7dfa..fc7f3c9 100644 --- a/src/game/scenes/main_scene.rs +++ b/src/game/scenes/main_scene.rs @@ -6,7 +6,7 @@ use crate::core::app::DEPTH_IMAGE_ID; use crate::core::app::context::WindowContext; use crate::core::app::user_event::UserEvent; use crate::core::input::InputManagerResource; -use crate::core::render::primitives::camera::Camera3D; +use crate::core::render::primitives::camera::{Camera3D, Camera3DTransform}; use crate::core::render::primitives::transform::Transform; use crate::core::render::primitives::velocity::Velocity; use crate::core::render::primitives::vulkan_resource::{ @@ -49,7 +49,10 @@ pub struct MainSceneState { } #[derive(Resource)] -pub struct CameraSpeed(f32); +pub struct MovementSpeed(f32); + +#[derive(Resource)] +pub struct CameraSensitivity(f32); #[derive(Default)] pub struct MainScene { @@ -109,21 +112,31 @@ impl AsScene for MainScene { obj.into_iter().next().unwrap() }; - let camera = window_context.with_renderer(|renderer| { + world.spawn(( Camera3D::new( - renderer.aspect_ratio(), + window_context.get_aspect_ratio(), std::f32::consts::FRAC_PI_2, 0.01, 1000.0, - ) - }); - world.insert_resource(CameraSpeed(50.0)); - world.insert_resource(camera); + ), + Camera3DTransform { + position: Vec3::ZERO, + rotation: Vec3::ZERO, + }, + )); + + world.insert_resource(MovementSpeed(50.0)); + world.insert_resource(CameraSensitivity(10.0)); let mut scheduler = Schedule::default(); - scheduler.add_systems(update_velocity_system); - scheduler.add_systems(update_timer_system); - scheduler.add_systems(update_camera_system); + scheduler.add_systems( + ( + update_camera_system, + update_velocity_system, + update_timer_system, + ) + .chain(), + ); world.insert_resource(Timer::new()); Self::create_entities(world, 100, 10.0, 10.0); @@ -144,7 +157,7 @@ impl AsScene for MainScene { let state = self.state.as_mut().unwrap(); { - let mut camera = world.resource_mut::(); + let mut camera = world.query::<&mut Camera3D>().single_mut(world).unwrap(); camera.update_projection(window_context.get_aspect_ratio()); } @@ -212,11 +225,18 @@ impl AsScene for MainScene { } // Create camera uniform using the actual camera - let camera_uniform = Arc::new( - world - .resource::() - .create_buffer(VulkanMemoryAllocator::get_from_world(world))?, - ); + let camera_uniform = { + let result = world + .query_filtered::<(&Camera3D, &Camera3DTransform), With>() + .single(&world) + .unwrap(); + + Arc::new( + result + .0 + .create_buffer(result.1, VulkanMemoryAllocator::get_from_world(world))?, + ) + }; let square_transforms = world .query_filtered::<&Transform, With>() .iter(&world) @@ -286,7 +306,10 @@ impl AsScene for MainScene { let delta_time = window_context.get_delta_time(); let window_id = window_context.window_id; let window_size = window_context.get_window_size(); - let camera = world.resource::(); + let camera_transform = world + .query_filtered::<&Camera3DTransform, With>() + .single(&world) + .unwrap(); let render_future = window_context.with_gui_mut(|gui| { gui.immediate_ui(|gui| { let ctx = gui.context(); @@ -318,7 +341,7 @@ impl AsScene for MainScene { ui.separator(); ui.label("Position caméra:"); - let position = camera.get_position(); + let position = camera_transform.position; ui.label(format!(" X: {:.2}", position[0])); ui.label(format!(" Y: {:.2}", position[1])); ui.label(format!(" Z: {:.2}", position[2])); @@ -326,7 +349,7 @@ impl AsScene for MainScene { ui.separator(); ui.label("Rotation caméra:"); - let rotation = camera.get_rotation(); + let rotation = camera_transform.rotation; ui.label(format!(" Yaw: {:.2}°", rotation.y.to_degrees())); ui.label(format!(" Pitch: {:.2}°", rotation.x.to_degrees())); @@ -415,7 +438,7 @@ fn update_velocity_system(mut query: Query<(&mut Transform, &Velocity)>, time: R let delta_time = time.delta_time(); // Update linear position - transform.translate(velocity.linear * delta_time); + transform.position += velocity.linear * delta_time; // Update angular rotation let angular_delta = velocity.angular * delta_time; @@ -425,7 +448,7 @@ fn update_velocity_system(mut query: Query<(&mut Transform, &Velocity)>, time: R angular_delta.y, angular_delta.z, ); - transform.rotate(rotation_delta); + transform.rotation *= rotation_delta; } } @@ -434,11 +457,40 @@ fn update_timer_system(mut timer: ResMut) { } fn update_camera_system( - mut camera: ResMut, + mut query: Query<&mut Camera3DTransform, With>, input_manager: Res, - timer: Res, - camera_speed: Res, + camera_sensitivity: Res, + movement_speed: Res, + time: Res, ) { let input_manager = input_manager.0.read().unwrap(); - camera.update(&input_manager, &timer, camera_speed.0, 10.0); + let mut camera_transform = query.single_mut().unwrap(); + + let delta_time = time.delta_time(); + + camera_transform.rotation += Vec3::new( + (input_manager.get_virtual_input_state("mouse_y") * camera_sensitivity.0 * delta_time) + .to_radians(), + (input_manager.get_virtual_input_state("mouse_x") * camera_sensitivity.0 * delta_time) + .to_radians(), + 0.0, + ); + + if camera_transform.rotation.x > std::f32::consts::FRAC_PI_2 { + camera_transform.rotation.x = std::f32::consts::FRAC_PI_2; + } + + if camera_transform.rotation.x < -std::f32::consts::FRAC_PI_2 { + camera_transform.rotation.x = -std::f32::consts::FRAC_PI_2; + } + + let (yaw_sin, yaw_cos) = camera_transform.rotation.y.sin_cos(); + let forward = Vec3::new(yaw_cos, 0.0, yaw_sin).normalize(); + let right = Vec3::new(-yaw_sin, 0.0, yaw_cos).normalize(); + + let tx = input_manager.get_virtual_input_state("move_right") * movement_speed.0 * delta_time; + camera_transform.position += tx * right; + + let tz = input_manager.get_virtual_input_state("move_forward") * movement_speed.0 * delta_time; + camera_transform.position += tz * forward; }