Merge dd98f5870b
into 877d278785
This commit is contained in:
commit
a2ae48f30b
@ -8,7 +8,7 @@
|
||||
|
||||
use bevy::{
|
||||
core_pipeline::core_3d::{Opaque3d, Opaque3dBatchSetKey, Opaque3dBinKey, CORE_3D_DEPTH_FORMAT},
|
||||
ecs::{component::Tick, system::StaticSystemParam},
|
||||
ecs::component::Tick,
|
||||
math::{vec3, vec4},
|
||||
pbr::{
|
||||
DrawMesh, MeshPipeline, MeshPipelineKey, MeshPipelineViewLayoutKey, RenderMeshInstances,
|
||||
@ -16,16 +16,12 @@ use bevy::{
|
||||
},
|
||||
prelude::*,
|
||||
render::{
|
||||
batching::{
|
||||
gpu_preprocessing::{
|
||||
self, PhaseBatchedInstanceBuffers, PhaseIndirectParametersBuffers,
|
||||
PreprocessWorkItem, UntypedPhaseBatchedInstanceBuffers,
|
||||
},
|
||||
GetBatchData, GetFullBatchData,
|
||||
},
|
||||
experimental::occlusion_culling::OcclusionCulling,
|
||||
batching::gpu_preprocessing::GpuPreprocessingSupport,
|
||||
extract_component::{ExtractComponent, ExtractComponentPlugin},
|
||||
mesh::{Indices, MeshVertexBufferLayoutRef, PrimitiveTopology, RenderMesh},
|
||||
mesh::{
|
||||
allocator::MeshAllocator, Indices, MeshVertexBufferLayoutRef, PrimitiveTopology,
|
||||
RenderMesh,
|
||||
},
|
||||
render_asset::{RenderAssetUsages, RenderAssets},
|
||||
render_phase::{
|
||||
AddRenderCommand, BinnedRenderPhaseType, DrawFunctions, SetItemPipeline,
|
||||
@ -37,7 +33,6 @@ use bevy::{
|
||||
RenderPipelineDescriptor, SpecializedMeshPipeline, SpecializedMeshPipelineError,
|
||||
SpecializedMeshPipelines, TextureFormat, VertexState,
|
||||
},
|
||||
view::NoIndirectDrawing,
|
||||
view::{self, ExtractedView, RenderVisibleEntities, ViewTarget, VisibilityClass},
|
||||
Render, RenderApp, RenderStartup, RenderSystems,
|
||||
},
|
||||
@ -262,7 +257,6 @@ impl SpecializedMeshPipeline for CustomMeshPipeline {
|
||||
count: mesh_key.msaa_samples(),
|
||||
..default()
|
||||
},
|
||||
|
||||
..default()
|
||||
})
|
||||
}
|
||||
@ -278,75 +272,32 @@ fn queue_custom_mesh_pipeline(
|
||||
Res<DrawFunctions<Opaque3d>>,
|
||||
),
|
||||
mut specialized_mesh_pipelines: ResMut<SpecializedMeshPipelines<CustomMeshPipeline>>,
|
||||
views: Query<(
|
||||
&RenderVisibleEntities,
|
||||
&ExtractedView,
|
||||
&Msaa,
|
||||
Has<NoIndirectDrawing>,
|
||||
Has<OcclusionCulling>,
|
||||
)>,
|
||||
views: Query<(&RenderVisibleEntities, &ExtractedView, &Msaa)>,
|
||||
(render_meshes, render_mesh_instances): (
|
||||
Res<RenderAssets<RenderMesh>>,
|
||||
Res<RenderMeshInstances>,
|
||||
),
|
||||
param: StaticSystemParam<<MeshPipeline as GetBatchData>::Param>,
|
||||
mut phase_batched_instance_buffers: ResMut<
|
||||
PhaseBatchedInstanceBuffers<Opaque3d, <MeshPipeline as GetBatchData>::BufferData>,
|
||||
>,
|
||||
mut phase_indirect_parameters_buffers: ResMut<PhaseIndirectParametersBuffers<Opaque3d>>,
|
||||
mut change_tick: Local<Tick>,
|
||||
mesh_allocator: Res<MeshAllocator>,
|
||||
gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
|
||||
) {
|
||||
let system_param_item = param.into_inner();
|
||||
|
||||
let UntypedPhaseBatchedInstanceBuffers {
|
||||
ref mut data_buffer,
|
||||
ref mut work_item_buffers,
|
||||
ref mut late_indexed_indirect_parameters_buffer,
|
||||
ref mut late_non_indexed_indirect_parameters_buffer,
|
||||
..
|
||||
} = phase_batched_instance_buffers.buffers;
|
||||
|
||||
// Get the id for our custom draw function
|
||||
let draw_function_id = opaque_draw_functions
|
||||
let draw_function = opaque_draw_functions
|
||||
.read()
|
||||
.id::<DrawSpecializedPipelineCommands>();
|
||||
|
||||
// Render phases are per-view, so we need to iterate over all views so that
|
||||
// the entity appears in them. (In this example, we have only one view, but
|
||||
// it's good practice to loop over all views anyway.)
|
||||
for (view_visible_entities, view, msaa, no_indirect_drawing, gpu_occlusion_culling) in
|
||||
views.iter()
|
||||
{
|
||||
for (view_visible_entities, view, msaa) in views.iter() {
|
||||
let Some(opaque_phase) = opaque_render_phases.get_mut(&view.retained_view_entity) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Create *work item buffers* if necessary. Work item buffers store the
|
||||
// indices of meshes that are to be rendered when indirect drawing is
|
||||
// enabled.
|
||||
let work_item_buffer = gpu_preprocessing::get_or_create_work_item_buffer::<Opaque3d>(
|
||||
work_item_buffers,
|
||||
view.retained_view_entity,
|
||||
no_indirect_drawing,
|
||||
gpu_occlusion_culling,
|
||||
);
|
||||
|
||||
// Initialize those work item buffers in preparation for this new frame.
|
||||
gpu_preprocessing::init_work_item_buffers(
|
||||
work_item_buffer,
|
||||
late_indexed_indirect_parameters_buffer,
|
||||
late_non_indexed_indirect_parameters_buffer,
|
||||
);
|
||||
|
||||
// Create the key based on the view. In this case we only care about MSAA and HDR
|
||||
let view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())
|
||||
| MeshPipelineKey::from_hdr(view.hdr);
|
||||
|
||||
// Set up a slot to hold information about the batch set we're going to
|
||||
// create. If there are any of our custom meshes in the scene, we'll
|
||||
// need this information in order for Bevy to kick off the rendering.
|
||||
let mut mesh_batch_set_info = None;
|
||||
|
||||
// Find all the custom rendered entities that are visible from this
|
||||
// view.
|
||||
for &(render_entity, visible_entity) in
|
||||
@ -363,34 +314,14 @@ fn queue_custom_mesh_pipeline(
|
||||
continue;
|
||||
};
|
||||
|
||||
let (vertex_slab, index_slab) = mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id);
|
||||
|
||||
// Specialize the key for the current mesh entity
|
||||
// For this example we only specialize based on the mesh topology
|
||||
// but you could have more complex keys and that's where you'd need to create those keys
|
||||
let mut mesh_key = view_key;
|
||||
mesh_key |= MeshPipelineKey::from_primitive_topology(mesh.primitive_topology());
|
||||
|
||||
// Initialize the batch set information if this was the first custom
|
||||
// mesh we saw. We'll need that information later to create the
|
||||
// batch set.
|
||||
if mesh_batch_set_info.is_none() {
|
||||
mesh_batch_set_info = Some(MeshBatchSetInfo {
|
||||
indirect_parameters_index: phase_indirect_parameters_buffers
|
||||
.buffers
|
||||
.allocate(mesh.indexed(), 1),
|
||||
is_indexed: mesh.indexed(),
|
||||
});
|
||||
}
|
||||
let mesh_info = mesh_batch_set_info.unwrap();
|
||||
|
||||
// Allocate some input and output indices. We'll need these to
|
||||
// create the *work item* below.
|
||||
let Some(input_index) =
|
||||
MeshPipeline::get_binned_index(&system_param_item, visible_entity)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let output_index = data_buffer.add() as u32;
|
||||
|
||||
// Finally, we can specialize the pipeline based on the key
|
||||
let pipeline_id = specialized_mesh_pipelines
|
||||
.specialize(
|
||||
@ -399,8 +330,8 @@ fn queue_custom_mesh_pipeline(
|
||||
mesh_key,
|
||||
&mesh.layout,
|
||||
)
|
||||
// This should never with this example, but if your pipeline specialization
|
||||
// can fail you need to handle the error here
|
||||
// This should never happen with this example, but if your pipeline
|
||||
// specialization can fail you need to handle the error here
|
||||
.expect("Failed to specialize mesh pipeline");
|
||||
|
||||
// Bump the change tick so that Bevy is forced to rebuild the bin.
|
||||
@ -410,59 +341,29 @@ fn queue_custom_mesh_pipeline(
|
||||
// Add the mesh with our specialized pipeline
|
||||
opaque_phase.add(
|
||||
Opaque3dBatchSetKey {
|
||||
draw_function: draw_function_id,
|
||||
draw_function,
|
||||
pipeline: pipeline_id,
|
||||
material_bind_group_index: None,
|
||||
vertex_slab: default(),
|
||||
index_slab: None,
|
||||
vertex_slab: vertex_slab.unwrap_or_default(),
|
||||
index_slab,
|
||||
lightmap_slab: None,
|
||||
},
|
||||
// The asset ID is arbitrary; we simply use [`AssetId::invalid`],
|
||||
// but you can use anything you like. Note that the asset ID need
|
||||
// not be the ID of a [`Mesh`].
|
||||
// For this example we can use the mesh asset id as the bin key,
|
||||
// but you can use any asset_id as a key
|
||||
Opaque3dBinKey {
|
||||
asset_id: AssetId::<Mesh>::invalid().untyped(),
|
||||
asset_id: mesh_instance.mesh_asset_id.into(),
|
||||
},
|
||||
(render_entity, visible_entity),
|
||||
mesh_instance.current_uniform_index,
|
||||
// This example supports batching, but if your pipeline doesn't
|
||||
// support it you can use `BinnedRenderPhaseType::UnbatchableMesh`
|
||||
BinnedRenderPhaseType::BatchableMesh,
|
||||
// This example supports batching and multi draw indirect,
|
||||
// but if your pipeline doesn't support it you can use
|
||||
// `BinnedRenderPhaseType::UnbatchableMesh`
|
||||
BinnedRenderPhaseType::mesh(
|
||||
mesh_instance.should_batch(),
|
||||
&gpu_preprocessing_support,
|
||||
),
|
||||
*change_tick,
|
||||
);
|
||||
|
||||
// Create a *work item*. A work item tells the Bevy renderer to
|
||||
// transform the mesh on GPU.
|
||||
work_item_buffer.push(
|
||||
mesh.indexed(),
|
||||
PreprocessWorkItem {
|
||||
input_index: input_index.into(),
|
||||
output_or_indirect_parameters_index: if no_indirect_drawing {
|
||||
output_index
|
||||
} else {
|
||||
mesh_info.indirect_parameters_index
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Now if there were any meshes, we need to add a command to the
|
||||
// indirect parameters buffer, so that the renderer will end up
|
||||
// enqueuing a command to draw the mesh.
|
||||
if let Some(mesh_info) = mesh_batch_set_info {
|
||||
phase_indirect_parameters_buffers
|
||||
.buffers
|
||||
.add_batch_set(mesh_info.is_indexed, mesh_info.indirect_parameters_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we end up having any custom meshes to draw, this contains information
|
||||
// needed to create the batch set.
|
||||
#[derive(Clone, Copy)]
|
||||
struct MeshBatchSetInfo {
|
||||
/// The first index of the mesh batch in the indirect parameters buffer.
|
||||
indirect_parameters_index: u32,
|
||||
/// Whether the mesh is indexed (has an index buffer).
|
||||
is_indexed: bool,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user