diff --git a/Cargo.lock b/Cargo.lock index 3700c7e..1aa29ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2627,6 +2627,7 @@ dependencies = [ "nalgebra", "postcard", "serde", + "serde_json", "uuid", "vulkano", "vulkano-shaders", diff --git a/Cargo.toml b/Cargo.toml index 1084712..947e6a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,4 @@ winit = "0.30.13" nalgebra = "*" uuid = { version = "1.23.1", features = ["v4"] } postcard = { version = "1.1", features = ["alloc"] } +serde_json = "1.0.149" diff --git a/src/app.rs b/src/app.rs index 8db215a..2d51947 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use crate::common::mesh::MeshRegistry; use crate::gpu::vertex3::Vertex3; use crate::triangle; @@ -30,16 +31,23 @@ use vulkano::pipeline::graphics::rasterization::RasterizationState; use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition}; use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState}; use vulkano::pipeline::layout::PipelineDescriptorSetLayoutCreateInfo; -use vulkano::pipeline::{GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo}; +use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, PipelineShaderStageCreateInfo}; use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}; use vulkano::shader::ShaderModule; use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo}; use vulkano::sync::GpuFuture; use vulkano::{Validated, VulkanError, VulkanLibrary, swapchain, sync}; +use vulkano::descriptor_set::DescriptorSet; +use vulkano::descriptor_set::layout::DescriptorSetLayout; use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::ActiveEventLoop; use winit::window::{Window, WindowAttributes, WindowId}; +use crate::common::camera::{Camera, CameraResources}; +use crate::common::instance::InstanceRegistry; +use crate::common::render_batch::RenderBatch; +use crate::common::scene::Scene; +use crate::gpu::instance::GpuInstance; struct VulkanContext { window: Arc, @@ -57,6 +65,9 @@ struct VulkanContext { pipeline: Arc, cmd_buffers: Vec>, mesh_registry: Arc, + instance_registry: Arc, + camera: Arc, + camera_resources: Arc, } impl VulkanContext { @@ -156,6 +167,10 @@ impl VulkanContext { let framebuffers = Self::create_framebuffers(&images, &render_pass)?; let image_extents = swapchain.image_extent(); + + // Create the camera. + let camera = Arc::new(Camera::new(image_extents)); + let pipeline = Self::create_pipeline( &device, &vert_shader, @@ -164,58 +179,43 @@ impl VulkanContext { [image_extents[0] as f32, image_extents[1] as f32], )?; - let vertex_buffer = Arc::new(Buffer::from_iter( - mem_allocator.clone(), - BufferCreateInfo { - usage: BufferUsage::VERTEX_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_HOST - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - vec![ - Vertex3 { - position: [0.5, 0.5, 0.0], - }, - Vertex3 { - position: [-0.5, 0.5, 0.0], - }, - Vertex3 { - position: [-0.5, -0.5, 0.0], - }, - Vertex3 { - position: [0.5, -0.5, 0.0], - }, - ], - )?); + // Get descriptor set layout + let pipeline_layout = pipeline.layout().clone(); + let desc_set_layout = pipeline_layout.set_layouts()[0].clone(); - let index_buffer = Arc::new(Buffer::from_iter( + // Create GPU-based camera resources + let camera_resources = CameraResources::new( mem_allocator.clone(), - BufferCreateInfo { - usage: BufferUsage::INDEX_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_HOST - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - vec![0, 1, 2, 0, 2, 3], - )?); + desc_allocator.clone(), + desc_set_layout + ); + + let scene = Scene::from_file_json("./test_scene.scene"); + let mesh_registry = Arc::new(MeshRegistry::from_scene( + &scene, + mem_allocator.clone() + )); + let instance_registry = Arc::new(InstanceRegistry::from_scene( + &scene + )); + + // Construct render batches each frame, starting with once here. + let batches = RenderBatch::build_batches( + mem_allocator.clone(), + mesh_registry.clone(), + instance_registry.clone() + ); let cmd_buffers = Self::get_command_buffers( &cmd_allocator, &queue, &pipeline, &framebuffers, - &vertex_buffer, - &index_buffer, + camera_resources.descriptor_set(), + mesh_registry.clone(), + batches, )?; - let mesh_registry = Arc::new(MeshRegistry::new(mem_allocator.clone())?); - Ok(Self { window, device, @@ -232,6 +232,9 @@ impl VulkanContext { pipeline, cmd_buffers, mesh_registry, + instance_registry, + camera, + camera_resources }) } @@ -364,7 +367,8 @@ impl VulkanContext { .entry_point("main") .ok_or("Failed to find fragment shader entry point")?; - let vertex_input_state = Vertex3::per_vertex().definition(&vs)?; + let vertex_input_state = [Vertex3::per_vertex(), GpuInstance::per_instance()] + .definition(&vs)?; let stages = vec![ PipelineShaderStageCreateInfo::new(vs), @@ -417,8 +421,9 @@ impl VulkanContext { queue: &Arc, pipeline: &Arc, framebuffers: &Vec>, - vertex_buffer: &Arc>, - index_buffer: &Subbuffer<[u32]>, + camera_desc_set: Arc, + mesh_registry: Arc, + render_batches: Vec, ) -> Result>, Box> { let buffers = framebuffers .iter() @@ -428,7 +433,7 @@ impl VulkanContext { queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, ) - .ok()?; + .expect("Couldn't create command buffer builder"); unsafe { builder @@ -442,18 +447,36 @@ impl VulkanContext { ..Default::default() }, ) - .ok()? + .unwrap() + .bind_descriptor_sets( + PipelineBindPoint::Graphics, + pipeline.layout().clone(), + 0, + camera_desc_set.clone(), + ) + .unwrap() .bind_pipeline_graphics(pipeline.clone()) - .ok()? - .bind_vertex_buffers(0, vertex_buffer.as_ref().clone()) - .ok()? - .bind_index_buffer(index_buffer.clone()) - .ok()? - // .draw(vertex_buffer.len() as u32, 1, 0, 0).ok()? - .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0) - .ok()? + .unwrap() + .bind_vertex_buffers(0, mesh_registry.vertex_buffer.as_ref().clone()) + .unwrap() + .bind_index_buffer(mesh_registry.index_buffer.as_ref().clone()) + .unwrap(); + + render_batches.iter().for_each(|batch| { + // Grab mesh information + let mesh = mesh_registry.get(&batch.mesh_id) + .expect("Mesh does not exist in registry"); + + builder + .bind_vertex_buffers(1, batch.instance_buffer.clone()) + .unwrap() + .draw_indexed(mesh.index_count as u32, batch.instance_count, mesh.index_loc as u32, mesh.vertex_loc as i32, 0) + .unwrap(); + }); + + builder .end_render_pass(SubpassEndInfo::default()) - .ok()?; + .unwrap(); } builder.build().ok() @@ -496,13 +519,20 @@ impl VulkanContext { [image_extents[0] as f32, image_extents[1] as f32], )?; + let batches = RenderBatch::build_batches( + self.mem_allocator.clone(), + self.mesh_registry.clone(), + self.instance_registry.clone() + ); + let command_buffers = Self::get_command_buffers( &self.cmd_allocator, &self.queue, &new_pipeline, &self.framebuffers, - &self.mesh_registry.vertex_buffer, - &self.mesh_registry.index_buffer, + self.camera_resources.descriptor_set(), + self.mesh_registry.clone(), + batches )?; self.pipeline = new_pipeline; diff --git a/src/common/camera.rs b/src/common/camera.rs new file mode 100644 index 0000000..aa6000b --- /dev/null +++ b/src/common/camera.rs @@ -0,0 +1,160 @@ +use std::f32::consts::PI; +use std::sync::Arc; +use nalgebra::{Matrix4, Point3, Vector2, Vector3}; +use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; +use vulkano::descriptor_set::allocator::DescriptorSetAllocator; +use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet}; +use vulkano::descriptor_set::layout::DescriptorSetLayout; +use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter}; +use crate::gpu::camera::CameraUniform; + +/// A camera set within 3D space. +pub struct Camera { + /// The position of the camera. + position: Vector3, + /// The forward direction of the camera. + forward: Vector3, + /// The upward direction of the camera. + up: Vector3, + /// The rightward direction of the camera. + right: Vector3, + /// The field of view, in radians. + fov: f32, + /// The extents of the viewport. + extents: Vector2, +} + +impl Camera { + /// Creates a new camera. This default camera is positioned at (1, 1, 1) and is looking at + /// (0, 0, 0), and a default FOV of 70 degrees. + pub fn new( + extents: impl Into> + ) -> Self { + let extents = extents.into(); + let position = Vector3::new(1.0, 1.0, 1.0); + let target = Vector3::zeros(); + + // Traveling along this vector moves us upward. + let up = Vector3::new(0.0, 1.0, 0.0); + + // Traveling along this vector moves us to the right. + let right = up.cross(&(position - target)).normalize(); + + // Traveling along this vector moves us toward the target. + let forward = target - position; + + Self { + position, + forward, + up, + right, + fov: 70.0 * PI / 180.0, + extents, + } + } + + /// Moves the camera forward, or backward if given negative speed. + pub fn move_forward(&mut self, speed: f32) { + self.forward += self.forward * speed; + } + + /// Moves the camera to the right, or left if given negative speed. + pub fn move_right(&mut self, speed: f32) { + self.right += self.right * speed; + } + + /// Moves the camera upwards, or downward if given negative speed. + pub fn move_up(&mut self, speed: f32) { + self.up += self.up * speed; + } + + /// Sets the extents of the viewport. + pub fn extents(&mut self, extents: impl Into>) { + let extents = extents.into(); + + self.extents = extents; + } + + /// Gets the current view matrix of the camera. + pub fn get_view(&self) -> Matrix4 { + Matrix4::look_at_rh( + &Point3::from(self.position), + &Point3::from(self.forward - self.position), + &self.up + ) + } + + /// Creates a perspective matrix based on the current viewport aspect ratio. + pub fn get_projection(&self) -> Matrix4 { + let aspect = self.extents.x as f32 / self.extents.y as f32; + + Matrix4::new_perspective( + aspect, + self.fov, + 1.0, + 10000.0 + ) + } +} + +/// An intermediate struct that maintains the buffer and descriptor set for the [`Camera`] struct. +/// The reason this information is not stored as part of the `Camera` itself is because tying +/// the GPU or rendering resources to the camera itself is quite awkward. +pub struct CameraResources { + buffer: Arc>, + descriptor_set: Arc, +} + +impl CameraResources { + /// Creates a new set of `CameraResources`. Automatically allocates a uniform buffer to store + /// [`CameraUniform`] information. + pub fn new( + alloc: Arc, + desc_alloc: Arc, + desc_layout: Arc, + ) -> Arc { + // Allocate the buffer + let buffer = Arc::new(Buffer::new_sized::( + alloc.clone(), + BufferCreateInfo { + usage: BufferUsage::UNIFORM_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_HOST | + MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + } + ).expect("Couldn't allocate the camera uniform buffer")); + + // Create the descriptor set + let descriptor_set = DescriptorSet::new( + desc_alloc.clone(), + desc_layout, + [WriteDescriptorSet::buffer(0, buffer.as_ref().clone())], + [] + ).expect("Couldn't create camera descriptor set"); + + Arc::new(Self { + buffer, + descriptor_set + }) + } + + /// Updates the buffer with the given [`Camera`] information. + pub fn update(&self, camera: &Camera) { + // Update the buffer with the new information from the camera. + let view = camera.get_view(); + let proj = camera.get_projection(); + + let mut buffer_data = self.buffer.write() + .unwrap(); + buffer_data.proj = proj.into(); + buffer_data.view = view.into(); + } + + /// Get a reference to the descriptor set. + pub fn descriptor_set(&self) -> Arc { + self.descriptor_set.clone() + } +} diff --git a/src/common/instance.rs b/src/common/instance.rs index 3650131..e161182 100644 --- a/src/common/instance.rs +++ b/src/common/instance.rs @@ -1,4 +1,5 @@ -use crate::common::scene::SceneInstance; +use std::collections::HashMap; +use crate::common::scene::{Scene, SceneInstance}; use nalgebra::{Matrix4, Vector3, Vector4}; /// Contains all information about an instance of a mesh, specifically its translation, rotation, @@ -9,9 +10,8 @@ use nalgebra::{Matrix4, Vector3, Vector4}; /// /// Before passing this instance into the shaders, construct a transformation matrix by calling /// [`MeshInstance::transform_matrix`]. +#[derive(Debug, Clone)] pub struct MeshInstance { - /// The ID of the mesh corresponding to this instance. - pub mesh_id: String, /// The translation of the instance from the center of the standard space. It is possible that /// local translation will be required in the future. pub translation: Vector4, @@ -35,21 +35,47 @@ impl MeshInstance { Matrix4::from_axis_angle(&Vector3::z_axis(), self.rotation.z) * Matrix4::new_nonuniform_scaling(&self.scale) } +} - /// Constructs a `MeshInstance` from the given [`SceneInstance`] and mesh ID. - fn from_scene_instance( - mesh_id: String, - SceneInstance { - translation, - rotation, - scale, - }: SceneInstance, - ) -> Self { +impl From for MeshInstance { + fn from(instance: SceneInstance) -> Self { + Self::from(&instance) + } +} + +impl From<&SceneInstance> for MeshInstance { + fn from(SceneInstance { translation, rotation, scale }: &SceneInstance) -> Self { Self { - mesh_id, - translation: Vector3::from(translation).to_homogeneous(), - rotation: Vector3::from(rotation).to_homogeneous(), - scale: Vector3::from(scale), + translation: Vector3::from(*translation).to_homogeneous(), + rotation: Vector3::from(*rotation).to_homogeneous(), + scale: Vector3::from(*scale), } } } + +/// A registry containing a series of `MeshInstance` structs linked to a mesh ID. +pub struct InstanceRegistry { + instances: HashMap>, +} + +impl InstanceRegistry { + pub fn from_scene(scene: &Scene) -> Self { + // Read information about the instances from the scene. + let instances: HashMap> = scene.instances.iter() + .fold(HashMap::new(), |mut map, (mesh_id, instance)| { + map.entry(mesh_id.clone()) + .and_modify(|v| v.push(instance.into())) + .or_insert(vec![instance.into()]); + map + }); + + Self { + instances + } + } + + pub fn get_instances_for(&self, mesh_id: &String) -> Vec { + // We can't move these instances because we'll want them again later. + self.instances.get(mesh_id).cloned().unwrap_or_default() + } +} diff --git a/src/common/mesh.rs b/src/common/mesh.rs index 3fe9415..b851189 100644 --- a/src/common/mesh.rs +++ b/src/common/mesh.rs @@ -32,7 +32,7 @@ impl Mesh {} /// used by the rendering pipeline. #[derive(Debug)] pub struct MeshRegistry { - meshes: HashMap, + pub meshes: HashMap, allocator: Arc, pub vertex_buffer: Arc>, pub index_buffer: Arc>, @@ -67,7 +67,7 @@ impl MeshRegistry { let vert_start = verts.len(); let all_verts = obj.vertices(); let vert_len = all_verts.len(); - verts.extend(all_verts.map(|v| Vertex3::from(v.position()))); + verts.extend(all_verts.map(|v| Vertex3::new(v.position(), v.normal().unwrap_or_default()))); let index_list = obj .triangles() @@ -156,7 +156,7 @@ impl MeshRegistry { } /// Attempts to find a [`Mesh`] with the given ID, returning `None` if it's not found. - pub fn get(&self, uuid: &str) -> Option<&Mesh> { + pub fn get(&self, uuid: &String) -> Option<&Mesh> { self.meshes.get(uuid) } } diff --git a/src/common/mod.rs b/src/common/mod.rs index bdf8973..13957ac 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,3 +1,5 @@ pub mod instance; pub mod mesh; pub mod scene; +pub mod render_batch; +pub mod camera; diff --git a/src/common/render_batch.rs b/src/common/render_batch.rs new file mode 100644 index 0000000..4564824 --- /dev/null +++ b/src/common/render_batch.rs @@ -0,0 +1,56 @@ +use std::sync::Arc; +use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; +use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter}; +use crate::common::instance::InstanceRegistry; +use crate::common::mesh::MeshRegistry; +use crate::gpu::instance::GpuInstance; + +#[derive(Debug, Clone)] +pub struct RenderBatch { + pub mesh_id: String, + pub instance_buffer: Subbuffer<[GpuInstance]>, + pub instance_count: u32, +} + +impl RenderBatch { + /// Builds a `Vec` from the given list of instances and meshes. This should be done + /// once per frame. + pub fn build_batches( + allocator: Arc, + mesh_registry: Arc, + instance_registry: Arc + ) -> Vec { + mesh_registry.meshes.iter() + .map(|(id, mesh)| { + let instances = instance_registry.get_instances_for(id); + + let gpu_instances = instances.iter() + .cloned() + .map(|instance| { + instance.into() + }) + .collect::>(); + + // Build instances into a RenderBatch + let instance_buffer = Buffer::from_iter( + allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::VERTEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE | + MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + gpu_instances + ).expect("Couldn't allocate instance buffer"); + + Self { + mesh_id: id.clone(), + instance_buffer, + instance_count: instances.len() as u32, + } + }).collect() + } +} diff --git a/src/common/scene.rs b/src/common/scene.rs index 7998a1b..eeb74d2 100644 --- a/src/common/scene.rs +++ b/src/common/scene.rs @@ -42,10 +42,23 @@ impl Scene { let mut contents = Vec::new(); let _ = file.read_to_end(&mut contents).unwrap(); - let mut scene: Self = + let scene: Self = postcard::from_bytes(contents.as_slice()).expect("Couldn't deserialize scene"); - let base = path.parent().unwrap_or(&Path::new(".")); + Self::resolve_paths(path, scene) + } + + pub fn from_file_json>(path: P) -> Self { + let path = path.as_ref(); + + let file = std::fs::File::open(path).unwrap(); + let scene: Self = serde_json::from_reader(file).unwrap(); + + Self::resolve_paths(path, scene) + } + + fn resolve_paths(scene_path: &Path, mut scene: Self) -> Self { + let base = scene_path.parent().unwrap_or(&Path::new(".")); scene.mesh_paths = scene .mesh_paths .into_iter() @@ -73,3 +86,34 @@ pub struct SceneInstance { pub rotation: [f32; 3], pub scale: [f32; 3], } + +#[cfg(test)] +pub mod create_files { + use std::error::Error; + use std::io::Write; + pub use super::*; + + #[test] + pub fn create_test_scene() -> Result<(), Box> { + let scene = Scene { + name: "Testing Scene".to_string(), + mesh_paths: HashMap::from([ + ("venator".to_string(), "Venator.obj".to_string()) + ]), + instances: HashMap::from([ + ("venator".to_string(), SceneInstance { + translation: [0.0, 0.0, 0.0], + rotation: [0.0, 0.0, 0.0], + scale: [1.0, 1.0, 1.0] + }) + ]) + }; + + let json = serde_json::to_string_pretty(&scene)?; + + let mut file = std::fs::File::create("test_scene.scene")?; + file.write_all(json.as_bytes())?; + + Ok(()) + } +} diff --git a/src/gpu/camera.rs b/src/gpu/camera.rs new file mode 100644 index 0000000..b3ec80a --- /dev/null +++ b/src/gpu/camera.rs @@ -0,0 +1,29 @@ +use std::sync::Arc; +use vulkano::buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer}; +use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter}; +use crate::common::camera::Camera; + +#[derive(BufferContents)] +#[repr(C)] +pub struct CameraUniform { + pub view: [[f32; 4]; 4], + pub proj: [[f32; 4]; 4], +} + +impl From for CameraUniform { + fn from(camera: Camera) -> Self { + Self::from(&camera) + } +} + +impl From<&Camera> for CameraUniform { + fn from(camera: &Camera) -> Self { + let view = camera.get_view(); + let proj = camera.get_projection(); + + Self { + view: view.into(), + proj: proj.into(), + } + } +} diff --git a/src/gpu/instance.rs b/src/gpu/instance.rs index a96c9eb..66e55ea 100644 --- a/src/gpu/instance.rs +++ b/src/gpu/instance.rs @@ -3,7 +3,7 @@ use vulkano::buffer::BufferContents; use vulkano::pipeline::graphics::vertex_input::Vertex; /// A transformation matrix for a mesh that can be passed into the shaders. -#[derive(BufferContents, Vertex)] +#[derive(Debug, Clone, BufferContents, Vertex)] #[repr(C)] pub struct GpuInstance { #[format(R32G32B32A32_SFLOAT)] diff --git a/src/gpu/mod.rs b/src/gpu/mod.rs index 239ca7e..f34f871 100644 --- a/src/gpu/mod.rs +++ b/src/gpu/mod.rs @@ -1,2 +1,3 @@ pub mod instance; pub mod vertex3; +pub mod camera; diff --git a/src/gpu/vertex3.rs b/src/gpu/vertex3.rs index e3615e2..e043055 100644 --- a/src/gpu/vertex3.rs +++ b/src/gpu/vertex3.rs @@ -6,12 +6,18 @@ use vulkano::pipeline::graphics::vertex_input::Vertex; pub struct Vertex3 { #[format(R32G32B32_SFLOAT)] pub(crate) position: [f32; 3], + #[format(R32G32B32_SFLOAT)] + pub(crate) normal: [f32; 3], } -impl From<[f32; 3]> for Vertex3 { - fn from(v: [f32; 3]) -> Self { +impl Vertex3 { + pub fn new( + position: [f32; 3], + normal: [f32; 3], + ) -> Self { Self { - position: v.clone(), + position, + normal, } } } diff --git a/src/shaders/test.vert b/src/shaders/test.vert new file mode 100644 index 0000000..1cfbe72 --- /dev/null +++ b/src/shaders/test.vert @@ -0,0 +1,32 @@ +#version 460 + +// Per-vertex information - Vertex3 struct +layout(location = 0) in vec3 position; +layout(location = 1) in vec3 normal; + +// Per-instance information - GpuInstance struct +layout(location = 2) in vec4 trans_col1; +layout(location = 3) in vec4 trans_col2; +layout(location = 4) in vec4 trans_col3; +layout(location = 5) in vec4 trans_col4; + +// Per-frame information - CameraUniform struct +//layout(location = 6) uniform vec4 proj_col1; +//layout(location = 7) uniform vec4 proj_col2; +//layout(location = 8) uniform vec4 proj_col3; +//layout(location = 9) uniform vec4 proj_col4; + +layout(set = 0, binding = 0) uniform CameraUniform { + mat4 view; + mat4 projection; +} camera; + +void main() { + // We then multiply each vertex by its transform to find the correct location in the scene. + mat4 transform = mat4(trans_col1, trans_col2, trans_col3, trans_col4); + //mat4 proj = mat4(proj_col1, proj_col2, proj_col3, proj_col4); + + mat4 mvp = camera.projection * camera.view * transform; + + gl_Position = transform * vec4(position, 1.0f); +} diff --git a/src/shaders/triangle_vert.glsl b/src/shaders/triangle_vert.glsl index c2c73aa..41f089d 100644 --- a/src/shaders/triangle_vert.glsl +++ b/src/shaders/triangle_vert.glsl @@ -1,7 +1,32 @@ #version 460 +// Per-vertex information - Vertex3 struct layout(location = 0) in vec3 position; +layout(location = 1) in vec3 normal; + +// Per-instance information - GpuInstance struct +layout(location = 2) in vec4 transform_col1; +layout(location = 3) in vec4 transform_col2; +layout(location = 4) in vec4 transform_col3; +layout(location = 5) in vec4 transform_col4; + +// Per-frame information - CameraUniform struct +//layout(location = 6) uniform vec4 proj_col1; +//layout(location = 7) uniform vec4 proj_col2; +//layout(location = 8) uniform vec4 proj_col3; +//layout(location = 9) uniform vec4 proj_col4; + +layout(set = 0, binding = 0) uniform CameraUniform { + mat4 view; + mat4 projection; +} camera; void main() { - gl_Position = vec4(position, 1.0); + // We then multiply each vertex by its transform to find the correct location in the scene. + mat4 transform = mat4(transform_col1, transform_col2, transform_col3, transform_col4); + //mat4 proj = mat4(proj_col1, proj_col2, proj_col3, proj_col4); + + mat4 mvp = camera.projection * camera.view * transform; + + gl_Position = transform * vec4(position, 1.0f); }