support instancing multiple meshes

This commit is contained in:
Carter Anderson 2020-01-11 13:14:26 -08:00
parent 4d903df33c
commit e1fb86ef8e

View file

@ -5,7 +5,7 @@ use crate::{
LocalToWorld, LocalToWorld,
}; };
use legion::prelude::*; use legion::prelude::*;
use std::mem; use std::{collections::HashMap, mem};
use wgpu::{Device, SwapChainOutput}; use wgpu::{Device, SwapChainOutput};
use zerocopy::AsBytes; use zerocopy::AsBytes;
@ -33,26 +33,45 @@ impl ForwardInstancedPipeline {
Read<Handle<Mesh>>, Read<Handle<Mesh>>,
Read<Instanced>, Read<Instanced>,
)>::query(); )>::query();
let entities_count = entities.iter(world).count(); if entities.iter(world).count() == 0 {
if entities_count == 0 {
return Vec::new(); return Vec::new();
} }
let size = mem::size_of::<SimpleMaterialUniforms>(); let uniform_size = mem::size_of::<SimpleMaterialUniforms>();
let mut mesh_groups: HashMap<
usize,
Vec<(
legion::borrow::Ref<Material>,
legion::borrow::Ref<LocalToWorld>,
)>,
> = HashMap::new();
for (material, transform, mesh, _) in entities.iter(world) {
match mesh_groups.get_mut(&mesh.id) {
Some(entities) => {
entities.push((material, transform));
}
None => {
let mut entities = Vec::new();
let id = mesh.id;
entities.push((material, transform));
mesh_groups.insert(id, entities);
}
}
}
let mut instance_buffer_infos = Vec::new();
for (mesh_id, mut same_mesh_entities) in mesh_groups {
let temp_buf_data = device.create_buffer_mapped( let temp_buf_data = device.create_buffer_mapped(
entities_count * size, same_mesh_entities.len() * uniform_size,
wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::VERTEX, wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::VERTEX,
); );
// TODO: generate these buffers for multiple meshes let entity_count = same_mesh_entities.len();
for ((material, transform), slot) in same_mesh_entities
let mut last_mesh_id = None; .drain(..)
for ((material, transform, mesh, _), slot) in entities .zip(temp_buf_data.data.chunks_exact_mut(uniform_size))
.iter(world)
.zip(temp_buf_data.data.chunks_exact_mut(size))
{ {
last_mesh_id = Some(mesh.id);
let (_, _, translation) = transform.0.to_scale_rotation_translation(); let (_, _, translation) = transform.0.to_scale_rotation_translation();
slot.copy_from_slice( slot.copy_from_slice(
SimpleMaterialUniforms { SimpleMaterialUniforms {
@ -63,12 +82,13 @@ impl ForwardInstancedPipeline {
); );
} }
let mut instance_buffer_infos = Vec::new();
instance_buffer_infos.push(InstanceBufferInfo { instance_buffer_infos.push(InstanceBufferInfo {
mesh_id: last_mesh_id.unwrap(), mesh_id: mesh_id,
buffer: temp_buf_data.finish(), buffer: temp_buf_data.finish(),
instance_count: entities_count, instance_count: entity_count,
}); });
}
instance_buffer_infos instance_buffer_infos
} }
@ -261,10 +281,7 @@ impl Pipeline for ForwardInstancedPipeline {
)); ));
pass.set_bind_group(0, self.local_bind_group.as_ref().unwrap(), &[]); pass.set_bind_group(0, self.local_bind_group.as_ref().unwrap(), &[]);
let mut mesh_storage = world let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
.resources
.get_mut::<AssetStorage<Mesh>>()
.unwrap();
for instance_buffer_info in self.instance_buffer_infos.as_ref().unwrap().iter() { for instance_buffer_info in self.instance_buffer_infos.as_ref().unwrap().iter() {
if let Some(mesh_asset) = mesh_storage.get(instance_buffer_info.mesh_id) { if let Some(mesh_asset) = mesh_storage.get(instance_buffer_info.mesh_id) {
mesh_asset.setup_buffers(&render_graph.device); mesh_asset.setup_buffers(&render_graph.device);