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
+26
-30
@@ -1,13 +1,13 @@
|
||||
use crate::gpu::camera::CameraUniform;
|
||||
use nalgebra::{Matrix4, Point3, Vector2, Vector3};
|
||||
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::descriptor_set::{DescriptorSet, WriteDescriptorSet};
|
||||
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter};
|
||||
use vulkano::pipeline::graphics::viewport::Viewport;
|
||||
use crate::gpu::camera::CameraUniform;
|
||||
|
||||
/// A camera set within 3D space.
|
||||
pub struct Camera {
|
||||
@@ -28,9 +28,7 @@ pub struct Camera {
|
||||
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<Vector2<u32>>
|
||||
) -> Self {
|
||||
pub fn new(extents: impl Into<Vector2<u32>>) -> Self {
|
||||
let extents = extents.into();
|
||||
let position = Vector3::new(-7.0, 7.0, -7.0);
|
||||
let target = Vector3::zeros();
|
||||
@@ -84,7 +82,7 @@ impl Camera {
|
||||
Matrix4::look_at_rh(
|
||||
&Point3::from(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> {
|
||||
let aspect = self.extents.x as f32 / self.extents.y as f32;
|
||||
|
||||
let mut proj = Matrix4::new_perspective(
|
||||
aspect,
|
||||
self.fov,
|
||||
1.0,
|
||||
10000.0
|
||||
);
|
||||
let mut proj = Matrix4::new_perspective(aspect, self.fov, 1.0, 10000.0);
|
||||
|
||||
// Flip the y-axis, since Vulkan uses a different coordinate system.
|
||||
proj[(1, 1)] *= -1.0;
|
||||
@@ -133,30 +126,34 @@ impl CameraResources {
|
||||
desc_layout: Arc<DescriptorSetLayout>,
|
||||
) -> Arc<Self> {
|
||||
// Allocate the buffer
|
||||
let buffer = Arc::new(Buffer::new_sized::<CameraUniform>(
|
||||
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"));
|
||||
let buffer = Arc::new(
|
||||
Buffer::new_sized::<CameraUniform>(
|
||||
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");
|
||||
[],
|
||||
)
|
||||
.expect("Couldn't create camera descriptor set");
|
||||
|
||||
Arc::new(Self {
|
||||
buffer,
|
||||
descriptor_set
|
||||
descriptor_set,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -166,8 +163,7 @@ impl CameraResources {
|
||||
let view = camera.get_view();
|
||||
let proj = camera.get_projection();
|
||||
|
||||
let mut buffer_data = self.buffer.write()
|
||||
.unwrap();
|
||||
let mut buffer_data = self.buffer.write().unwrap();
|
||||
buffer_data.proj = proj.into();
|
||||
buffer_data.view = view.into();
|
||||
}
|
||||
|
||||
+19
-12
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
use crate::common::scene::{Scene, SceneInstance};
|
||||
use nalgebra::{Matrix4, Vector3, Vector4};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// 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`.
|
||||
@@ -44,7 +44,13 @@ 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 {
|
||||
translation: Vector3::from(*translation).to_homogeneous(),
|
||||
rotation: Vector3::from(*rotation).to_homogeneous(),
|
||||
@@ -61,17 +67,18 @@ pub struct InstanceRegistry {
|
||||
impl InstanceRegistry {
|
||||
pub fn from_scene(scene: &Scene) -> Self {
|
||||
// Read information about the instances from the scene.
|
||||
let instances: HashMap<String, Vec<MeshInstance>> = 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
|
||||
});
|
||||
let instances: HashMap<String, Vec<MeshInstance>> =
|
||||
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
|
||||
}
|
||||
Self { instances }
|
||||
}
|
||||
|
||||
pub fn get_instances_for(&self, mesh_id: &String) -> Vec<MeshInstance> {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct MaterialRegistry {
|
||||
materials: HashMap<String, Material>
|
||||
materials: HashMap<String, Material>,
|
||||
}
|
||||
|
||||
impl MaterialRegistry {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
materials: HashMap::new()
|
||||
materials: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-4
@@ -1,11 +1,11 @@
|
||||
use crate::common::scene::Scene;
|
||||
use crate::gpu::vertex3::Vertex3;
|
||||
use crate::loaders::mesh_loader::{MeshInfo, MeshLoader};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer};
|
||||
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter};
|
||||
use wavefront::Obj;
|
||||
use crate::loaders::mesh_loader::{MeshInfo, MeshLoader};
|
||||
|
||||
/// 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,
|
||||
@@ -56,7 +56,9 @@ impl MeshRegistry {
|
||||
.map(|(id, path)| {
|
||||
(
|
||||
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>>();
|
||||
@@ -71,7 +73,9 @@ impl MeshRegistry {
|
||||
let all_verts = obj.vertices;
|
||||
let all_norms = obj.normals;
|
||||
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())
|
||||
.for_each(|((pos, norm), uv)| {
|
||||
buf_verts.push(Vertex3::new(*pos, *norm, *uv));
|
||||
@@ -81,7 +85,10 @@ impl MeshRegistry {
|
||||
let obj_num_idx = obj.indices.len();
|
||||
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.
|
||||
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 instance;
|
||||
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::mesh::MeshRegistry;
|
||||
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)]
|
||||
pub struct RenderBatch {
|
||||
@@ -18,9 +18,11 @@ impl RenderBatch {
|
||||
pub fn build_batches(
|
||||
allocator: Arc<dyn MemoryAllocator>,
|
||||
mesh_registry: Arc<MeshRegistry>,
|
||||
instance_registry: Arc<InstanceRegistry>
|
||||
instance_registry: Arc<InstanceRegistry>,
|
||||
) -> Vec<Self> {
|
||||
mesh_registry.meshes.iter()
|
||||
mesh_registry
|
||||
.meshes
|
||||
.iter()
|
||||
.filter_map(|(id, mesh)| {
|
||||
let instances = instance_registry.get_instances_for(id);
|
||||
|
||||
@@ -29,11 +31,10 @@ impl RenderBatch {
|
||||
return None;
|
||||
}
|
||||
|
||||
let gpu_instances = instances.iter()
|
||||
let gpu_instances = instances
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|instance| {
|
||||
instance.into()
|
||||
})
|
||||
.map(|instance| instance.into())
|
||||
.collect::<Vec<GpuInstance>>();
|
||||
|
||||
// Build instances into a RenderBatch
|
||||
@@ -44,18 +45,20 @@ impl RenderBatch {
|
||||
..Default::default()
|
||||
},
|
||||
AllocationCreateInfo {
|
||||
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE |
|
||||
MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
|
||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||
..Default::default()
|
||||
},
|
||||
gpu_instances
|
||||
).expect("Couldn't allocate instance buffer");
|
||||
gpu_instances,
|
||||
)
|
||||
.expect("Couldn't allocate instance buffer");
|
||||
|
||||
Some(Self {
|
||||
mesh_id: id.clone(),
|
||||
instance_buffer,
|
||||
instance_count: instances.len() as u32,
|
||||
})
|
||||
}).collect()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
+8
-9
@@ -89,24 +89,23 @@ pub struct SceneInstance {
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod create_files {
|
||||
pub use super::*;
|
||||
use std::error::Error;
|
||||
use std::io::Write;
|
||||
pub use super::*;
|
||||
|
||||
#[test]
|
||||
pub fn create_test_scene() -> Result<(), Box<dyn Error>> {
|
||||
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 {
|
||||
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]
|
||||
})
|
||||
])
|
||||
scale: [1.0, 1.0, 1.0],
|
||||
},
|
||||
)]),
|
||||
};
|
||||
|
||||
let json = serde_json::to_string_pretty(&scene)?;
|
||||
|
||||
Reference in new issue
Block a user