Update transform

This commit is contained in:
Florian RICHER 2025-06-07 21:13:31 +02:00
parent 1a61aab218
commit 4f96a1e4b5
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
2 changed files with 99 additions and 26 deletions

View file

@ -10,13 +10,17 @@ use vulkano::{
use crate::core::render::primitives::{AsBindableBuffer, AsVertexBuffer}; use crate::core::render::primitives::{AsBindableBuffer, AsVertexBuffer};
#[derive(Debug, Clone)]
pub struct Transform { pub struct Transform {
pub position: Vec3, pub position: Vec3,
pub rotation: Quat, pub rotation: Quat,
pub scale: Vec3, pub scale: Vec3,
// Cache to avoid unnecessary recalculations
cached_matrix: Option<Mat4>,
dirty: bool,
} }
#[derive(BufferContents, Vertex, Clone, Copy)] #[derive(BufferContents, Vertex, Clone, Copy, Debug)]
#[repr(C)] #[repr(C)]
pub struct TransformRaw { pub struct TransformRaw {
#[format(R32G32B32A32_SFLOAT)] #[format(R32G32B32A32_SFLOAT)]
@ -26,49 +30,113 @@ pub struct TransformRaw {
impl Default for Transform { impl Default for Transform {
fn default() -> Self { fn default() -> Self {
Self { Self {
position: Vec3::default(), position: Vec3::ZERO,
rotation: Quat::default(), rotation: Quat::IDENTITY,
scale: Vec3::ONE, scale: Vec3::ONE,
cached_matrix: None,
dirty: true,
} }
} }
} }
impl Transform { 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) { pub fn rotate(&mut self, rotation: Quat) {
self.rotation *= rotation; self.rotation *= rotation;
self.mark_dirty();
} }
pub fn translate(&mut self, translation: Vec3) { pub fn translate(&mut self, translation: Vec3) {
self.position += translation; self.position += translation;
self.mark_dirty();
} }
pub fn scale(&mut self, scale: Vec3) { pub fn scale(&mut self, scale: Vec3) {
self.scale *= scale; 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 { TransformRaw {
model: (Mat4::from_translation(self.position) model: self.matrix().to_cols_array_2d(),
* Mat4::from_quat(self.rotation)
* Mat4::from_scale(self.scale))
.to_cols_array_2d(),
} }
} }
/// Create a buffer from transforms (immutable - recalculates each time)
pub fn create_buffer( pub fn create_buffer(
memory_allocator: &Arc<StandardMemoryAllocator>, memory_allocator: &Arc<StandardMemoryAllocator>,
transforms: &[Transform], transforms: &[Transform],
) -> Result<Subbuffer<[TransformRaw]>, Validated<AllocateBufferError>> { ) -> Result<Subbuffer<[TransformRaw]>, Validated<AllocateBufferError>> {
TransformRaw::create_vertex_buffer( TransformRaw::create_vertex_buffer(
memory_allocator, memory_allocator,
&transforms &transforms.iter().map(|t| t.to_raw()).collect::<Vec<_>>(),
.iter()
.map(|t| t.to_raw_tranform())
.collect::<Vec<_>>(),
) )
} }
} }
impl From<&Transform> for TransformRaw {
fn from(transform: &Transform) -> Self {
transform.to_raw()
}
}
impl From<Mat4> 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<TransformRaw> for TransformRaw { impl AsBindableBuffer<TransformRaw> for TransformRaw {
type BufferData = TransformRaw; type BufferData = TransformRaw;

View file

@ -58,19 +58,16 @@ impl Scene for MainScene {
let instance_spacing = 10.0; let instance_spacing = 10.0;
let num_instances_per_row = (num_instances as f32 / instance_spacing).ceil() as u32; let num_instances_per_row = (num_instances as f32 / instance_spacing).ceil() as u32;
let instances: Vec<Transform> = (0..num_instances) let instances: Vec<Transform> = (0..num_instances)
.map(|i| Transform { .map(|i| {
position: Vec3::new( Transform::new(
(i % num_instances_per_row) as f32 * (instance_spacing + instance_size), Vec3::new(
0.0, (i % num_instances_per_row) as f32 * (instance_spacing + instance_size),
(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, Quat::from_euler(EulerRot::XYZ, 0.0, rand::random_range(0.0..=360.0), 0.0),
0.0, Vec3::new(instance_size, instance_size, instance_size),
rand::random_range(0.0..=360.0), )
0.0,
),
scale: Vec3::new(instance_size, instance_size, instance_size),
}) })
.collect(); .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 if app_context
.with_input_manager(|input_manager| input_manager.get_virtual_input_state("mouse_left")) .with_input_manager(|input_manager| input_manager.get_virtual_input_state("mouse_left"))
> 0.0 > 0.0
@ -167,7 +172,7 @@ impl Scene for MainScene {
before_future: Box<dyn GpuFuture>, before_future: Box<dyn GpuFuture>,
app_context: &mut WindowContext, app_context: &mut WindowContext,
) -> Result<Box<dyn GpuFuture>, Box<dyn Error>> { ) -> Result<Box<dyn GpuFuture>, Box<dyn Error>> {
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( let mut builder = AutoCommandBufferBuilder::primary(
app_context.command_buffer_allocator.clone(), app_context.command_buffer_allocator.clone(),