camera: fix camera movement
Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 8m11s

This commit is contained in:
Florian RICHER 2025-05-29 13:54:00 +02:00
parent f835941432
commit 998aa68da1
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
10 changed files with 83 additions and 103 deletions

View file

@ -1,5 +1,12 @@
# Project # 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 ## Usefull links
- https://vulkan-tutorial.com/fr/Introduction - https://vulkan-tutorial.com/fr/Introduction

View file

@ -39,6 +39,7 @@
libxkbcommon libxkbcommon
wayland wayland
libGL libGL
# Xorg # Xorg
xorg.libX11 xorg.libX11
xorg.libXcursor xorg.libXcursor
@ -64,7 +65,7 @@
++ packages; ++ packages;
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; 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"; RUST_LOG = "debug,rust_vulkan_test=trace";
}; };
in in

View file

@ -65,6 +65,7 @@ impl ApplicationHandler for App {
renderer.swapchain_format(), renderer.swapchain_format(),
GuiConfig { GuiConfig {
is_overlay: true, is_overlay: true,
allow_srgb_render_target: true,
..Default::default() ..Default::default()
}, },
) )
@ -132,7 +133,9 @@ impl ApplicationHandler for App {
self.scene_manager.load_scene_if_not_loaded(&scene_context); self.scene_manager.load_scene_if_not_loaded(&scene_context);
if let Some(scene) = self.scene_manager.current_scene_mut() { 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 = renderer.acquire(None, |_| {}).unwrap();
let acquire_future = scene.render( let acquire_future = scene.render(

View file

@ -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::{ use vulkano::{
Validated, Validated,
buffer::{AllocateBufferError, Subbuffer}, buffer::{AllocateBufferError, Subbuffer},
@ -13,7 +13,6 @@ use super::mvp::MVP;
#[derive(Default)] #[derive(Default)]
pub struct Camera { pub struct Camera {
view: Mat4,
projection: Mat4, projection: Mat4,
position: Vec3, position: Vec3,
@ -21,9 +20,8 @@ pub struct Camera {
} }
impl Camera { impl Camera {
pub fn new(view: Mat4, projection: Mat4) -> Self { pub fn new(projection: Mat4) -> Self {
Self { Self {
view,
projection, projection,
position: Vec3::ZERO, position: Vec3::ZERO,
rotation: Vec3::ZERO, rotation: Vec3::ZERO,
@ -45,43 +43,57 @@ impl Camera {
0.0, 0.0,
); );
if self.rotation.x > 90.0 { if self.rotation.x > FRAC_PI_2 {
self.rotation = Vec3::new(90.0, self.rotation.y, 0.0); self.rotation = Vec3::new(FRAC_PI_2, self.rotation.y, 0.0);
} }
if self.rotation.x < -90.0 { if self.rotation.x < -FRAC_PI_2 {
self.rotation = Vec3::new(-90.0, self.rotation.y, 0.0); self.rotation = Vec3::new(-FRAC_PI_2, self.rotation.y, 0.0);
} }
let movement_delta = movement_speed * timer.delta_time(); 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; 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; let tz = input_manager.get_virtual_input_state("move_forward") * movement_delta;
self.position += tz * forward;
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();
} }
pub fn set_projection(&mut self, projection: Mat4) { pub fn set_projection(&mut self, projection: Mat4) {
self.projection = projection; self.projection = projection;
} }
pub fn get_position(&self) -> Vec3 {
self.position
}
pub fn get_rotation(&self) -> Vec3 {
self.rotation
}
pub fn create_buffer( pub fn create_buffer(
&self, &self,
memory_allocator: &Arc<StandardMemoryAllocator>, memory_allocator: &Arc<StandardMemoryAllocator>,
) -> Result<Subbuffer<[MVP]>, Validated<AllocateBufferError>> { ) -> Result<Subbuffer<[MVP]>, Validated<AllocateBufferError>> {
let mut world_matrix = Mat4::IDENTITY; let (sin_pitch, cos_pitch) = self.rotation.x.sin_cos();
world_matrix *= Mat4::from_quat(Quat::from_euler( let (sin_yaw, cos_yaw) = self.rotation.y.sin_cos();
glam::EulerRot::XYX,
self.rotation.x,
self.rotation.y,
self.rotation.z,
));
world_matrix *= Mat4::from_translation(self.position);
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)
} }
} }

View file

@ -10,20 +10,12 @@ use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, Standar
#[derive(BufferContents, Clone, Copy)] #[derive(BufferContents, Clone, Copy)]
#[repr(C)] #[repr(C)]
pub struct MVP { pub struct MVP {
world: [[f32; 4]; 4], pub model: [[f32; 4]; 4],
view: [[f32; 4]; 4], pub view: [[f32; 4]; 4],
projection: [[f32; 4]; 4], pub projection: [[f32; 4]; 4],
} }
impl MVP { 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( pub fn into_buffer(
self, self,
memory_allocator: &Arc<StandardMemoryAllocator>, memory_allocator: &Arc<StandardMemoryAllocator>,

View file

@ -1,9 +1,4 @@
use std::sync::Arc; use vulkano::buffer::BufferContents;
use vulkano::Validated;
use vulkano::buffer::{
AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer,
};
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator};
use vulkano::pipeline::graphics::vertex_input::Vertex; use vulkano::pipeline::graphics::vertex_input::Vertex;
#[derive(BufferContents, Vertex)] #[derive(BufferContents, Vertex)]
@ -15,24 +10,3 @@ pub struct Vertex2D {
#[format(R32G32_SFLOAT)] #[format(R32G32_SFLOAT)]
pub uv: [f32; 2], pub uv: [f32; 2],
} }
impl Vertex2D {
pub fn create_buffer(
vertices: Vec<Vertex2D>,
memory_allocator: &Arc<StandardMemoryAllocator>,
) -> Result<Subbuffer<[Vertex2D]>, Validated<AllocateBufferError>> {
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,
)
}
}

View file

@ -14,7 +14,9 @@ impl SceneManager {
pub fn load_scene_if_not_loaded(&mut self, scene_context: &SceneContext) { pub fn load_scene_if_not_loaded(&mut self, scene_context: &SceneContext) {
if let Some(current_scene) = self.current_scene.as_mut() { if let Some(current_scene) = self.current_scene.as_mut() {
if !current_scene.loaded() { if !current_scene.loaded() {
current_scene.load(scene_context); if let Err(e) = current_scene.load(scene_context) {
log::error!("Error loading scene: {}", e);
}
} }
} }
} }

View file

@ -11,8 +11,8 @@ pub use manager::SceneManager;
pub trait Scene { pub trait Scene {
fn loaded(&self) -> bool; fn loaded(&self) -> bool;
fn load(&mut self, scene_context: &SceneContext); fn load(&mut self, scene_context: &SceneContext) -> Result<(), Box<dyn Error>>;
fn update(&mut self, scene_context: &SceneContext); fn update(&mut self, scene_context: &SceneContext) -> Result<(), Box<dyn Error>>;
fn render( fn render(
&mut self, &mut self,
image_view: &Arc<ImageView>, image_view: &Arc<ImageView>,

View file

@ -5,7 +5,7 @@ use crate::core::render::texture::Texture;
use crate::core::scene::Scene; use crate::core::scene::Scene;
use crate::core::scene::SceneContext; use crate::core::scene::SceneContext;
use egui_winit_vulkano::{Gui, egui}; use egui_winit_vulkano::{Gui, egui};
use glam::{Mat4, Vec3}; use glam::Mat4;
use vulkano::{ use vulkano::{
command_buffer::{ command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract, AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract,
@ -36,48 +36,36 @@ impl Scene for MainScene {
self.state.is_some() self.state.is_some()
} }
fn load(&mut self, scene_context: &SceneContext) { fn load(&mut self, scene_context: &SceneContext) -> Result<(), Box<dyn Error>> {
let square = Square::new( let square = Square::new(
&scene_context.device, &scene_context.device,
&scene_context.memory_allocator, &scene_context.memory_allocator,
scene_context.swapchain_format, scene_context.swapchain_format,
) )?;
.unwrap();
let camera = Camera::new( let camera = Camera::new(Mat4::perspective_rh_gl(
Mat4::look_at_rh( std::f32::consts::FRAC_PI_2,
Vec3::new(0.3, 0.3, 1.0), scene_context.aspect_ratio,
Vec3::new(0.0, 0.0, 0.0), 0.01,
Vec3::new(0.0, -1.0, 0.0), 1000.0,
), ));
Mat4::perspective_rh_gl(
std::f32::consts::FRAC_PI_2,
scene_context.aspect_ratio,
0.01,
100.0,
),
);
let mut uploads = AutoCommandBufferBuilder::primary( let mut uploads = AutoCommandBufferBuilder::primary(
scene_context.command_buffer_allocator.clone(), scene_context.command_buffer_allocator.clone(),
scene_context.graphics_queue.queue_family_index(), scene_context.graphics_queue.queue_family_index(),
CommandBufferUsage::OneTimeSubmit, CommandBufferUsage::OneTimeSubmit,
) )?;
.unwrap();
let texture = Texture::from_file( let texture = Texture::from_file(
&scene_context.device, &scene_context.device,
&scene_context.memory_allocator, &scene_context.memory_allocator,
&mut uploads, &mut uploads,
"res/textures/wooden-crate.jpg", "res/textures/wooden-crate.jpg",
) )?;
.unwrap();
let _ = uploads let _ = uploads
.build() .build()?
.unwrap() .execute(scene_context.graphics_queue.clone())?;
.execute(scene_context.graphics_queue.clone())
.unwrap();
self.state = Some(MainSceneState { self.state = Some(MainSceneState {
square, square,
@ -85,10 +73,12 @@ impl Scene for MainScene {
texture, texture,
speed: 50.0, speed: 50.0,
}); });
Ok(())
} }
fn update(&mut self, scene_context: &SceneContext) { fn update(&mut self, scene_context: &SceneContext) -> Result<(), Box<dyn Error>> {
let state = self.state.as_mut().unwrap(); let state = self.state.as_mut().ok_or("State not found")?;
state.camera.update( state.camera.update(
&scene_context.input_manager, &scene_context.input_manager,
&scene_context.timer, &scene_context.timer,
@ -96,12 +86,7 @@ impl Scene for MainScene {
10.0, 10.0,
); );
state.camera.set_projection(Mat4::perspective_rh_gl( Ok(())
std::f32::consts::FRAC_PI_2,
scene_context.aspect_ratio,
0.01,
100.0,
));
} }
fn render( fn render(
@ -111,7 +96,7 @@ impl Scene for MainScene {
scene_context: &SceneContext, scene_context: &SceneContext,
gui: &mut Gui, gui: &mut Gui,
) -> Result<Box<dyn GpuFuture>, Box<dyn Error>> { ) -> Result<Box<dyn GpuFuture>, Box<dyn Error>> {
let state = self.state.as_ref().unwrap(); let state = self.state.as_ref().ok_or("State not found")?;
let mut builder = AutoCommandBufferBuilder::primary( let mut builder = AutoCommandBufferBuilder::primary(
scene_context.command_buffer_allocator.clone(), scene_context.command_buffer_allocator.clone(),
@ -174,6 +159,12 @@ impl Scene for MainScene {
"Delta time: {:?}", "Delta time: {:?}",
scene_context.timer.delta_time() scene_context.timer.delta_time()
)); ));
ui.label(format!(
"Position: {:?}, Rotation: {:?}",
state.camera.get_position(),
state.camera.get_rotation()
));
}); });
}); });

View file

@ -21,7 +21,6 @@ fn main() {
vec![ vec![
VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyW), AxisDirection::Normal), VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyW), AxisDirection::Normal),
VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyS), AxisDirection::Invert), VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyS), AxisDirection::Invert),
VirtualBinding::Axis(0, AxisDirection::Normal, 0.0),
], ],
), ),
( (
@ -29,7 +28,6 @@ fn main() {
vec![ vec![
VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyD), AxisDirection::Normal), VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyD), AxisDirection::Normal),
VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyA), AxisDirection::Invert), VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyA), AxisDirection::Invert),
VirtualBinding::Axis(1, AxisDirection::Normal, 0.0),
], ],
), ),
( (