feat: additional implementation of renderer

This commit is contained in:
alphafetus committed 2026-08-25 10:31:36 -04:00
1 parent 639875b603
commit 8683f8b565
16 files changed
+197 -195

No files matched your search

+26 -30
View File
@@ -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
View File
@@ -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> {
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)?;