This commit is contained in:
IceSentry 2025-07-18 11:14:32 +02:00 committed by GitHub
commit a2ae48f30b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -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,
}