From 4f96a1e4b5c0e2db0e148554f8f197571be178f4 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sat, 7 Jun 2025 21:13:31 +0200 Subject: [PATCH] Update transform --- src/core/render/primitives/transform.rs | 92 +++++++++++++++++++++---- src/game/scenes/main_scene.rs | 33 +++++---- 2 files changed, 99 insertions(+), 26 deletions(-) diff --git a/src/core/render/primitives/transform.rs b/src/core/render/primitives/transform.rs index a108d14..d7c1249 100644 --- a/src/core/render/primitives/transform.rs +++ b/src/core/render/primitives/transform.rs @@ -10,13 +10,17 @@ use vulkano::{ use crate::core::render::primitives::{AsBindableBuffer, AsVertexBuffer}; +#[derive(Debug, Clone)] pub struct Transform { pub position: Vec3, pub rotation: Quat, pub scale: Vec3, + // Cache to avoid unnecessary recalculations + cached_matrix: Option, + dirty: bool, } -#[derive(BufferContents, Vertex, Clone, Copy)] +#[derive(BufferContents, Vertex, Clone, Copy, Debug)] #[repr(C)] pub struct TransformRaw { #[format(R32G32B32A32_SFLOAT)] @@ -26,49 +30,113 @@ pub struct TransformRaw { impl Default for Transform { fn default() -> Self { Self { - position: Vec3::default(), - rotation: Quat::default(), + position: Vec3::ZERO, + rotation: Quat::IDENTITY, scale: Vec3::ONE, + cached_matrix: None, + dirty: true, } } } impl Transform { + pub fn new(position: Vec3, rotation: Quat, scale: Vec3) -> Self { + Self { + position, + rotation, + scale, + cached_matrix: None, + dirty: true, + } + } + pub fn rotate(&mut self, rotation: Quat) { self.rotation *= rotation; + self.mark_dirty(); } pub fn translate(&mut self, translation: Vec3) { self.position += translation; + self.mark_dirty(); } pub fn scale(&mut self, scale: Vec3) { self.scale *= scale; + self.mark_dirty(); } - pub fn to_raw_tranform(&self) -> TransformRaw { + pub fn set_position(&mut self, position: Vec3) { + self.position = position; + self.mark_dirty(); + } + + pub fn set_rotation(&mut self, rotation: Quat) { + self.rotation = rotation; + self.mark_dirty(); + } + + pub fn set_scale(&mut self, scale: Vec3) { + self.scale = scale; + self.mark_dirty(); + } + + fn mark_dirty(&mut self) { + self.dirty = true; + self.cached_matrix = None; + } + + /// Get the transformation matrix (immutable - recalculates each time) + pub fn matrix(&self) -> Mat4 { + Mat4::from_translation(self.position) + * Mat4::from_quat(self.rotation) + * Mat4::from_scale(self.scale) + } + + /// Convert to GPU-ready format (immutable - recalculates each time) + pub fn to_raw(&self) -> TransformRaw { TransformRaw { - model: (Mat4::from_translation(self.position) - * Mat4::from_quat(self.rotation) - * Mat4::from_scale(self.scale)) - .to_cols_array_2d(), + model: self.matrix().to_cols_array_2d(), } } + /// Create a buffer from transforms (immutable - recalculates each time) pub fn create_buffer( memory_allocator: &Arc, transforms: &[Transform], ) -> Result, Validated> { TransformRaw::create_vertex_buffer( memory_allocator, - &transforms - .iter() - .map(|t| t.to_raw_tranform()) - .collect::>(), + &transforms.iter().map(|t| t.to_raw()).collect::>(), ) } } +impl From<&Transform> for TransformRaw { + fn from(transform: &Transform) -> Self { + transform.to_raw() + } +} + +impl From for TransformRaw { + fn from(matrix: Mat4) -> Self { + Self { + model: matrix.to_cols_array_2d(), + } + } +} + +impl TransformRaw { + pub fn from_matrix(matrix: Mat4) -> Self { + Self { + model: matrix.to_cols_array_2d(), + } + } + + pub fn to_matrix(&self) -> Mat4 { + Mat4::from_cols_array_2d(&self.model) + } +} + impl AsBindableBuffer for TransformRaw { type BufferData = TransformRaw; diff --git a/src/game/scenes/main_scene.rs b/src/game/scenes/main_scene.rs index 37fd4ed..933bccb 100644 --- a/src/game/scenes/main_scene.rs +++ b/src/game/scenes/main_scene.rs @@ -58,19 +58,16 @@ impl Scene for MainScene { let instance_spacing = 10.0; let num_instances_per_row = (num_instances as f32 / instance_spacing).ceil() as u32; let instances: Vec = (0..num_instances) - .map(|i| Transform { - position: Vec3::new( - (i % num_instances_per_row) as f32 * (instance_spacing + instance_size), - 0.0, - (i / num_instances_per_row) as f32 * (instance_spacing + instance_size), - ), - rotation: Quat::from_euler( - EulerRot::XYZ, - 0.0, - rand::random_range(0.0..=360.0), - 0.0, - ), - scale: Vec3::new(instance_size, instance_size, instance_size), + .map(|i| { + Transform::new( + Vec3::new( + (i % num_instances_per_row) as f32 * (instance_spacing + instance_size), + 0.0, + (i / num_instances_per_row) as f32 * (instance_spacing + instance_size), + ), + Quat::from_euler(EulerRot::XYZ, 0.0, rand::random_range(0.0..=360.0), 0.0), + Vec3::new(instance_size, instance_size, instance_size), + ) }) .collect(); @@ -129,6 +126,14 @@ impl Scene for MainScene { }); }); + let delta_time = app_context.get_delta_time(); + for (i, instance) in state.instances.iter_mut().enumerate() { + let rotation_speed = (i % 10) as f32; + let rotation_delta = Quat::from_rotation_y(rotation_speed * delta_time); + + instance.rotate(rotation_delta); + } + if app_context .with_input_manager(|input_manager| input_manager.get_virtual_input_state("mouse_left")) > 0.0 @@ -167,7 +172,7 @@ impl Scene for MainScene { before_future: Box, app_context: &mut WindowContext, ) -> Result, Box> { - let state = self.state.as_ref().ok_or("State not loaded")?; + let state = self.state.as_mut().ok_or("State not loaded")?; let mut builder = AutoCommandBufferBuilder::primary( app_context.command_buffer_allocator.clone(),