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,42 +33,62 @@ 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 temp_buf_data = device.create_buffer_mapped( let mut mesh_groups: HashMap<
entities_count * size, usize,
wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::VERTEX, Vec<(
); legion::borrow::Ref<Material>,
legion::borrow::Ref<LocalToWorld>,
// TODO: generate these buffers for multiple meshes )>,
> = HashMap::new();
let mut last_mesh_id = None; for (material, transform, mesh, _) in entities.iter(world) {
for ((material, transform, mesh, _), slot) in entities match mesh_groups.get_mut(&mesh.id) {
.iter(world) Some(entities) => {
.zip(temp_buf_data.data.chunks_exact_mut(size)) entities.push((material, transform));
{
last_mesh_id = Some(mesh.id);
let (_, _, translation) = transform.0.to_scale_rotation_translation();
slot.copy_from_slice(
SimpleMaterialUniforms {
position: translation.into(),
color: material.color.into(),
} }
.as_bytes(), 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(); let mut instance_buffer_infos = Vec::new();
instance_buffer_infos.push(InstanceBufferInfo { for (mesh_id, mut same_mesh_entities) in mesh_groups {
mesh_id: last_mesh_id.unwrap(), let temp_buf_data = device.create_buffer_mapped(
buffer: temp_buf_data.finish(), same_mesh_entities.len() * uniform_size,
instance_count: entities_count, wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::VERTEX,
}); );
let entity_count = same_mesh_entities.len();
for ((material, transform), slot) in same_mesh_entities
.drain(..)
.zip(temp_buf_data.data.chunks_exact_mut(uniform_size))
{
let (_, _, translation) = transform.0.to_scale_rotation_translation();
slot.copy_from_slice(
SimpleMaterialUniforms {
position: translation.into(),
color: material.color.into(),
}
.as_bytes(),
);
}
instance_buffer_infos.push(InstanceBufferInfo {
mesh_id: mesh_id,
buffer: temp_buf_data.finish(),
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);