From 998aa68da1321dcfb7a3018353194d3df43c95f4 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Thu, 29 May 2025 13:54:00 +0200 Subject: [PATCH] camera: fix camera movement --- README.md | 7 ++++ flake.nix | 3 +- src/core/app.rs | 5 ++- src/core/render/primitives/camera.rs | 60 +++++++++++++++++----------- src/core/render/primitives/mvp.rs | 14 ++----- src/core/render/primitives/vertex.rs | 28 +------------ src/core/scene/manager.rs | 4 +- src/core/scene/mod.rs | 4 +- src/game/main_scene.rs | 59 ++++++++++++--------------- src/main.rs | 2 - 10 files changed, 83 insertions(+), 103 deletions(-) diff --git a/README.md b/README.md index c74b5d4..6e4bad1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@ # Project +Run renderdoc on wayland: + +```console +WAYLAND_DISPLAY= QT_QPA_PLATFORM=xcb qrenderdoc +``` +> Not supported yet https://github.com/baldurk/renderdoc/issues/853 + ## Usefull links - https://vulkan-tutorial.com/fr/Introduction diff --git a/flake.nix b/flake.nix index dbd8d4c..c5bbd9a 100644 --- a/flake.nix +++ b/flake.nix @@ -39,6 +39,7 @@ libxkbcommon wayland libGL + # Xorg xorg.libX11 xorg.libXcursor @@ -64,7 +65,7 @@ ++ packages; LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; - VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d:${pkgs.renderdoc}/share/vulkan/implicit_layer.d"; + VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d"; RUST_LOG = "debug,rust_vulkan_test=trace"; }; in diff --git a/src/core/app.rs b/src/core/app.rs index 5865cb1..33a5dc1 100644 --- a/src/core/app.rs +++ b/src/core/app.rs @@ -65,6 +65,7 @@ impl ApplicationHandler for App { renderer.swapchain_format(), GuiConfig { is_overlay: true, + allow_srgb_render_target: true, ..Default::default() }, ) @@ -132,7 +133,9 @@ impl ApplicationHandler for App { self.scene_manager.load_scene_if_not_loaded(&scene_context); if let Some(scene) = self.scene_manager.current_scene_mut() { - scene.update(&scene_context); + if let Err(e) = scene.update(&scene_context) { + log::error!("Error updating scene: {}", e); + } let acquire_future = renderer.acquire(None, |_| {}).unwrap(); let acquire_future = scene.render( diff --git a/src/core/render/primitives/camera.rs b/src/core/render/primitives/camera.rs index c322c7c..34950ce 100644 --- a/src/core/render/primitives/camera.rs +++ b/src/core/render/primitives/camera.rs @@ -1,6 +1,6 @@ -use std::{f32::consts::PI, sync::Arc}; +use std::{f32::consts::FRAC_PI_2, sync::Arc}; -use glam::{Mat4, Quat, Vec3}; +use glam::{Mat4, Vec3, Vec4}; use vulkano::{ Validated, buffer::{AllocateBufferError, Subbuffer}, @@ -13,7 +13,6 @@ use super::mvp::MVP; #[derive(Default)] pub struct Camera { - view: Mat4, projection: Mat4, position: Vec3, @@ -21,9 +20,8 @@ pub struct Camera { } impl Camera { - pub fn new(view: Mat4, projection: Mat4) -> Self { + pub fn new(projection: Mat4) -> Self { Self { - view, projection, position: Vec3::ZERO, rotation: Vec3::ZERO, @@ -45,43 +43,57 @@ impl Camera { 0.0, ); - if self.rotation.x > 90.0 { - self.rotation = Vec3::new(90.0, self.rotation.y, 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 < -90.0 { - self.rotation = Vec3::new(-90.0, 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.x += tx * (self.rotation.y).cos(); - self.position.z += tx * (self.rotation.y).sin(); - - self.position.x += tz * (self.rotation.y + PI / 2.0).cos(); - self.position.z += tz * (self.rotation.y + PI / 2.0).sin(); + self.position += tz * forward; } pub fn set_projection(&mut self, projection: Mat4) { self.projection = projection; } + pub fn get_position(&self) -> Vec3 { + self.position + } + + pub fn get_rotation(&self) -> Vec3 { + self.rotation + } + pub fn create_buffer( &self, memory_allocator: &Arc, ) -> Result, Validated> { - let mut world_matrix = Mat4::IDENTITY; - world_matrix *= Mat4::from_quat(Quat::from_euler( - glam::EulerRot::XYX, - self.rotation.x, - self.rotation.y, - self.rotation.z, - )); - world_matrix *= Mat4::from_translation(self.position); + let (sin_pitch, cos_pitch) = self.rotation.x.sin_cos(); + let (sin_yaw, cos_yaw) = self.rotation.y.sin_cos(); - MVP::new(&world_matrix, &self.view, &self.projection).into_buffer(memory_allocator) + let view_matrix = Mat4::look_to_rh( + self.position, + Vec3::new(cos_pitch * cos_yaw, sin_pitch, cos_pitch * sin_yaw).normalize(), + Vec3::Y, + ); + + MVP { + model: Mat4::IDENTITY.to_cols_array_2d(), + view: view_matrix.to_cols_array_2d(), + projection: self.projection.to_cols_array_2d(), + } + .into_buffer(memory_allocator) } } diff --git a/src/core/render/primitives/mvp.rs b/src/core/render/primitives/mvp.rs index fb73ad3..b06b55f 100644 --- a/src/core/render/primitives/mvp.rs +++ b/src/core/render/primitives/mvp.rs @@ -10,20 +10,12 @@ use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, Standar #[derive(BufferContents, Clone, Copy)] #[repr(C)] pub struct MVP { - world: [[f32; 4]; 4], - view: [[f32; 4]; 4], - projection: [[f32; 4]; 4], + pub model: [[f32; 4]; 4], + pub view: [[f32; 4]; 4], + pub projection: [[f32; 4]; 4], } impl MVP { - pub fn new(world: &Mat4, view: &Mat4, projection: &Mat4) -> Self { - Self { - world: world.to_cols_array_2d(), - view: view.to_cols_array_2d(), - projection: projection.to_cols_array_2d(), - } - } - pub fn into_buffer( self, memory_allocator: &Arc, diff --git a/src/core/render/primitives/vertex.rs b/src/core/render/primitives/vertex.rs index b35588c..566df22 100644 --- a/src/core/render/primitives/vertex.rs +++ b/src/core/render/primitives/vertex.rs @@ -1,9 +1,4 @@ -use std::sync::Arc; -use vulkano::Validated; -use vulkano::buffer::{ - AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer, -}; -use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}; +use vulkano::buffer::BufferContents; use vulkano::pipeline::graphics::vertex_input::Vertex; #[derive(BufferContents, Vertex)] @@ -15,24 +10,3 @@ pub struct Vertex2D { #[format(R32G32_SFLOAT)] pub uv: [f32; 2], } - -impl Vertex2D { - pub fn create_buffer( - vertices: Vec, - memory_allocator: &Arc, - ) -> Result, Validated> { - Buffer::from_iter( - memory_allocator.clone(), - BufferCreateInfo { - usage: BufferUsage::VERTEX_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - vertices, - ) - } -} diff --git a/src/core/scene/manager.rs b/src/core/scene/manager.rs index 8e25a74..e2043f2 100644 --- a/src/core/scene/manager.rs +++ b/src/core/scene/manager.rs @@ -14,7 +14,9 @@ impl SceneManager { pub fn load_scene_if_not_loaded(&mut self, scene_context: &SceneContext) { if let Some(current_scene) = self.current_scene.as_mut() { if !current_scene.loaded() { - current_scene.load(scene_context); + if let Err(e) = current_scene.load(scene_context) { + log::error!("Error loading scene: {}", e); + } } } } diff --git a/src/core/scene/mod.rs b/src/core/scene/mod.rs index dc97ece..a71bfbb 100644 --- a/src/core/scene/mod.rs +++ b/src/core/scene/mod.rs @@ -11,8 +11,8 @@ pub use manager::SceneManager; pub trait Scene { fn loaded(&self) -> bool; - fn load(&mut self, scene_context: &SceneContext); - fn update(&mut self, scene_context: &SceneContext); + fn load(&mut self, scene_context: &SceneContext) -> Result<(), Box>; + fn update(&mut self, scene_context: &SceneContext) -> Result<(), Box>; fn render( &mut self, image_view: &Arc, diff --git a/src/game/main_scene.rs b/src/game/main_scene.rs index 3000746..0aa18ac 100644 --- a/src/game/main_scene.rs +++ b/src/game/main_scene.rs @@ -5,7 +5,7 @@ use crate::core::render::texture::Texture; use crate::core::scene::Scene; use crate::core::scene::SceneContext; use egui_winit_vulkano::{Gui, egui}; -use glam::{Mat4, Vec3}; +use glam::Mat4; use vulkano::{ command_buffer::{ AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract, @@ -36,48 +36,36 @@ impl Scene for MainScene { self.state.is_some() } - fn load(&mut self, scene_context: &SceneContext) { + fn load(&mut self, scene_context: &SceneContext) -> Result<(), Box> { let square = Square::new( &scene_context.device, &scene_context.memory_allocator, scene_context.swapchain_format, - ) - .unwrap(); + )?; - let camera = Camera::new( - Mat4::look_at_rh( - Vec3::new(0.3, 0.3, 1.0), - Vec3::new(0.0, 0.0, 0.0), - Vec3::new(0.0, -1.0, 0.0), - ), - Mat4::perspective_rh_gl( - std::f32::consts::FRAC_PI_2, - scene_context.aspect_ratio, - 0.01, - 100.0, - ), - ); + let camera = Camera::new(Mat4::perspective_rh_gl( + std::f32::consts::FRAC_PI_2, + scene_context.aspect_ratio, + 0.01, + 1000.0, + )); let mut uploads = AutoCommandBufferBuilder::primary( scene_context.command_buffer_allocator.clone(), scene_context.graphics_queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, - ) - .unwrap(); + )?; let texture = Texture::from_file( &scene_context.device, &scene_context.memory_allocator, &mut uploads, "res/textures/wooden-crate.jpg", - ) - .unwrap(); + )?; let _ = uploads - .build() - .unwrap() - .execute(scene_context.graphics_queue.clone()) - .unwrap(); + .build()? + .execute(scene_context.graphics_queue.clone())?; self.state = Some(MainSceneState { square, @@ -85,10 +73,12 @@ impl Scene for MainScene { texture, speed: 50.0, }); + + Ok(()) } - fn update(&mut self, scene_context: &SceneContext) { - let state = self.state.as_mut().unwrap(); + fn update(&mut self, scene_context: &SceneContext) -> Result<(), Box> { + let state = self.state.as_mut().ok_or("State not found")?; state.camera.update( &scene_context.input_manager, &scene_context.timer, @@ -96,12 +86,7 @@ impl Scene for MainScene { 10.0, ); - state.camera.set_projection(Mat4::perspective_rh_gl( - std::f32::consts::FRAC_PI_2, - scene_context.aspect_ratio, - 0.01, - 100.0, - )); + Ok(()) } fn render( @@ -111,7 +96,7 @@ impl Scene for MainScene { scene_context: &SceneContext, gui: &mut Gui, ) -> Result, Box> { - let state = self.state.as_ref().unwrap(); + let state = self.state.as_ref().ok_or("State not found")?; let mut builder = AutoCommandBufferBuilder::primary( scene_context.command_buffer_allocator.clone(), @@ -174,6 +159,12 @@ impl Scene for MainScene { "Delta time: {:?}", scene_context.timer.delta_time() )); + + ui.label(format!( + "Position: {:?}, Rotation: {:?}", + state.camera.get_position(), + state.camera.get_rotation() + )); }); }); diff --git a/src/main.rs b/src/main.rs index 7a4284c..ffe5f72 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,6 @@ fn main() { vec![ VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyW), AxisDirection::Normal), VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyS), AxisDirection::Invert), - VirtualBinding::Axis(0, AxisDirection::Normal, 0.0), ], ), ( @@ -29,7 +28,6 @@ fn main() { vec![ VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyD), AxisDirection::Normal), VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyA), AxisDirection::Invert), - VirtualBinding::Axis(1, AxisDirection::Normal, 0.0), ], ), (