feat: additional implementation of renderer
This commit is contained in:
1 parent
639875b603
commit
8683f8b565
16 files changed
+197
-195
No files matched your search
+52
-67
@@ -1,4 +1,9 @@
|
|||||||
|
use crate::common::camera::{Camera, CameraResources};
|
||||||
|
use crate::common::instance::InstanceRegistry;
|
||||||
use crate::common::mesh::MeshRegistry;
|
use crate::common::mesh::MeshRegistry;
|
||||||
|
use crate::common::render_batch::RenderBatch;
|
||||||
|
use crate::common::scene::Scene;
|
||||||
|
use crate::gpu::instance::GpuInstance;
|
||||||
use crate::gpu::vertex3::Vertex3;
|
use crate::gpu::vertex3::Vertex3;
|
||||||
use crate::triangle;
|
use crate::triangle;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
@@ -15,35 +20,33 @@ use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
|||||||
use vulkano::device::{
|
use vulkano::device::{
|
||||||
Device, DeviceCreateInfo, DeviceExtensions, Queue, QueueCreateInfo, QueueFlags,
|
Device, DeviceCreateInfo, DeviceExtensions, Queue, QueueCreateInfo, QueueFlags,
|
||||||
};
|
};
|
||||||
|
use vulkano::format::Format;
|
||||||
use vulkano::image::view::ImageView;
|
use vulkano::image::view::ImageView;
|
||||||
use vulkano::image::{Image, ImageCreateInfo, ImageType, ImageUsage};
|
use vulkano::image::{Image, ImageCreateInfo, ImageType, ImageUsage};
|
||||||
use vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions};
|
use vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions};
|
||||||
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, StandardMemoryAllocator};
|
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, StandardMemoryAllocator};
|
||||||
use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo;
|
use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo;
|
||||||
use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState};
|
use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState};
|
||||||
|
use vulkano::pipeline::graphics::depth_stencil::{DepthState, DepthStencilState};
|
||||||
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
|
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
|
||||||
use vulkano::pipeline::graphics::multisample::MultisampleState;
|
use vulkano::pipeline::graphics::multisample::MultisampleState;
|
||||||
use vulkano::pipeline::graphics::rasterization::RasterizationState;
|
use vulkano::pipeline::graphics::rasterization::RasterizationState;
|
||||||
use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition};
|
use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition};
|
||||||
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
|
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
|
||||||
use vulkano::pipeline::layout::PipelineDescriptorSetLayoutCreateInfo;
|
use vulkano::pipeline::layout::PipelineDescriptorSetLayoutCreateInfo;
|
||||||
use vulkano::pipeline::{DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, PipelineShaderStageCreateInfo};
|
use vulkano::pipeline::{
|
||||||
|
DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout,
|
||||||
|
PipelineShaderStageCreateInfo,
|
||||||
|
};
|
||||||
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
|
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
|
||||||
use vulkano::shader::ShaderModule;
|
use vulkano::shader::ShaderModule;
|
||||||
use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo};
|
use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo};
|
||||||
use vulkano::sync::GpuFuture;
|
use vulkano::sync::GpuFuture;
|
||||||
use vulkano::{Validated, VulkanError, VulkanLibrary, swapchain, sync};
|
use vulkano::{Validated, VulkanError, VulkanLibrary, swapchain, sync};
|
||||||
use vulkano::format::Format;
|
|
||||||
use vulkano::pipeline::graphics::depth_stencil::{DepthState, DepthStencilState};
|
|
||||||
use winit::application::ApplicationHandler;
|
use winit::application::ApplicationHandler;
|
||||||
use winit::event::WindowEvent;
|
use winit::event::WindowEvent;
|
||||||
use winit::event_loop::ActiveEventLoop;
|
use winit::event_loop::ActiveEventLoop;
|
||||||
use winit::window::{Window, WindowAttributes, WindowId};
|
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 {
|
struct VulkanContext {
|
||||||
window: Arc<Window>,
|
window: Arc<Window>,
|
||||||
@@ -165,23 +168,14 @@ impl VulkanContext {
|
|||||||
let frag_shader = triangle::load_fragment(device.clone())
|
let frag_shader = triangle::load_fragment(device.clone())
|
||||||
.map_err(|e| format!("Failed to load fragment shader: {e}"))?;
|
.map_err(|e| format!("Failed to load fragment shader: {e}"))?;
|
||||||
|
|
||||||
let framebuffers = Self::create_framebuffers(
|
let framebuffers = Self::create_framebuffers(mem_allocator.clone(), &images, &render_pass)?;
|
||||||
mem_allocator.clone(),
|
|
||||||
&images,
|
|
||||||
&render_pass
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let image_extents = swapchain.image_extent();
|
let image_extents = swapchain.image_extent();
|
||||||
|
|
||||||
// Create the camera.
|
// Create the camera.
|
||||||
let camera = Camera::new(image_extents);
|
let camera = Camera::new(image_extents);
|
||||||
|
|
||||||
let pipeline = Self::create_pipeline(
|
let pipeline = Self::create_pipeline(&device, &vert_shader, &frag_shader, &render_pass)?;
|
||||||
&device,
|
|
||||||
&vert_shader,
|
|
||||||
&frag_shader,
|
|
||||||
&render_pass,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Get descriptor set layout
|
// Get descriptor set layout
|
||||||
let pipeline_layout = pipeline.layout().clone();
|
let pipeline_layout = pipeline.layout().clone();
|
||||||
@@ -191,17 +185,12 @@ impl VulkanContext {
|
|||||||
let camera_resources = CameraResources::new(
|
let camera_resources = CameraResources::new(
|
||||||
mem_allocator.clone(),
|
mem_allocator.clone(),
|
||||||
desc_allocator.clone(),
|
desc_allocator.clone(),
|
||||||
desc_set_layout
|
desc_set_layout,
|
||||||
);
|
);
|
||||||
|
|
||||||
let scene = Scene::from_file_json("./test_scene.scene");
|
let scene = Scene::from_file_json("./test_scene.scene");
|
||||||
let mesh_registry = Arc::new(MeshRegistry::from_scene(
|
let mesh_registry = Arc::new(MeshRegistry::from_scene(&scene, mem_allocator.clone()));
|
||||||
&scene,
|
let instance_registry = Arc::new(InstanceRegistry::from_scene(&scene));
|
||||||
mem_allocator.clone()
|
|
||||||
));
|
|
||||||
let instance_registry = Arc::new(InstanceRegistry::from_scene(
|
|
||||||
&scene
|
|
||||||
));
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
window,
|
window,
|
||||||
@@ -220,7 +209,7 @@ impl VulkanContext {
|
|||||||
mesh_registry,
|
mesh_registry,
|
||||||
instance_registry,
|
instance_registry,
|
||||||
camera,
|
camera,
|
||||||
camera_resources
|
camera_resources,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,16 +249,13 @@ impl VulkanContext {
|
|||||||
RenderBatch::build_batches(
|
RenderBatch::build_batches(
|
||||||
self.mem_allocator.clone(),
|
self.mem_allocator.clone(),
|
||||||
self.mesh_registry.clone(),
|
self.mesh_registry.clone(),
|
||||||
self.instance_registry.clone()
|
self.instance_registry.clone(),
|
||||||
)
|
),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let future = sync::now(self.device.clone())
|
let future = sync::now(self.device.clone())
|
||||||
.join(acquire_future)
|
.join(acquire_future)
|
||||||
.then_execute(
|
.then_execute(self.queue.clone(), cmd_buffer.clone())?
|
||||||
self.queue.clone(),
|
|
||||||
cmd_buffer.clone(),
|
|
||||||
)?
|
|
||||||
.then_swapchain_present(
|
.then_swapchain_present(
|
||||||
self.queue.clone(),
|
self.queue.clone(),
|
||||||
SwapchainPresentInfo::swapchain_image_index(self.swapchain.clone(), image_idx),
|
SwapchainPresentInfo::swapchain_image_index(self.swapchain.clone(), image_idx),
|
||||||
@@ -339,19 +325,17 @@ impl VulkanContext {
|
|||||||
images: &Vec<Arc<Image>>,
|
images: &Vec<Arc<Image>>,
|
||||||
render_pass: &Arc<RenderPass>,
|
render_pass: &Arc<RenderPass>,
|
||||||
) -> Result<Vec<Arc<Framebuffer>>, Box<dyn Error>> {
|
) -> Result<Vec<Arc<Framebuffer>>, Box<dyn Error>> {
|
||||||
let depth_buffer = ImageView::new_default(
|
let depth_buffer = ImageView::new_default(Image::new(
|
||||||
Image::new(
|
alloc.clone(),
|
||||||
alloc.clone(),
|
ImageCreateInfo {
|
||||||
ImageCreateInfo {
|
image_type: ImageType::Dim2d,
|
||||||
image_type: ImageType::Dim2d,
|
format: Format::D16_UNORM,
|
||||||
format: Format::D16_UNORM,
|
extent: images[0].extent(),
|
||||||
extent: images[0].extent(),
|
usage: ImageUsage::DEPTH_STENCIL_ATTACHMENT | ImageUsage::TRANSIENT_ATTACHMENT,
|
||||||
usage: ImageUsage::DEPTH_STENCIL_ATTACHMENT | ImageUsage::TRANSIENT_ATTACHMENT,
|
..Default::default()
|
||||||
..Default::default()
|
},
|
||||||
},
|
AllocationCreateInfo::default(),
|
||||||
AllocationCreateInfo::default()
|
)?)?;
|
||||||
)?
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let framebuffers = images
|
let framebuffers = images
|
||||||
.iter()
|
.iter()
|
||||||
@@ -388,8 +372,8 @@ impl VulkanContext {
|
|||||||
.entry_point("main")
|
.entry_point("main")
|
||||||
.ok_or("Failed to find fragment shader entry point")?;
|
.ok_or("Failed to find fragment shader entry point")?;
|
||||||
|
|
||||||
let vertex_input_state = [Vertex3::per_vertex(), GpuInstance::per_instance()]
|
let vertex_input_state =
|
||||||
.definition(&vs)?;
|
[Vertex3::per_vertex(), GpuInstance::per_instance()].definition(&vs)?;
|
||||||
|
|
||||||
let stages = vec![
|
let stages = vec![
|
||||||
PipelineShaderStageCreateInfo::new(vs),
|
PipelineShaderStageCreateInfo::new(vs),
|
||||||
@@ -453,15 +437,12 @@ impl VulkanContext {
|
|||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
)
|
)
|
||||||
.expect("Couldn't create command buffer builder");
|
.expect("Couldn't create command buffer builder");
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.begin_render_pass(
|
.begin_render_pass(
|
||||||
RenderPassBeginInfo {
|
RenderPassBeginInfo {
|
||||||
clear_values: vec![
|
clear_values: vec![Some([0.1, 0.1, 0.1, 0.5].into()), Some(1f32.into())],
|
||||||
Some([0.1, 0.1, 0.1, 0.5].into()),
|
|
||||||
Some(1f32.into()),
|
|
||||||
],
|
|
||||||
..RenderPassBeginInfo::framebuffer(framebuffer.clone())
|
..RenderPassBeginInfo::framebuffer(framebuffer.clone())
|
||||||
},
|
},
|
||||||
SubpassBeginInfo {
|
SubpassBeginInfo {
|
||||||
@@ -469,10 +450,7 @@ impl VulkanContext {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)?
|
)?
|
||||||
.set_viewport(
|
.set_viewport(0, [camera.viewport()].into_iter().collect())?
|
||||||
0,
|
|
||||||
[camera.viewport()].into_iter().collect()
|
|
||||||
)?
|
|
||||||
.bind_descriptor_sets(
|
.bind_descriptor_sets(
|
||||||
PipelineBindPoint::Graphics,
|
PipelineBindPoint::Graphics,
|
||||||
pipeline.layout().clone(),
|
pipeline.layout().clone(),
|
||||||
@@ -486,13 +464,20 @@ impl VulkanContext {
|
|||||||
unsafe {
|
unsafe {
|
||||||
render_batches.iter().for_each(|batch| {
|
render_batches.iter().for_each(|batch| {
|
||||||
// Grab mesh information
|
// Grab mesh information
|
||||||
let mesh = mesh_registry.get(&batch.mesh_id)
|
let mesh = mesh_registry
|
||||||
|
.get(&batch.mesh_id)
|
||||||
.expect("Mesh does not exist in registry");
|
.expect("Mesh does not exist in registry");
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.bind_vertex_buffers(1, batch.instance_buffer.clone())
|
.bind_vertex_buffers(1, batch.instance_buffer.clone())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.draw_indexed(mesh.index_count as u32, batch.instance_count, mesh.index_loc as u32, mesh.vertex_loc as i32, 0)
|
.draw_indexed(
|
||||||
|
mesh.index_count as u32,
|
||||||
|
batch.instance_count,
|
||||||
|
mesh.index_loc as u32,
|
||||||
|
mesh.vertex_loc as i32,
|
||||||
|
0,
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -524,12 +509,11 @@ impl VulkanContext {
|
|||||||
self.swapchain_images = new_images;
|
self.swapchain_images = new_images;
|
||||||
|
|
||||||
// Recreate the framebuffers, which depend on the swapchain.
|
// Recreate the framebuffers, which depend on the swapchain.
|
||||||
let new_framebuffers =
|
let new_framebuffers = Self::create_framebuffers(
|
||||||
Self::create_framebuffers(
|
self.mem_allocator.clone(),
|
||||||
self.mem_allocator.clone(),
|
&self.swapchain_images,
|
||||||
&self.swapchain_images,
|
&self.render_pass,
|
||||||
&self.render_pass
|
)?;
|
||||||
)?;
|
|
||||||
|
|
||||||
self.framebuffers = new_framebuffers;
|
self.framebuffers = new_framebuffers;
|
||||||
|
|
||||||
@@ -541,7 +525,8 @@ impl VulkanContext {
|
|||||||
&self.render_pass,
|
&self.render_pass,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.camera.extents([image_extents.width, image_extents.height]);
|
self.camera
|
||||||
|
.extents([image_extents.width, image_extents.height]);
|
||||||
|
|
||||||
self.pipeline = new_pipeline;
|
self.pipeline = new_pipeline;
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-30
@@ -1,13 +1,13 @@
|
|||||||
|
use crate::gpu::camera::CameraUniform;
|
||||||
|
use nalgebra::{Matrix4, Point3, Vector2, Vector3};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use nalgebra::{Matrix4, Point3, Vector2, Vector3};
|
|
||||||
use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer};
|
use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer};
|
||||||
use vulkano::descriptor_set::allocator::DescriptorSetAllocator;
|
use vulkano::descriptor_set::allocator::DescriptorSetAllocator;
|
||||||
use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet};
|
|
||||||
use vulkano::descriptor_set::layout::DescriptorSetLayout;
|
use vulkano::descriptor_set::layout::DescriptorSetLayout;
|
||||||
|
use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet};
|
||||||
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter};
|
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter};
|
||||||
use vulkano::pipeline::graphics::viewport::Viewport;
|
use vulkano::pipeline::graphics::viewport::Viewport;
|
||||||
use crate::gpu::camera::CameraUniform;
|
|
||||||
|
|
||||||
/// A camera set within 3D space.
|
/// A camera set within 3D space.
|
||||||
pub struct Camera {
|
pub struct Camera {
|
||||||
@@ -28,9 +28,7 @@ pub struct Camera {
|
|||||||
impl Camera {
|
impl Camera {
|
||||||
/// Creates a new camera. This default camera is positioned at (1, 1, 1) and is looking at
|
/// 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.
|
/// (0, 0, 0), and a default FOV of 70 degrees.
|
||||||
pub fn new(
|
pub fn new(extents: impl Into<Vector2<u32>>) -> Self {
|
||||||
extents: impl Into<Vector2<u32>>
|
|
||||||
) -> Self {
|
|
||||||
let extents = extents.into();
|
let extents = extents.into();
|
||||||
let position = Vector3::new(-7.0, 7.0, -7.0);
|
let position = Vector3::new(-7.0, 7.0, -7.0);
|
||||||
let target = Vector3::zeros();
|
let target = Vector3::zeros();
|
||||||
@@ -84,7 +82,7 @@ impl Camera {
|
|||||||
Matrix4::look_at_rh(
|
Matrix4::look_at_rh(
|
||||||
&Point3::from(self.position),
|
&Point3::from(self.position),
|
||||||
&Point3::from(self.forward - self.position),
|
&Point3::from(self.forward - self.position),
|
||||||
&self.up
|
&self.up,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,12 +90,7 @@ impl Camera {
|
|||||||
pub fn get_projection(&self) -> Matrix4<f32> {
|
pub fn get_projection(&self) -> Matrix4<f32> {
|
||||||
let aspect = self.extents.x as f32 / self.extents.y as f32;
|
let aspect = self.extents.x as f32 / self.extents.y as f32;
|
||||||
|
|
||||||
let mut proj = Matrix4::new_perspective(
|
let mut proj = Matrix4::new_perspective(aspect, self.fov, 1.0, 10000.0);
|
||||||
aspect,
|
|
||||||
self.fov,
|
|
||||||
1.0,
|
|
||||||
10000.0
|
|
||||||
);
|
|
||||||
|
|
||||||
// Flip the y-axis, since Vulkan uses a different coordinate system.
|
// Flip the y-axis, since Vulkan uses a different coordinate system.
|
||||||
proj[(1, 1)] *= -1.0;
|
proj[(1, 1)] *= -1.0;
|
||||||
@@ -133,30 +126,34 @@ impl CameraResources {
|
|||||||
desc_layout: Arc<DescriptorSetLayout>,
|
desc_layout: Arc<DescriptorSetLayout>,
|
||||||
) -> Arc<Self> {
|
) -> Arc<Self> {
|
||||||
// Allocate the buffer
|
// Allocate the buffer
|
||||||
let buffer = Arc::new(Buffer::new_sized::<CameraUniform>(
|
let buffer = Arc::new(
|
||||||
alloc.clone(),
|
Buffer::new_sized::<CameraUniform>(
|
||||||
BufferCreateInfo {
|
alloc.clone(),
|
||||||
usage: BufferUsage::UNIFORM_BUFFER,
|
BufferCreateInfo {
|
||||||
..Default::default()
|
usage: BufferUsage::UNIFORM_BUFFER,
|
||||||
},
|
..Default::default()
|
||||||
AllocationCreateInfo {
|
},
|
||||||
memory_type_filter: MemoryTypeFilter::PREFER_HOST |
|
AllocationCreateInfo {
|
||||||
MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
memory_type_filter: MemoryTypeFilter::PREFER_HOST
|
||||||
..Default::default()
|
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||||
}
|
..Default::default()
|
||||||
).expect("Couldn't allocate the camera uniform buffer"));
|
},
|
||||||
|
)
|
||||||
|
.expect("Couldn't allocate the camera uniform buffer"),
|
||||||
|
);
|
||||||
|
|
||||||
// Create the descriptor set
|
// Create the descriptor set
|
||||||
let descriptor_set = DescriptorSet::new(
|
let descriptor_set = DescriptorSet::new(
|
||||||
desc_alloc.clone(),
|
desc_alloc.clone(),
|
||||||
desc_layout,
|
desc_layout,
|
||||||
[WriteDescriptorSet::buffer(0, buffer.as_ref().clone())],
|
[WriteDescriptorSet::buffer(0, buffer.as_ref().clone())],
|
||||||
[]
|
[],
|
||||||
).expect("Couldn't create camera descriptor set");
|
)
|
||||||
|
.expect("Couldn't create camera descriptor set");
|
||||||
|
|
||||||
Arc::new(Self {
|
Arc::new(Self {
|
||||||
buffer,
|
buffer,
|
||||||
descriptor_set
|
descriptor_set,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,8 +163,7 @@ impl CameraResources {
|
|||||||
let view = camera.get_view();
|
let view = camera.get_view();
|
||||||
let proj = camera.get_projection();
|
let proj = camera.get_projection();
|
||||||
|
|
||||||
let mut buffer_data = self.buffer.write()
|
let mut buffer_data = self.buffer.write().unwrap();
|
||||||
.unwrap();
|
|
||||||
buffer_data.proj = proj.into();
|
buffer_data.proj = proj.into();
|
||||||
buffer_data.view = view.into();
|
buffer_data.view = view.into();
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-12
@@ -1,6 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use crate::common::scene::{Scene, SceneInstance};
|
use crate::common::scene::{Scene, SceneInstance};
|
||||||
use nalgebra::{Matrix4, Vector3, Vector4};
|
use nalgebra::{Matrix4, Vector3, Vector4};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// Contains all information about an instance of a mesh, specifically its translation, rotation,
|
/// Contains all information about an instance of a mesh, specifically its translation, rotation,
|
||||||
/// and scale. Note that the rotation is a [`Vector4`], and not a `Quaternion`.
|
/// and scale. Note that the rotation is a [`Vector4`], and not a `Quaternion`.
|
||||||
@@ -44,7 +44,13 @@ impl From<SceneInstance> for MeshInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl From<&SceneInstance> for MeshInstance {
|
impl From<&SceneInstance> for MeshInstance {
|
||||||
fn from(SceneInstance { translation, rotation, scale }: &SceneInstance) -> Self {
|
fn from(
|
||||||
|
SceneInstance {
|
||||||
|
translation,
|
||||||
|
rotation,
|
||||||
|
scale,
|
||||||
|
}: &SceneInstance,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
translation: Vector3::from(*translation).to_homogeneous(),
|
translation: Vector3::from(*translation).to_homogeneous(),
|
||||||
rotation: Vector3::from(*rotation).to_homogeneous(),
|
rotation: Vector3::from(*rotation).to_homogeneous(),
|
||||||
@@ -61,17 +67,18 @@ pub struct InstanceRegistry {
|
|||||||
impl InstanceRegistry {
|
impl InstanceRegistry {
|
||||||
pub fn from_scene(scene: &Scene) -> Self {
|
pub fn from_scene(scene: &Scene) -> Self {
|
||||||
// Read information about the instances from the scene.
|
// Read information about the instances from the scene.
|
||||||
let instances: HashMap<String, Vec<MeshInstance>> = scene.instances.iter()
|
let instances: HashMap<String, Vec<MeshInstance>> =
|
||||||
.fold(HashMap::new(), |mut map, (mesh_id, instance)| {
|
scene
|
||||||
map.entry(mesh_id.clone())
|
.instances
|
||||||
.and_modify(|v| v.push(instance.into()))
|
.iter()
|
||||||
.or_insert(vec![instance.into()]);
|
.fold(HashMap::new(), |mut map, (mesh_id, instance)| {
|
||||||
map
|
map.entry(mesh_id.clone())
|
||||||
});
|
.and_modify(|v| v.push(instance.into()))
|
||||||
|
.or_insert(vec![instance.into()]);
|
||||||
|
map
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self { instances }
|
||||||
instances
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_instances_for(&self, mesh_id: &String) -> Vec<MeshInstance> {
|
pub fn get_instances_for(&self, mesh_id: &String) -> Vec<MeshInstance> {
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct MaterialRegistry {
|
pub struct MaterialRegistry {
|
||||||
materials: HashMap<String, Material>
|
materials: HashMap<String, Material>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaterialRegistry {
|
impl MaterialRegistry {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
materials: HashMap::new()
|
materials: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-4
@@ -1,11 +1,11 @@
|
|||||||
use crate::common::scene::Scene;
|
use crate::common::scene::Scene;
|
||||||
use crate::gpu::vertex3::Vertex3;
|
use crate::gpu::vertex3::Vertex3;
|
||||||
|
use crate::loaders::mesh_loader::{MeshInfo, MeshLoader};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer};
|
use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer};
|
||||||
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter};
|
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter};
|
||||||
use wavefront::Obj;
|
use wavefront::Obj;
|
||||||
use crate::loaders::mesh_loader::{MeshInfo, MeshLoader};
|
|
||||||
|
|
||||||
/// This struct is slightly misleading - it doesn't actually contain the mesh information, but
|
/// This struct is slightly misleading - it doesn't actually contain the mesh information, but
|
||||||
/// the locations of the mesh's information in the overall application's vertex buffer, index buffer,
|
/// the locations of the mesh's information in the overall application's vertex buffer, index buffer,
|
||||||
@@ -56,7 +56,9 @@ impl MeshRegistry {
|
|||||||
.map(|(id, path)| {
|
.map(|(id, path)| {
|
||||||
(
|
(
|
||||||
id.clone(),
|
id.clone(),
|
||||||
mesh_loader.load_mesh(path).expect("Couldn't read wavefront file"),
|
mesh_loader
|
||||||
|
.load_mesh(path)
|
||||||
|
.expect("Couldn't read wavefront file"),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<HashMap<String, MeshInfo>>();
|
.collect::<HashMap<String, MeshInfo>>();
|
||||||
@@ -71,7 +73,9 @@ impl MeshRegistry {
|
|||||||
let all_verts = obj.vertices;
|
let all_verts = obj.vertices;
|
||||||
let all_norms = obj.normals;
|
let all_norms = obj.normals;
|
||||||
let obj_num_verts = all_verts.len();
|
let obj_num_verts = all_verts.len();
|
||||||
all_verts.iter().zip(all_norms.iter())
|
all_verts
|
||||||
|
.iter()
|
||||||
|
.zip(all_norms.iter())
|
||||||
.zip(obj.uvs.iter())
|
.zip(obj.uvs.iter())
|
||||||
.for_each(|((pos, norm), uv)| {
|
.for_each(|((pos, norm), uv)| {
|
||||||
buf_verts.push(Vertex3::new(*pos, *norm, *uv));
|
buf_verts.push(Vertex3::new(*pos, *norm, *uv));
|
||||||
@@ -81,7 +85,10 @@ impl MeshRegistry {
|
|||||||
let obj_num_idx = obj.indices.len();
|
let obj_num_idx = obj.indices.len();
|
||||||
buf_indices.extend(obj.indices);
|
buf_indices.extend(obj.indices);
|
||||||
|
|
||||||
println!("Loaded mesh \"{}\" with {} vertices and {} indices", id, obj_num_verts, obj_num_idx);
|
println!(
|
||||||
|
"Loaded mesh \"{}\" with {} vertices and {} indices",
|
||||||
|
id, obj_num_verts, obj_num_idx
|
||||||
|
);
|
||||||
|
|
||||||
// TODO Create bounding boxes for each mesh and associate them with the struct.
|
// TODO Create bounding boxes for each mesh and associate them with the struct.
|
||||||
mesh_list.insert(
|
mesh_list.insert(
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
pub mod instance;
|
|
||||||
pub mod mesh;
|
|
||||||
pub mod scene;
|
|
||||||
pub mod render_batch;
|
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
|
pub mod instance;
|
||||||
mod material;
|
mod material;
|
||||||
|
pub mod mesh;
|
||||||
|
pub mod render_batch;
|
||||||
|
pub mod scene;
|
||||||
+17
-14
@@ -1,9 +1,9 @@
|
|||||||
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::instance::InstanceRegistry;
|
||||||
use crate::common::mesh::MeshRegistry;
|
use crate::common::mesh::MeshRegistry;
|
||||||
use crate::gpu::instance::GpuInstance;
|
use crate::gpu::instance::GpuInstance;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer};
|
||||||
|
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RenderBatch {
|
pub struct RenderBatch {
|
||||||
@@ -18,9 +18,11 @@ impl RenderBatch {
|
|||||||
pub fn build_batches(
|
pub fn build_batches(
|
||||||
allocator: Arc<dyn MemoryAllocator>,
|
allocator: Arc<dyn MemoryAllocator>,
|
||||||
mesh_registry: Arc<MeshRegistry>,
|
mesh_registry: Arc<MeshRegistry>,
|
||||||
instance_registry: Arc<InstanceRegistry>
|
instance_registry: Arc<InstanceRegistry>,
|
||||||
) -> Vec<Self> {
|
) -> Vec<Self> {
|
||||||
mesh_registry.meshes.iter()
|
mesh_registry
|
||||||
|
.meshes
|
||||||
|
.iter()
|
||||||
.filter_map(|(id, mesh)| {
|
.filter_map(|(id, mesh)| {
|
||||||
let instances = instance_registry.get_instances_for(id);
|
let instances = instance_registry.get_instances_for(id);
|
||||||
|
|
||||||
@@ -29,11 +31,10 @@ impl RenderBatch {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let gpu_instances = instances.iter()
|
let gpu_instances = instances
|
||||||
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|instance| {
|
.map(|instance| instance.into())
|
||||||
instance.into()
|
|
||||||
})
|
|
||||||
.collect::<Vec<GpuInstance>>();
|
.collect::<Vec<GpuInstance>>();
|
||||||
|
|
||||||
// Build instances into a RenderBatch
|
// Build instances into a RenderBatch
|
||||||
@@ -44,18 +45,20 @@ impl RenderBatch {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
AllocationCreateInfo {
|
AllocationCreateInfo {
|
||||||
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE |
|
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
|
||||||
MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
gpu_instances
|
gpu_instances,
|
||||||
).expect("Couldn't allocate instance buffer");
|
)
|
||||||
|
.expect("Couldn't allocate instance buffer");
|
||||||
|
|
||||||
Some(Self {
|
Some(Self {
|
||||||
mesh_id: id.clone(),
|
mesh_id: id.clone(),
|
||||||
instance_buffer,
|
instance_buffer,
|
||||||
instance_count: instances.len() as u32,
|
instance_count: instances.len() as u32,
|
||||||
})
|
})
|
||||||
}).collect()
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+8
-9
@@ -89,24 +89,23 @@ pub struct SceneInstance {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod create_files {
|
pub mod create_files {
|
||||||
|
pub use super::*;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
pub use super::*;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn create_test_scene() -> Result<(), Box<dyn Error>> {
|
pub fn create_test_scene() -> Result<(), Box<dyn Error>> {
|
||||||
let scene = Scene {
|
let scene = Scene {
|
||||||
name: "Testing Scene".to_string(),
|
name: "Testing Scene".to_string(),
|
||||||
mesh_paths: HashMap::from([
|
mesh_paths: HashMap::from([("venator".to_string(), "Venator.obj".to_string())]),
|
||||||
("venator".to_string(), "Venator.obj".to_string())
|
instances: HashMap::from([(
|
||||||
]),
|
"venator".to_string(),
|
||||||
instances: HashMap::from([
|
SceneInstance {
|
||||||
("venator".to_string(), SceneInstance {
|
|
||||||
translation: [0.0, 0.0, 0.0],
|
translation: [0.0, 0.0, 0.0],
|
||||||
rotation: [0.0, 0.0, 0.0],
|
rotation: [0.0, 0.0, 0.0],
|
||||||
scale: [1.0, 1.0, 1.0]
|
scale: [1.0, 1.0, 1.0],
|
||||||
})
|
},
|
||||||
])
|
)]),
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = serde_json::to_string_pretty(&scene)?;
|
let json = serde_json::to_string_pretty(&scene)?;
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
use vulkano::buffer::BufferContents;
|
|
||||||
use crate::common::camera::Camera;
|
use crate::common::camera::Camera;
|
||||||
|
use vulkano::buffer::BufferContents;
|
||||||
|
|
||||||
#[derive(BufferContents)]
|
#[derive(BufferContents)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
|
pub mod camera;
|
||||||
pub mod instance;
|
pub mod instance;
|
||||||
pub mod vertex3;
|
pub mod vertex3;
|
||||||
pub mod camera;
|
|
||||||
+2
-6
@@ -13,15 +13,11 @@ pub struct Vertex3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Vertex3 {
|
impl Vertex3 {
|
||||||
pub fn new(
|
pub fn new(position: [f32; 3], normal: [f32; 3], uv: [f32; 3]) -> Self {
|
||||||
position: [f32; 3],
|
|
||||||
normal: [f32; 3],
|
|
||||||
uv: [f32; 3],
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
position,
|
position,
|
||||||
normal,
|
normal,
|
||||||
uv
|
uv,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::path::Path;
|
|
||||||
use anyhow::Result;
|
|
||||||
use crate::loaders::mesh_loader::{MeshFileLoader, MeshInfo};
|
use crate::loaders::mesh_loader::{MeshFileLoader, MeshInfo};
|
||||||
|
use anyhow::Result;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
pub struct GltfLoader;
|
pub struct GltfLoader;
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ impl MeshFileLoader for GltfLoader {
|
|||||||
vertices,
|
vertices,
|
||||||
indices,
|
indices,
|
||||||
normals,
|
normals,
|
||||||
uvs
|
uvs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+19
-11
@@ -1,9 +1,9 @@
|
|||||||
|
use super::gltf_loader::*;
|
||||||
|
use crate::loaders::obj_loader::ObjLoader;
|
||||||
|
use anyhow::Result;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use anyhow::Result;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use crate::loaders::obj_loader::ObjLoader;
|
|
||||||
use super::gltf_loader::*;
|
|
||||||
|
|
||||||
pub struct MeshInfo {
|
pub struct MeshInfo {
|
||||||
/// The mesh's vertices.
|
/// The mesh's vertices.
|
||||||
@@ -21,7 +21,7 @@ pub trait MeshFileLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct MeshLoader {
|
pub struct MeshLoader {
|
||||||
loaders: HashMap<String, Box<dyn MeshFileLoader>>
|
loaders: HashMap<String, Box<dyn MeshFileLoader>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
@@ -29,29 +29,37 @@ pub enum MeshLoaderError {
|
|||||||
#[error("file extension is missing")]
|
#[error("file extension is missing")]
|
||||||
MissingExtension,
|
MissingExtension,
|
||||||
#[error("extension {0} is not supported")]
|
#[error("extension {0} is not supported")]
|
||||||
ExtensionNotSupported(String)
|
ExtensionNotSupported(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MeshLoader {
|
impl MeshLoader {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut loaders = HashMap::new();
|
let mut loaders = HashMap::new();
|
||||||
loaders.insert("gltf".into(), Box::new(GltfLoader) as Box<dyn MeshFileLoader>);
|
loaders.insert(
|
||||||
|
"gltf".into(),
|
||||||
|
Box::new(GltfLoader) as Box<dyn MeshFileLoader>,
|
||||||
|
);
|
||||||
|
loaders.insert(
|
||||||
|
"glb".into(),
|
||||||
|
Box::new(GltfLoader) as Box<dyn MeshFileLoader>,
|
||||||
|
);
|
||||||
loaders.insert("obj".into(), Box::new(ObjLoader));
|
loaders.insert("obj".into(), Box::new(ObjLoader));
|
||||||
|
|
||||||
Self {
|
Self { loaders }
|
||||||
loaders
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a mesh and returns a `Result` containing the information.
|
/// Loads a mesh and returns a `Result` containing the information.
|
||||||
pub fn load_mesh<P: AsRef<Path>>(&self, path: &P) -> Result<MeshInfo> {
|
pub fn load_mesh<P: AsRef<Path>>(&self, path: &P) -> Result<MeshInfo> {
|
||||||
let ext = path.as_ref().extension()
|
let ext = path
|
||||||
|
.as_ref()
|
||||||
|
.extension()
|
||||||
.and_then(|ext| ext.to_str())
|
.and_then(|ext| ext.to_str())
|
||||||
.ok_or(MeshLoaderError::MissingExtension)?;
|
.ok_or(MeshLoaderError::MissingExtension)?;
|
||||||
|
|
||||||
println!("Found extension {}, continuing with loading", ext);
|
println!("Found extension {}, continuing with loading", ext);
|
||||||
|
|
||||||
self.loaders.get(ext)
|
self.loaders
|
||||||
|
.get(ext)
|
||||||
.ok_or(MeshLoaderError::ExtensionNotSupported(ext.to_string()))?
|
.ok_or(MeshLoaderError::ExtensionNotSupported(ext.to_string()))?
|
||||||
.load_mesh(path.as_ref())
|
.load_mesh(path.as_ref())
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
pub mod gltf_loader;
|
pub mod gltf_loader;
|
||||||
pub mod mesh_loader;
|
pub mod mesh_loader;
|
||||||
mod obj_loader;
|
mod obj_loader;
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
use std::path::Path;
|
|
||||||
use wavefront::Obj;
|
|
||||||
use crate::gpu::vertex3::Vertex3;
|
use crate::gpu::vertex3::Vertex3;
|
||||||
use crate::loaders::mesh_loader::{MeshFileLoader, MeshInfo};
|
use crate::loaders::mesh_loader::{MeshFileLoader, MeshInfo};
|
||||||
|
use std::path::Path;
|
||||||
|
use wavefront::Obj;
|
||||||
|
|
||||||
pub struct ObjLoader;
|
pub struct ObjLoader;
|
||||||
|
|
||||||
impl MeshFileLoader for ObjLoader {
|
impl MeshFileLoader for ObjLoader {
|
||||||
fn load_mesh(&self, path: &Path) -> anyhow::Result<MeshInfo> {
|
fn load_mesh(&self, path: &Path) -> anyhow::Result<MeshInfo> {
|
||||||
let obj_info = Obj::from_file(path)
|
let obj_info = Obj::from_file(path).expect("Couldn't read wavefront file");
|
||||||
.expect("Couldn't read wavefront file");
|
|
||||||
|
|
||||||
let index_list = obj_info
|
let index_list = obj_info
|
||||||
.triangles()
|
.triangles()
|
||||||
@@ -23,7 +22,7 @@ impl MeshFileLoader for ObjLoader {
|
|||||||
vertices: obj_info.positions().to_vec(),
|
vertices: obj_info.positions().to_vec(),
|
||||||
normals: obj_info.normals().to_vec(),
|
normals: obj_info.normals().to_vec(),
|
||||||
indices: index_list,
|
indices: index_list,
|
||||||
uvs: obj_info.uvs().to_vec()
|
uvs: obj_info.uvs().to_vec(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+25
-23
@@ -1,26 +1,28 @@
|
|||||||
{
|
{
|
||||||
"name": "Testing Scene",
|
"name": "Testing Scene",
|
||||||
"mesh_paths": {
|
"mesh_paths": {
|
||||||
"gunship": "meshes/laat_gunship/scene.obj",
|
"gunship": "meshes/laat_gunship/scene.obj",
|
||||||
"trooper": "meshes/clone_trooper/scene.gltf"
|
"trooper": "meshes/clone_trooper/scene.gltf",
|
||||||
},
|
"destroyer": "../meshes/sw_isd.glb",
|
||||||
"instances": {
|
"interceptor": "../meshes/sw_tie_interceptor.glb"
|
||||||
"trooper": {
|
},
|
||||||
"translation": [
|
"instances": {
|
||||||
0.0,
|
"interceptor": {
|
||||||
0.0,
|
"translation": [
|
||||||
0.0
|
0.0,
|
||||||
],
|
0.0,
|
||||||
"rotation": [
|
0.0
|
||||||
0.0,
|
],
|
||||||
0.0,
|
"rotation": [
|
||||||
0.0
|
0.0,
|
||||||
],
|
0.0,
|
||||||
"scale": [
|
0.0
|
||||||
1.0,
|
],
|
||||||
1.0,
|
"scale": [
|
||||||
1.0
|
1.0,
|
||||||
]
|
1.0,
|
||||||
|
1.0
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user