diff --git a/res/shaders/vertex.vert b/res/shaders/vertex.vert index 65b0acf..bb1c261 100644 --- a/res/shaders/vertex.vert +++ b/res/shaders/vertex.vert @@ -1 +1,18 @@ -#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 +#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 { + 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; +} diff --git a/src/core/render/mod.rs b/src/core/render/mod.rs index a86d640..a074771 100644 --- a/src/core/render/mod.rs +++ b/src/core/render/mod.rs @@ -1,5 +1,5 @@ pub mod app; pub mod pipelines; +pub mod primitives; pub mod render_context; -pub mod vertex; pub mod vulkan_context; diff --git a/src/core/render/pipelines/triangle_pipeline.rs b/src/core/render/pipelines/triangle_pipeline.rs index 62bd8b0..b7ffce4 100644 --- a/src/core/render/pipelines/triangle_pipeline.rs +++ b/src/core/render/pipelines/triangle_pipeline.rs @@ -20,13 +20,14 @@ use vulkano::pipeline::{ }; use vulkano::shader::{EntryPoint, ShaderStages}; -use crate::core::render::vertex::Vertex2D; +use crate::core::render::primitives::vertex::Vertex2D; pub mod shaders { pub mod vs { vulkano_shaders::shader! { ty: "vertex", path: r"res/shaders/vertex.vert", + generate_structs: false, } } @@ -34,6 +35,7 @@ pub mod shaders { vulkano_shaders::shader! { ty: "fragment", path: r"res/shaders/vertex.frag", + generate_structs: false, } } } diff --git a/src/core/render/primitives/camera.rs b/src/core/render/primitives/camera.rs new file mode 100644 index 0000000..efd61e5 --- /dev/null +++ b/src/core/render/primitives/camera.rs @@ -0,0 +1,48 @@ +use std::sync::Arc; + +use glam::Mat4; +use vulkano::{ + Validated, + buffer::{AllocateBufferError, Subbuffer}, + memory::allocator::StandardMemoryAllocator, +}; + +use super::{mvp::MVP, transform::Transform}; + +#[derive(Default)] +pub struct Camera { + view: Mat4, + projection: Mat4, + + transform: Transform, +} + +impl Camera { + pub fn new(view: Mat4, projection: Mat4) -> Self { + Self { + view, + projection, + transform: Transform::default(), + } + } + + pub fn get_transform(&self) -> &Transform { + &self.transform + } + + pub fn get_transform_mut(&mut self) -> &mut Transform { + &mut self.transform + } + + pub fn set_projection(&mut self, projection: Mat4) { + self.projection = projection; + } + + pub fn create_buffer( + &self, + memory_allocator: &Arc, + ) -> Result, Validated> { + MVP::new(&self.transform.get_mat4(), &self.view, &self.projection) + .into_buffer(memory_allocator) + } +} diff --git a/src/core/render/primitives/mod.rs b/src/core/render/primitives/mod.rs new file mode 100644 index 0000000..fd0b762 --- /dev/null +++ b/src/core/render/primitives/mod.rs @@ -0,0 +1,4 @@ +pub mod camera; +mod mvp; +pub mod transform; +pub mod vertex; diff --git a/src/core/render/primitives/mvp.rs b/src/core/render/primitives/mvp.rs new file mode 100644 index 0000000..fb73ad3 --- /dev/null +++ b/src/core/render/primitives/mvp.rs @@ -0,0 +1,45 @@ +use std::sync::Arc; + +use glam::Mat4; +use vulkano::Validated; +use vulkano::buffer::{ + AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer, +}; +use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}; + +#[derive(BufferContents, Clone, Copy)] +#[repr(C)] +pub struct MVP { + world: [[f32; 4]; 4], + view: [[f32; 4]; 4], + projection: [[f32; 4]; 4], +} + +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( + self, + memory_allocator: &Arc, + ) -> Result, Validated> { + Buffer::from_iter( + memory_allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::UNIFORM_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + [self], + ) + } +} diff --git a/src/core/render/primitives/transform.rs b/src/core/render/primitives/transform.rs new file mode 100644 index 0000000..88e6422 --- /dev/null +++ b/src/core/render/primitives/transform.rs @@ -0,0 +1,37 @@ +use glam::{Mat4, Quat, Vec3}; + +pub struct Transform { + position: Vec3, + rotation: Quat, + scale: Vec3, +} + +impl Default for Transform { + fn default() -> Self { + Self { + position: Vec3::default(), + rotation: Quat::default(), + scale: Vec3::ONE, + } + } +} + +impl Transform { + pub fn rotate(&mut self, rotation: Quat) { + self.rotation = self.rotation * rotation; + } + + pub fn translate(&mut self, translation: Vec3) { + self.position += translation; + } + + pub fn scale(&mut self, scale: Vec3) { + self.scale *= scale; + } + + pub fn get_mat4(&self) -> Mat4 { + Mat4::from_translation(self.position) + * Mat4::from_quat(self.rotation) + * Mat4::from_scale(self.scale) + } +} diff --git a/src/core/render/vertex.rs b/src/core/render/primitives/vertex.rs similarity index 100% rename from src/core/render/vertex.rs rename to src/core/render/primitives/vertex.rs diff --git a/src/game/main_scene.rs b/src/game/main_scene.rs index c0e13be..54ca089 100644 --- a/src/game/main_scene.rs +++ b/src/game/main_scene.rs @@ -1,25 +1,19 @@ use crate::core::input::InputState; -use crate::core::render::pipelines::triangle_pipeline::shaders::vs; +use crate::core::render::primitives::camera::Camera; +use crate::core::render::primitives::vertex::Vertex2D; use crate::core::render::render_context::RenderContext; use crate::core::scene::Scene; use crate::core::timer::Timer; -use glam::{Mat3, Mat4, Vec3}; -use std::error::Error; +use glam::{Mat4, Quat, Vec3}; use std::sync::Arc; -use std::time::Instant; -use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; +use vulkano::buffer::Subbuffer; use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}; use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet}; -use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}; use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint}; -use vulkano_util::renderer::VulkanoWindowRenderer; use winit::event::ElementState; use winit::keyboard::{KeyCode, PhysicalKey}; use crate::core::render::pipelines::triangle_pipeline::create_triangle_pipeline; -use crate::core::render::vertex::Vertex2D; - -use crate::core::render::vulkan_context::VulkanContext; const VERTICES: [Vertex2D; 12] = [ // Triangle en haut à gauche @@ -79,8 +73,7 @@ const VERTICES: [Vertex2D; 12] = [ pub struct MainSceneState { pipeline: Arc, vertex_buffer: Subbuffer<[Vertex2D]>, - uniform_buffer: Subbuffer, - rotation: f32, + camera: Camera, } #[derive(Default)] @@ -101,39 +94,72 @@ impl Scene for MainScene { Vertex2D::create_buffer(Vec::from_iter(VERTICES), render_context.memory_allocator()) .unwrap(); - let uniform_buffer = MainScene::get_uniform_buffer( - 0.0, - render_context.memory_allocator(), - render_context.aspect_ratio(), + let camera = Camera::new( + 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), + ), + Mat4::perspective_rh_gl( + std::f32::consts::FRAC_PI_2, + render_context.aspect_ratio(), + 0.01, + 100.0, + ), ); self.state = Some(MainSceneState { pipeline, vertex_buffer, - uniform_buffer, - rotation: 0.0, + camera, }) } fn update(&mut self, render_context: &RenderContext, input_state: &InputState, timer: &Timer) { let state = self.state.as_mut().unwrap(); - let delta_rotation = if input_state.get_key_state(PhysicalKey::Code(KeyCode::KeyA)) + + let speed = 50.0 * timer.delta_time(); + + let mut rot = Quat::default(); + rot *= Quat::from_rotation_y(input_state.mouse_state.delta.x * speed.to_radians()); + rot *= Quat::from_rotation_x(input_state.mouse_state.delta.y * speed.to_radians()); + state.camera.get_transform_mut().rotate(rot); + + let translation_x = if input_state.get_key_state(PhysicalKey::Code(KeyCode::KeyA)) == &ElementState::Pressed { - timer.delta_time() * 5.0 + timer.delta_time() * speed } else if input_state.get_key_state(PhysicalKey::Code(KeyCode::KeyD)) == &ElementState::Pressed { - timer.delta_time() * -5.0 + timer.delta_time() * -speed } else { timer.delta_time() * 0.0 }; - state.rotation += delta_rotation; - state.uniform_buffer = MainScene::get_uniform_buffer( - state.rotation, - render_context.memory_allocator(), + + let translation_z = if input_state.get_key_state(PhysicalKey::Code(KeyCode::KeyW)) + == &ElementState::Pressed + { + timer.delta_time() * speed + } else if input_state.get_key_state(PhysicalKey::Code(KeyCode::KeyS)) + == &ElementState::Pressed + { + timer.delta_time() * -speed + } else { + timer.delta_time() * 0.0 + }; + + state + .camera + .get_transform_mut() + .translate(Vec3::new(translation_x, 0.0, translation_z)); + + state.camera.set_projection(Mat4::perspective_rh_gl( + std::f32::consts::FRAC_PI_2, render_context.aspect_ratio(), - ); + 0.01, + 100.0, + )); } fn render( @@ -141,33 +167,35 @@ impl Scene for MainScene { render_context: &RenderContext, builder: &mut AutoCommandBufferBuilder, ) { - let vertex_count = self.state.as_ref().unwrap().vertex_buffer.len() as u32; + let state = self.state.as_ref().unwrap(); + let vertex_count = state.vertex_buffer.len() as u32; let instance_count = vertex_count / 3; - let layout = &self.state.as_ref().unwrap().pipeline.layout().set_layouts()[0]; + let layout = &state.pipeline.layout().set_layouts()[0]; + let uniform_buffer = state + .camera + .create_buffer(render_context.memory_allocator()) + .unwrap(); let descriptor_set = DescriptorSet::new( render_context.descriptor_set_allocator().clone(), layout.clone(), - [WriteDescriptorSet::buffer( - 0, - self.state.as_ref().unwrap().uniform_buffer.clone(), - )], + [WriteDescriptorSet::buffer(0, uniform_buffer)], [], ) .unwrap(); unsafe { builder - .bind_pipeline_graphics(self.state.as_ref().unwrap().pipeline.clone()) + .bind_pipeline_graphics(state.pipeline.clone()) .unwrap() .bind_descriptor_sets( PipelineBindPoint::Graphics, - self.state.as_ref().unwrap().pipeline.layout().clone(), + state.pipeline.layout().clone(), 0, descriptor_set, ) .unwrap() - .bind_vertex_buffers(0, self.state.as_ref().unwrap().vertex_buffer.clone()) + .bind_vertex_buffers(0, state.vertex_buffer.clone()) .unwrap() .draw(vertex_count, instance_count, 0, 0) .unwrap(); @@ -176,44 +204,3 @@ impl Scene for MainScene { fn unload(&mut self) {} } - -impl MainScene { - fn get_uniform_buffer( - rotation: f32, - memory_allocator: &Arc, - aspect_ratio: f32, - ) -> Subbuffer { - let rotation = Mat3::from_rotation_y(rotation); - - // 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 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(), - }; - - Buffer::from_data( - memory_allocator.clone(), - BufferCreateInfo { - usage: BufferUsage::UNIFORM_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - uniform_data, - ) - .unwrap() - } -}