use crate::component::CuboidInstancesBuffer;
use crate::draw_function::DrawCuboidInstances;
use crate::CuboidInstance;
use bevy::reflect::TypeUuid;
use bevy::{
core_pipeline::Transparent3d,
pbr::{MeshPipeline, MeshPipelineKey, MeshUniform},
prelude::*,
render::{
mesh::MeshVertexBufferLayout,
render_asset::RenderAssets,
render_phase::{DrawFunctions, RenderPhase},
render_resource::*,
view::{ExtractedView, Msaa},
},
};
pub(crate) const SHADER_HANDLE: HandleUntyped =
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 18213821065145195219);
pub(crate) struct CuboidInstancingPipeline {
shader: Handle<Shader>,
mesh_pipeline: MeshPipeline,
}
impl FromWorld for CuboidInstancingPipeline {
fn from_world(world: &mut World) -> Self {
let mesh_pipeline = world.get_resource::<MeshPipeline>().unwrap();
CuboidInstancingPipeline {
shader: SHADER_HANDLE.typed(),
mesh_pipeline: mesh_pipeline.clone(),
}
}
}
impl SpecializedMeshPipeline for CuboidInstancingPipeline {
type Key = MeshPipelineKey;
fn specialize(
&self,
key: Self::Key,
layout: &MeshVertexBufferLayout,
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
let mut descriptor = self.mesh_pipeline.specialize(key, layout)?;
descriptor.vertex.shader = self.shader.clone();
descriptor.vertex.buffers.push(VertexBufferLayout {
array_stride: std::mem::size_of::<CuboidInstance>() as u64,
step_mode: VertexStepMode::Instance,
attributes: CuboidInstance::VERTEX_ATTRIBUTES.to_vec(),
});
descriptor.fragment.as_mut().unwrap().shader = self.shader.clone();
descriptor.layout = Some(vec![
self.mesh_pipeline.view_layout.clone(),
self.mesh_pipeline.mesh_layout.clone(),
]);
Ok(descriptor)
}
}
pub(crate) fn queue_instances(
transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
custom_pipeline: Res<CuboidInstancingPipeline>,
msaa: Res<Msaa>,
mut pipelines: ResMut<SpecializedMeshPipelines<CuboidInstancingPipeline>>,
mut pipeline_cache: ResMut<PipelineCache>,
meshes: Res<RenderAssets<Mesh>>,
material_meshes: Query<
(Entity, &MeshUniform, &Handle<Mesh>),
(With<Handle<Mesh>>, With<CuboidInstancesBuffer>),
>,
mut views: Query<(&ExtractedView, &mut RenderPhase<Transparent3d>)>,
) {
let draw_custom = transparent_3d_draw_functions
.read()
.get_id::<DrawCuboidInstances>()
.unwrap();
let msaa_key = MeshPipelineKey::from_msaa_samples(msaa.samples);
for (view, mut transparent_phase) in views.iter_mut() {
let view_matrix = view.transform.compute_matrix();
let view_row_2 = view_matrix.row(2);
for (entity, mesh_uniform, mesh_handle) in material_meshes.iter() {
if let Some(mesh) = meshes.get(mesh_handle) {
let key =
msaa_key | MeshPipelineKey::from_primitive_topology(mesh.primitive_topology);
let pipeline = pipelines
.specialize(&mut pipeline_cache, &custom_pipeline, key, &mesh.layout)
.unwrap();
transparent_phase.add(Transparent3d {
entity,
pipeline,
draw_function: draw_custom,
distance: view_row_2.dot(mesh_uniform.transform.col(3)),
});
}
}
}
}