diff --git a/Cargo.lock b/Cargo.lock index cbd0e43..78fdb0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -490,6 +490,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "glam" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" + [[package]] name = "half" version = "2.4.1" @@ -1137,6 +1143,7 @@ version = "0.1.0" dependencies = [ "anyhow", "env_logger", + "glam", "log", "vulkano", "vulkano-shaders", diff --git a/Cargo.toml b/Cargo.toml index 9ad5563..62dde55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,9 @@ winit = { version = "0.30", features = ["rwh_06"] } vulkano = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" } vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" } +# Math +glam = { version = "0.29" } + # Log and tracing log = "0.4" env_logger = "0.11.5" diff --git a/res/shaders/vertex.vert b/res/shaders/vertex.vert index ec483f7..65b0acf 100644 --- a/res/shaders/vertex.vert +++ b/res/shaders/vertex.vert @@ -1 +1 @@ -#version 450 layout (location = 0) in vec2 position; layout (location = 1) in vec3 color; layout (location = 0) out vec3 fragColor; layout (set = 0, binding = 0) uniform MVP_Data { mat4 model; mat4 view; mat4 projection; } uniforms; void main() { gl_Position = vec4(position, 0.0, 1.0); fragColor = color; } \ No newline at end of file +#version 450 layout (location = 0) in vec2 position; layout (location = 1) in vec3 color; layout (location = 0) out vec3 fragColor; layout (set = 0, binding = 0) uniform MVPData { mat4 world; mat4 view; mat4 projection; } uniforms; void main() { mat4 worldview = uniforms.view * uniforms.world; gl_Position = uniforms.projection * worldview * vec4(position, 0.0, 1.0); fragColor = color; } \ No newline at end of file diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 21def04..01187d5 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -3,7 +3,6 @@ mod pipelines; mod render_context; mod vertex; pub use app::App; -pub use pipelines::create_triangle_pipeline; mod scene; pub use scene::Scene; diff --git a/src/renderer/pipelines/mod.rs b/src/renderer/pipelines/mod.rs index 670717a..e5f30a7 100644 --- a/src/renderer/pipelines/mod.rs +++ b/src/renderer/pipelines/mod.rs @@ -1,2 +1 @@ -mod triangle_pipeline; -pub use triangle_pipeline::create_triangle_pipeline; +pub mod triangle_pipeline; diff --git a/src/renderer/pipelines/triangle_pipeline.rs b/src/renderer/pipelines/triangle_pipeline.rs index 1423b8f..f6001f7 100644 --- a/src/renderer/pipelines/triangle_pipeline.rs +++ b/src/renderer/pipelines/triangle_pipeline.rs @@ -22,7 +22,7 @@ use vulkano::swapchain::Swapchain; use crate::renderer::Vertex2D; -mod shaders { +pub mod shaders { pub mod vs { vulkano_shaders::shader! { ty: "vertex", @@ -52,7 +52,7 @@ pub fn create_triangle_pipeline( let mut bindings = BTreeMap::::new(); let mut descriptor_set_layout_binding = - DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBufferDynamic); + DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer); descriptor_set_layout_binding.stages = ShaderStages::VERTEX; bindings.insert(0, descriptor_set_layout_binding); diff --git a/src/renderer/scene.rs b/src/renderer/scene.rs index c820380..266a7a8 100644 --- a/src/renderer/scene.rs +++ b/src/renderer/scene.rs @@ -1,13 +1,19 @@ +use crate::renderer::pipelines::triangle_pipeline::shaders::vs; +use glam::{Mat3, Mat4, Vec3}; use std::error::Error; use std::sync::Arc; -use vulkano::buffer::Subbuffer; +use std::time::Instant; +use vulkano::buffer::allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}; +use vulkano::buffer::{BufferUsage, Subbuffer}; use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}; +use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator; +use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet}; use vulkano::device::Device; -use vulkano::memory::allocator::StandardMemoryAllocator; -use vulkano::pipeline::GraphicsPipeline; +use vulkano::memory::allocator::{MemoryTypeFilter, StandardMemoryAllocator}; +use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint}; use vulkano::swapchain::Swapchain; -use crate::renderer::{create_triangle_pipeline, Vertex2D}; +use crate::renderer::{pipelines::triangle_pipeline::create_triangle_pipeline, Vertex2D}; const VERTICES: [Vertex2D; 12] = [ // Triangle en haut à gauche @@ -67,6 +73,11 @@ const VERTICES: [Vertex2D; 12] = [ pub struct Scene { pipeline: Arc, vertex_buffer: Subbuffer<[Vertex2D]>, + + uniform_buffer_allocator: SubbufferAllocator, + rotation_start: Instant, + swapchain: Arc, + descriptor_set_allocator: Arc, } impl Scene { @@ -78,9 +89,28 @@ impl Scene { let pipeline = create_triangle_pipeline(device, swapchain)?; let vertex_buffer = Vertex2D::create_buffer(Vec::from_iter(VERTICES), memory_allocator)?; + let uniform_buffer_allocator = SubbufferAllocator::new( + memory_allocator.clone(), + SubbufferAllocatorCreateInfo { + buffer_usage: BufferUsage::UNIFORM_BUFFER, + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + ); + + let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( + device.clone(), + Default::default(), + )); + Ok(Scene { pipeline, vertex_buffer, + uniform_buffer_allocator, + rotation_start: Instant::now(), + swapchain: swapchain.clone(), + descriptor_set_allocator, }) } @@ -91,13 +121,59 @@ impl Scene { let vertex_count = self.vertex_buffer.len() as u32; let instance_count = vertex_count / 3; + let uniform_buffer = self.get_uniform_buffer(); + let layout = &self.pipeline.layout().set_layouts()[0]; + let descriptor_set = DescriptorSet::new( + self.descriptor_set_allocator.clone(), + layout.clone(), + [WriteDescriptorSet::buffer(0, uniform_buffer)], + [], + ) + .unwrap(); + unsafe { builder .bind_pipeline_graphics(self.pipeline.clone())? + .bind_descriptor_sets( + PipelineBindPoint::Graphics, + self.pipeline.layout().clone(), + 0, + descriptor_set, + )? .bind_vertex_buffers(0, self.vertex_buffer.clone())? .draw(vertex_count, instance_count, 0, 0)?; } Ok(()) } + + fn get_uniform_buffer(&self) -> Subbuffer { + let elapsed = self.rotation_start.elapsed(); + let rotation = elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 / 1_000_000_000.0; + let rotation = Mat3::from_rotation_y(rotation as f32); + + // NOTE: This teapot was meant for OpenGL where the origin is at the lower left + // instead the origin is at the upper left in Vulkan, so we reverse the Y axis. + let aspect_ratio = + self.swapchain.image_extent()[0] as f32 / self.swapchain.image_extent()[1] as f32; + + let proj = Mat4::perspective_rh_gl(std::f32::consts::FRAC_PI_2, aspect_ratio, 0.01, 100.0); + let view = 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), + ); + let scale = Mat4::from_scale(Vec3::splat(1.0)); + + let uniform_data = vs::MVPData { + world: Mat4::from_mat3(rotation).to_cols_array_2d(), + view: (view * scale).to_cols_array_2d(), + projection: proj.to_cols_array_2d(), + }; + + let buffer = self.uniform_buffer_allocator.allocate_sized().unwrap(); + *buffer.write().unwrap() = uniform_data; + + buffer + } }