Start implementing the new Model and Mesh types with the renderer

This commit is contained in:
SeanOMik 2023-09-29 14:46:08 -04:00
parent 9d6d51af83
commit fdf1c4d338
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
4 changed files with 99 additions and 95 deletions

View File

@ -1,18 +1,16 @@
use edict::Component; use edict::Component;
use crate::render::{vertex::Vertex, mesh::Mesh, material::Material}; use lyra_resource::Mesh;
#[derive(Clone, Component)] #[derive(Clone, Component)]
pub struct MeshComponent { pub struct MeshComponent {
pub mesh: Mesh, pub mesh: Mesh,
pub material: Material,
} }
impl MeshComponent { impl MeshComponent {
pub fn new(mesh: Mesh, material: Material) -> Self { pub fn new(mesh: Mesh) -> Self {
Self { Self {
mesh, mesh,
material
} }
} }
} }

View File

@ -1,22 +1,22 @@
use crate::assets::{Model, Resource}; use lyra_resource::ResHandle;
use std::sync::Arc; use crate::assets::Model;
#[derive(Clone, edict::Component)] #[derive(Clone, edict::Component)]
pub struct ModelComponent(pub Arc<Resource<Model>>); pub struct ModelComponent(pub ResHandle<Model>);
impl From<Arc<Resource<Model>>> for ModelComponent { impl From<ResHandle<Model>> for ModelComponent {
fn from(value: Arc<Resource<Model>>) -> Self { fn from(value: ResHandle<Model>) -> Self {
ModelComponent(value) ModelComponent(value)
} }
} }
/* impl From<Arc<Resource<Model>> for ModelComponent { /* impl From<ResHandle<Model> for ModelComponent {
} */ } */
impl std::ops::Deref for ModelComponent { impl std::ops::Deref for ModelComponent {
type Target = Arc<Resource<Model>>; type Target = ResHandle<Model>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.0

View File

@ -2,11 +2,11 @@ use edict::EntityId;
use crate::math::Transform; use crate::math::Transform;
use super::{mesh::Mesh, material::Material}; //use super::mesh::Mesh;
use lyra_resource::Mesh;
pub struct RenderJob { pub struct RenderJob {
mesh: Mesh, mesh: Mesh,
material: Material,
entity: EntityId, entity: EntityId,
transform: Transform, transform: Transform,
@ -14,10 +14,9 @@ pub struct RenderJob {
} }
impl RenderJob { impl RenderJob {
pub fn new(mesh: Mesh, material: Material, entity: EntityId, transform: Transform, last_transform: Option<Transform>) -> Self { pub fn new(mesh: Mesh, entity: EntityId, transform: Transform, last_transform: Option<Transform>) -> Self {
Self { Self {
mesh, mesh,
material,
entity, entity,
transform, transform,
last_transform, last_transform,
@ -28,10 +27,6 @@ impl RenderJob {
&self.mesh &self.mesh
} }
pub fn material(&self)-> &Material {
&self.material
}
pub fn entity(&self)-> EntityId { pub fn entity(&self)-> EntityId {
self.entity self.entity
} }

View File

@ -5,30 +5,25 @@ use std::num::NonZeroU64;
use std::sync::Arc; use std::sync::Arc;
use std::borrow::Cow; use std::borrow::Cow;
use aligned_vec::AVec;
use async_std::sync::Mutex;
use async_trait::async_trait;
use atomicell::{AtomicCell, RefMut};
use edict::query::EpochOf; use edict::query::EpochOf;
use edict::{EntityId, Entities}; use edict::{EntityId, Entities};
use glam::Mat4; use glam::Vec3;
use tracing::{debug, warn}; use tracing::{debug, warn};
use wgpu::{BindGroup, BindGroupLayout, Limits, BufferBinding}; use wgpu::{BindGroup, BindGroupLayout, Limits};
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use winit::window::Window; use winit::window::Window;
use crate::ecs::components::camera::CameraComponent; use crate::ecs::components::camera::CameraComponent;
use crate::ecs::components::mesh::MeshComponent; use crate::ecs::components::mesh::MeshComponent;
use crate::ecs::components::model::ModelComponent;
use crate::ecs::components::transform::TransformComponent; use crate::ecs::components::transform::TransformComponent;
use crate::math::{Transform, Angle};
use crate::resources;
use super::camera::RenderCamera; use super::camera::RenderCamera;
use super::desc_buf_lay::DescVertexBufferLayout; use super::desc_buf_lay::DescVertexBufferLayout;
use super::texture::RenderTexture; use super::texture::RenderTexture;
use super::vertex::Vertex; use super::{render_pipeline::FullRenderPipeline, render_buffer::BufferStorage, render_job::RenderJob};
use super::{render_pipeline::FullRenderPipeline, render_buffer::BufferStorage, render_job::RenderJob, mesh::Mesh};
use lyra_resource::Mesh;
pub trait Renderer { pub trait Renderer {
fn prepare(&mut self, main_world: &mut edict::World); fn prepare(&mut self, main_world: &mut edict::World);
@ -36,7 +31,7 @@ pub trait Renderer {
fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>); fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>);
fn surface_size(&self) -> winit::dpi::PhysicalSize<u32>; fn surface_size(&self) -> winit::dpi::PhysicalSize<u32>;
fn add_render_pipeline(&mut self, shader_id: u32, pipeline: Arc<FullRenderPipeline>); fn add_render_pipeline(&mut self, shader_id: u64, pipeline: Arc<FullRenderPipeline>);
} }
struct RenderBufferStorage { struct RenderBufferStorage {
@ -145,7 +140,7 @@ pub struct BasicRenderer {
pub clear_color: wgpu::Color, pub clear_color: wgpu::Color,
pub render_pipelines: HashMap<u32, Arc<FullRenderPipeline>>, pub render_pipelines: HashMap<u64, Arc<FullRenderPipeline>>,
pub render_jobs: VecDeque<RenderJob>, pub render_jobs: VecDeque<RenderJob>,
buffer_storage: HashMap<EntityId, RenderBufferStorage>, // TODO: clean up left over buffers from deleted entities/components buffer_storage: HashMap<EntityId, RenderBufferStorage>, // TODO: clean up left over buffers from deleted entities/components
@ -391,13 +386,13 @@ impl BasicRenderer {
} }
// TODO: minimize how often model buffers are updated by checking if they changed // TODO: minimize how often model buffers are updated by checking if they changed
fn update_model_buffers(&mut self, entity: EntityId, model: &MeshComponent) { fn update_mesh_buffers(&mut self, entity: EntityId, mesh: &Mesh) {
if let Some(buffers) = self.buffer_storage.get_mut(&entity) { if let Some(buffers) = self.buffer_storage.get_mut(&entity) {
// check if the buffer sizes dont match. If they dont, completely remake the buffers // check if the buffer sizes dont match. If they dont, completely remake the buffers
let vertices = &model.mesh.vertices; let vertices = mesh.position().unwrap();
if buffers.buffer_vertex.count() != vertices.len() { if buffers.buffer_vertex.count() != vertices.len() {
drop(buffers); drop(buffers);
let (vert, idx) = self.create_vertex_index_buffers(&model.mesh); let (vert, idx) = self.create_vertex_index_buffers(mesh);
// have to re-get buffers because of borrow checker // have to re-get buffers because of borrow checker
let buffers = self.buffer_storage.get_mut(&entity).unwrap(); let buffers = self.buffer_storage.get_mut(&entity).unwrap();
@ -411,14 +406,14 @@ impl BasicRenderer {
let vertex_buffer = buffers.buffer_vertex.buffer(); let vertex_buffer = buffers.buffer_vertex.buffer();
let vertices = vertices.as_slice(); let vertices = vertices.as_slice();
// align the vertices to 4 bytes (u32 is 4 bytes, which is wgpu::COPY_BUFFER_ALIGNMENT) // align the vertices to 4 bytes (u32 is 4 bytes, which is wgpu::COPY_BUFFER_ALIGNMENT)
let (_, vertices, _) = bytemuck::pod_align_to::<Vertex, u32>(vertices); let (_, vertices, _) = bytemuck::pod_align_to::<Vec3, u32>(vertices);
self.queue.write_buffer(&vertex_buffer, 0, bytemuck::cast_slice(&vertices)); self.queue.write_buffer(&vertex_buffer, 0, bytemuck::cast_slice(&vertices));
// update the indices if they're given // update the indices if they're given
if let Some(index_buffer) = buffers.buffer_indices.as_ref() { if let Some(index_buffer) = buffers.buffer_indices.as_ref() {
let index_buffer = index_buffer.buffer(); let index_buffer = index_buffer.buffer();
let indices = model.mesh.indices.as_ref().unwrap().as_slice(); let indices = mesh.indices.as_ref().unwrap().as_slice();
let (_, indices, _) = bytemuck::pod_align_to::<u16, u32>(indices); let (_, indices, _) = bytemuck::pod_align_to::<u32, u32>(indices); // TODO: Don't force indicies into u32
self.queue.write_buffer(index_buffer, 0, bytemuck::cast_slice(&indices)); self.queue.write_buffer(index_buffer, 0, bytemuck::cast_slice(&indices));
} }
@ -426,14 +421,15 @@ impl BasicRenderer {
} }
fn create_vertex_index_buffers(&mut self, mesh: &Mesh) -> (BufferStorage, Option<BufferStorage>) { fn create_vertex_index_buffers(&mut self, mesh: &Mesh) -> (BufferStorage, Option<BufferStorage>) {
let vertices = mesh.position().unwrap();
let vertex_buffer = self.device.create_buffer_init( let vertex_buffer = self.device.create_buffer_init(
&wgpu::util::BufferInitDescriptor { &wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"), label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(mesh.vertices.as_slice()), contents: bytemuck::cast_slice(vertices.as_slice()),
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages:: COPY_DST, usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages:: COPY_DST,
} }
); );
let vertex_buffer = BufferStorage::new(vertex_buffer, 0, mesh.vertices.len()); let vertex_buffer = BufferStorage::new(vertex_buffer, 0, vertices.len());
let buffer_indices = match mesh.indices.as_ref() { let buffer_indices = match mesh.indices.as_ref() {
Some(indices) => { Some(indices) => {
@ -457,63 +453,66 @@ impl BasicRenderer {
( vertex_buffer, buffer_indices ) ( vertex_buffer, buffer_indices )
} }
fn create_model_buffers(&mut self, model: &MeshComponent, transform_indices: TransformBufferIndices) -> RenderBufferStorage { fn create_mesh_buffers(&mut self, mesh: &Mesh, transform_indices: TransformBufferIndices) -> RenderBufferStorage {
let mesh = &model.mesh;
let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(mesh); let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(mesh);
let model_texture = &model.material.texture; let (diffuse_layout, diffuse_bindgroup) = if let Some(model_texture) = &mesh.material().texture {
let image = &model_texture.data.as_ref().unwrap().image; let image = &model_texture.data.as_ref().unwrap().image;
let diffuse_texture = RenderTexture::from_image(&self.device, &self.queue, image, None).unwrap(); let diffuse_texture = RenderTexture::from_image(&self.device, &self.queue, image, None).unwrap();
let texture_bind_group_layout = let texture_bind_group_layout =
self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[ entries: &[
wgpu::BindGroupLayoutEntry { wgpu::BindGroupLayoutEntry {
binding: 0, binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT, visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture { ty: wgpu::BindingType::Texture {
multisampled: false, multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2, view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true }, sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
}, },
count: None, wgpu::BindGroupLayoutEntry {
}, binding: 1,
wgpu::BindGroupLayoutEntry { visibility: wgpu::ShaderStages::FRAGMENT,
binding: 1, // This should match the filterable field of the
visibility: wgpu::ShaderStages::FRAGMENT, // corresponding Texture entry above.
// This should match the filterable field of the ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
// corresponding Texture entry above. count: None,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), },
count: None, ],
}, label: Some("texture_bind_group_layout"),
], });
label: Some("texture_bind_group_layout"),
});
let diffuse_bind_group = self.device.create_bind_group( let diffuse_bind_group = self.device.create_bind_group(
&wgpu::BindGroupDescriptor { &wgpu::BindGroupDescriptor {
layout: &texture_bind_group_layout, layout: &texture_bind_group_layout,
entries: &[ entries: &[
wgpu::BindGroupEntry { wgpu::BindGroupEntry {
binding: 0, binding: 0,
resource: wgpu::BindingResource::TextureView(diffuse_texture.view()), resource: wgpu::BindingResource::TextureView(diffuse_texture.view()),
}, },
wgpu::BindGroupEntry { wgpu::BindGroupEntry {
binding: 1, binding: 1,
resource: wgpu::BindingResource::Sampler(diffuse_texture.sampler()), resource: wgpu::BindingResource::Sampler(diffuse_texture.sampler()),
} }
], ],
label: Some("diffuse_bind_group"), label: Some("diffuse_bind_group"),
} }
); );
(Some(texture_bind_group_layout), Some(diffuse_bind_group))
} else {
(None, None)
};
RenderBufferStorage { RenderBufferStorage {
buffer_vertex: vertex_buffer, buffer_vertex: vertex_buffer,
buffer_indices, buffer_indices,
render_texture: None, render_texture: None,
texture_layout: None, texture_layout: diffuse_layout,
texture_bindgroup: Some(diffuse_bind_group), texture_bindgroup: diffuse_bindgroup,
transform_index: transform_indices transform_index: transform_indices
} }
} }
@ -561,9 +560,13 @@ impl Renderer for BasicRenderer {
let mut alive_entities = HashSet::new(); let mut alive_entities = HashSet::new();
for (entity, model, model_epoch, transform) in main_world.query::<(Entities, &MeshComponent, EpochOf<MeshComponent>, &TransformComponent)>().iter() { for (entity, model, model_epoch, transform) in main_world.query::<(Entities, &ModelComponent, EpochOf<ModelComponent>, &TransformComponent)>().iter() {
debug!("Collecting model things");
let model = model.data.as_ref().unwrap().as_ref();
let model_mesh = model.meshes.first().unwrap();
// Create the render job and push it to the queue // Create the render job and push it to the queue
let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity, transform.transform, None); let job = RenderJob::new(model_mesh.clone(), entity, transform.transform, None);
self.render_jobs.push_back(job); self.render_jobs.push_back(job);
alive_entities.insert(entity); alive_entities.insert(entity);
@ -579,7 +582,7 @@ impl Renderer for BasicRenderer {
entity, transform.transform.calculate_mat4()); entity, transform.transform.calculate_mat4());
// create the mesh's buffers // create the mesh's buffers
let buffers = self.create_model_buffers(model, indices); let buffers = self.create_mesh_buffers(model_mesh, indices);
self.buffer_storage.insert(entity, buffers); self.buffer_storage.insert(entity, buffers);
} else { } else {
// update entity transforms // update entity transforms
@ -588,11 +591,15 @@ impl Renderer for BasicRenderer {
// if the model was updated, update its buffers // if the model was updated, update its buffers
if model_epoch == last_epoch { if model_epoch == last_epoch {
self.update_model_buffers(entity, model); self.update_mesh_buffers(entity, model_mesh);
} }
} }
} }
for (entity, mesh, mesh_epoch, transform) in main_world.query::<(Entities, &MeshComponent, EpochOf<MeshComponent>, &TransformComponent)>().iter() {
debug!("TODO: Process MeshComponents"); // TODO: Process MeshComponents
}
// collect dead entities // collect dead entities
self.transform_buffers.tick(); self.transform_buffers.tick();
@ -642,9 +649,11 @@ impl Renderer for BasicRenderer {
}), }),
}); });
debug!("Executing {} render jobs", self.render_jobs.len());
// Pop off jobs from the queue as they're being processed // Pop off jobs from the queue as they're being processed
while let Some(job) = self.render_jobs.pop_front() { while let Some(job) = self.render_jobs.pop_front() {
if let Some(pipeline) = self.render_pipelines.get(&job.material().shader_id) { if let Some(pipeline) = self.render_pipelines.get(&job.mesh().material().shader_uuid.unwrap_or(0)) {
// specify to use this pipeline // specify to use this pipeline
render_pass.set_pipeline(pipeline.get_wgpu_pipeline()); render_pass.set_pipeline(pipeline.get_wgpu_pipeline());
@ -674,11 +683,13 @@ impl Renderer for BasicRenderer {
render_pass.set_index_buffer(indices.buffer().slice(..), wgpu::IndexFormat::Uint16); render_pass.set_index_buffer(indices.buffer().slice(..), wgpu::IndexFormat::Uint16);
render_pass.draw_indexed(0..indices_len, 0, 0..1); render_pass.draw_indexed(0..indices_len, 0, 0..1);
} else { } else {
let vertices = mesh.position().unwrap();
render_pass.set_vertex_buffer(buffers.buffer_vertex.slot(), buffers.buffer_vertex.buffer().slice(..)); render_pass.set_vertex_buffer(buffers.buffer_vertex.slot(), buffers.buffer_vertex.buffer().slice(..));
render_pass.draw(0..mesh.vertices.len() as u32, 0..1); render_pass.draw(0..vertices.len() as u32, 0..1);
} }
} else { } else {
warn!("Failure to find RenderPipeline with shader id of '{}'!", job.material().shader_id); warn!("Failure to find RenderPipeline with shader id of '{}'!", job.mesh().material().shader_uuid.unwrap_or(0));
} }
} }
} }
@ -706,7 +717,7 @@ impl Renderer for BasicRenderer {
self.size self.size
} }
fn add_render_pipeline(&mut self, shader_id: u32, pipeline: Arc<FullRenderPipeline>) { fn add_render_pipeline(&mut self, shader_id: u64, pipeline: Arc<FullRenderPipeline>) {
self.render_pipelines.insert(shader_id, pipeline); self.render_pipelines.insert(shader_id, pipeline);
} }
} }