feat(renderer): add dynamic mesh updates via buffer reallocation

This commit is contained in:
Serkyo 2026-05-16 19:04:20 +02:00
parent ab01c8a033
commit 203cc2a671
3 changed files with 57 additions and 6 deletions

View file

@ -8,7 +8,7 @@
mod device; mod device;
pub mod error; pub mod error;
mod instance; mod instance;
mod mesh; pub mod mesh;
mod pipeline; mod pipeline;
mod renderer; mod renderer;
mod surface; mod surface;
@ -119,6 +119,8 @@ impl Renderer {
let (vertex_buffer, vertex_allocation, index_buffer, index_allocation) = let (vertex_buffer, vertex_allocation, index_buffer, index_allocation) =
create_geometry(&device, &mut allocator)?; create_geometry(&device, &mut allocator)?;
let index_count = 36;
let (depth_image, depth_allocation, depth_image_view) = let (depth_image, depth_allocation, depth_image_view) =
create_depth_resources(&device, &mut allocator, swapchain_extent)?; create_depth_resources(&device, &mut allocator, swapchain_extent)?;
@ -144,6 +146,7 @@ impl Renderer {
allocator, allocator,
index_buffer, index_buffer,
index_allocation, index_allocation,
index_count,
depth_image, depth_image,
depth_allocation, depth_allocation,
depth_image_view, depth_image_view,

View file

@ -10,7 +10,9 @@ use bytemuck::{Pod, Zeroable};
#[derive(Copy, Clone, Debug, Pod, Zeroable)] #[derive(Copy, Clone, Debug, Pod, Zeroable)]
pub struct Vertex { pub struct Vertex {
/// 3D position of the vertex (X, Y, Z). /// 3D position of the vertex (X, Y, Z).
/// The position coordinates of the vertex [x, y, z].
pub position: [f32; 3], pub position: [f32; 3],
/// The RGB color of the vertex [r, g, b].
pub color: [f32; 3], pub color: [f32; 3],
} }
@ -19,6 +21,9 @@ impl Vertex {
/// ///
/// This defines the 'stride' (distance between vertices) and specifies that /// This defines the 'stride' (distance between vertices) and specifies that
/// data is read per-vertex rather than per-instance. /// data is read per-vertex rather than per-instance.
///
/// # Panics
/// Panics if the size of the vertex structure exceeds the maximum value of a 32-bit unsigned integer.
#[allow(clippy::expect_used)] #[allow(clippy::expect_used)]
pub fn get_binding_description() -> ash::vk::VertexInputBindingDescription { pub fn get_binding_description() -> ash::vk::VertexInputBindingDescription {
ash::vk::VertexInputBindingDescription::default() ash::vk::VertexInputBindingDescription::default()

View file

@ -1,4 +1,5 @@
use crate::error::RendererError; use crate::create_gpu_buffer;
use crate::{error::RendererError, mesh::Vertex};
use crate::sync::SyncPrimitives; use crate::sync::SyncPrimitives;
use ash::{Device, Instance, khr, vk}; use ash::{Device, Instance, khr, vk};
use gpu_allocator::vulkan::{Allocation, Allocator}; use gpu_allocator::vulkan::{Allocation, Allocator};
@ -58,6 +59,7 @@ pub struct Renderer {
pub(crate) index_buffer: vk::Buffer, pub(crate) index_buffer: vk::Buffer,
/// Memory allocation for the index buffer. /// Memory allocation for the index buffer.
pub(crate) index_allocation: Allocation, pub(crate) index_allocation: Allocation,
pub(crate) index_count: u32,
/// The depth image used for depth testing. /// The depth image used for depth testing.
pub(crate) depth_image: vk::Image, pub(crate) depth_image: vk::Image,
/// Image view for the depth buffer. /// Image view for the depth buffer.
@ -276,12 +278,12 @@ impl Renderer {
f64::from(self.swapchain_extent.width) / f64::from(self.swapchain_extent.height); f64::from(self.swapchain_extent.width) / f64::from(self.swapchain_extent.height);
#[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_possible_truncation)]
let mut projection = let mut projection =
glam::Mat4::perspective_rh(45.0_f32.to_radians(), aspect as f32, 0.1, 100.0); glam::Mat4::perspective_rh(45.0_f32.to_radians(), aspect as f32, 0.1, 500.0);
projection.col_mut(1).y *= -1.0; projection.col_mut(1).y *= -1.0;
let view = glam::Mat4::look_at_rh( let view = glam::Mat4::look_at_rh(
glam::vec3(2.0, 2.0, 2.0), glam::vec3(16.0, 40.0, 60.0),
glam::vec3(0.0, 0.0, 0.0), glam::vec3(16.0, 16.0, 16.0),
glam::vec3(0.0, 1.0, 0.0), glam::vec3(0.0, 1.0, 0.0),
); );
@ -297,7 +299,7 @@ impl Renderer {
mvp_bytes, mvp_bytes,
); );
self.device.cmd_draw_indexed(cmd, 36, 1, 0, 0, 0); self.device.cmd_draw_indexed(cmd, self.index_count, 1, 0, 0, 0);
} }
} }
@ -335,6 +337,47 @@ impl Renderer {
Ok(()) Ok(())
} }
/// Replaces the currently rendering mesh with a new set of vertices and indices.
///
/// # Errors
/// Returns a `RendererError` if new Vulkan buffers cannot be allocated or created.
#[allow(clippy::cast_possible_truncation)]
pub fn update_mesh(&mut self, vertices: &[Vertex], indices: &[u32]) -> Result<(), RendererError> {
unsafe {
let _ = self.device.device_wait_idle();
let _ = self.allocator.free(std::ptr::read(&raw const self.vertex_allocation));
self.device.destroy_buffer(self.vertex_buffer, None);
let _ = self.allocator.free(std::ptr::read(&raw const self.index_allocation));
self.device.destroy_buffer(self.index_buffer, None);
}
let (v_buf, v_alloc) = create_gpu_buffer(
&self.device,
&mut self.allocator,
bytemuck::cast_slice(vertices),
vk::BufferUsageFlags::VERTEX_BUFFER,
"Chunk Vertex Buffer",
)?;
let (i_buf, i_alloc) = crate::create_gpu_buffer(
&self.device,
&mut self.allocator,
bytemuck::cast_slice(indices),
vk::BufferUsageFlags::INDEX_BUFFER,
"Chunk Index Buffer",
)?;
self.vertex_buffer = v_buf;
self.vertex_allocation = v_alloc;
self.index_buffer = i_buf;
self.index_allocation = i_alloc;
self.index_count = indices.len() as u32;
Ok(())
}
} }
impl Drop for Renderer { impl Drop for Renderer {