1mod prepass_bindings;
2
3use crate::{
4 alpha_mode_pipeline_key, binding_arrays_are_usable, buffer_layout,
5 collect_meshes_for_gpu_building, init_material_pipeline, set_mesh_motion_vector_flags,
6 setup_morph_and_skinning_defs, skin, DeferredDrawFunction, DeferredFragmentShader,
7 DeferredVertexShader, DrawMesh, EntitySpecializationTicks, ErasedMaterialPipelineKey, Material,
8 MaterialPipeline, MaterialProperties, MeshLayouts, MeshPipeline, MeshPipelineKey,
9 OpaqueRendererMethod, PreparedMaterial, PrepassDrawFunction, PrepassFragmentShader,
10 PrepassVertexShader, RenderLightmaps, RenderMaterialInstances, RenderMeshInstanceFlags,
11 RenderMeshInstances, RenderPhaseType, SetMaterialBindGroup, SetMeshBindGroup, ShadowView,
12};
13use bevy_app::{App, Plugin, PreUpdate};
14use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
15use bevy_camera::{Camera, Camera3d};
16use bevy_core_pipeline::{core_3d::CORE_3D_DEPTH_FORMAT, deferred::*, prepass::*};
17use bevy_ecs::{
18 prelude::*,
19 system::{
20 lifetimeless::{Read, SRes},
21 SystemParamItem,
22 },
23};
24use bevy_math::{Affine3A, Mat4, Vec4};
25use bevy_mesh::{Mesh, Mesh3d, MeshVertexBufferLayoutRef};
26use bevy_render::{
27 alpha::AlphaMode,
28 batching::gpu_preprocessing::GpuPreprocessingSupport,
29 globals::{GlobalsBuffer, GlobalsUniform},
30 mesh::{allocator::MeshAllocator, RenderMesh},
31 render_asset::{prepare_assets, RenderAssets},
32 render_phase::*,
33 render_resource::{binding_types::uniform_buffer, *},
34 renderer::{RenderAdapter, RenderDevice, RenderQueue},
35 sync_world::RenderEntity,
36 view::{
37 ExtractedView, Msaa, RenderVisibilityRanges, RetainedViewEntity, ViewUniform,
38 ViewUniformOffset, ViewUniforms, VISIBILITY_RANGES_STORAGE_BUFFER_COUNT,
39 },
40 Extract, ExtractSchedule, Render, RenderApp, RenderDebugFlags, RenderStartup, RenderSystems,
41};
42use bevy_shader::{load_shader_library, Shader, ShaderDefVal};
43use bevy_transform::prelude::GlobalTransform;
44pub use prepass_bindings::*;
45use tracing::{error, warn};
46
47#[cfg(feature = "meshlet")]
48use crate::meshlet::{
49 prepare_material_meshlet_meshes_prepass, queue_material_meshlet_meshes, InstanceManager,
50 MeshletMesh3d,
51};
52
53use alloc::sync::Arc;
54use bevy_derive::{Deref, DerefMut};
55use bevy_ecs::{component::Tick, system::SystemChangeTick};
56use bevy_platform::collections::HashMap;
57use bevy_render::{
58 erased_render_asset::ErasedRenderAssets,
59 sync_world::MainEntityHashMap,
60 view::RenderVisibleEntities,
61 RenderSystems::{PrepareAssets, PrepareResources},
62};
63use bevy_utils::default;
64use core::marker::PhantomData;
65
66pub struct PrepassPipelinePlugin;
70
71impl Plugin for PrepassPipelinePlugin {
72 fn build(&self, app: &mut App) {
73 embedded_asset!(app, "prepass.wgsl");
74
75 load_shader_library!(app, "prepass_bindings.wgsl");
76 load_shader_library!(app, "prepass_utils.wgsl");
77 load_shader_library!(app, "prepass_io.wgsl");
78
79 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
80 return;
81 };
82
83 render_app
84 .add_systems(
85 RenderStartup,
86 (
87 init_prepass_pipeline.after(init_material_pipeline),
88 init_prepass_view_bind_group,
89 )
90 .chain(),
91 )
92 .add_systems(
93 Render,
94 prepare_prepass_view_bind_group.in_set(RenderSystems::PrepareBindGroups),
95 )
96 .init_resource::<SpecializedMeshPipelines<PrepassPipelineSpecializer>>();
97 }
98}
99
100pub struct PrepassPlugin {
104 pub debug_flags: RenderDebugFlags,
106}
107
108impl PrepassPlugin {
109 pub fn new(debug_flags: RenderDebugFlags) -> Self {
111 PrepassPlugin { debug_flags }
112 }
113}
114
115impl Plugin for PrepassPlugin {
116 fn build(&self, app: &mut App) {
117 let no_prepass_plugin_loaded = app
118 .world()
119 .get_resource::<AnyPrepassPluginLoaded>()
120 .is_none();
121
122 if no_prepass_plugin_loaded {
123 app.insert_resource(AnyPrepassPluginLoaded)
124 .add_systems(
127 PreUpdate,
128 (
129 update_mesh_previous_global_transforms,
130 update_previous_view_data,
131 ),
132 )
133 .add_plugins((
134 BinnedRenderPhasePlugin::<Opaque3dPrepass, MeshPipeline>::new(self.debug_flags),
135 BinnedRenderPhasePlugin::<AlphaMask3dPrepass, MeshPipeline>::new(
136 self.debug_flags,
137 ),
138 ));
139 }
140
141 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
142 return;
143 };
144
145 if no_prepass_plugin_loaded {
146 render_app
147 .add_systems(ExtractSchedule, extract_camera_previous_view_data)
148 .add_systems(
149 Render,
150 prepare_previous_view_uniforms.in_set(PrepareResources),
151 );
152 }
153
154 render_app
155 .init_resource::<ViewPrepassSpecializationTicks>()
156 .init_resource::<ViewKeyPrepassCache>()
157 .init_resource::<SpecializedPrepassMaterialPipelineCache>()
158 .add_render_command::<Opaque3dPrepass, DrawPrepass>()
159 .add_render_command::<AlphaMask3dPrepass, DrawPrepass>()
160 .add_render_command::<Opaque3dDeferred, DrawPrepass>()
161 .add_render_command::<AlphaMask3dDeferred, DrawPrepass>()
162 .add_systems(
163 Render,
164 (
165 check_prepass_views_need_specialization.in_set(PrepareAssets),
166 specialize_prepass_material_meshes
167 .in_set(RenderSystems::PrepareMeshes)
168 .after(prepare_assets::<RenderMesh>)
169 .after(collect_meshes_for_gpu_building)
170 .after(set_mesh_motion_vector_flags),
171 queue_prepass_material_meshes.in_set(RenderSystems::QueueMeshes),
172 ),
173 );
174
175 #[cfg(feature = "meshlet")]
176 render_app.add_systems(
177 Render,
178 prepare_material_meshlet_meshes_prepass
179 .in_set(RenderSystems::QueueMeshes)
180 .before(queue_material_meshlet_meshes)
181 .run_if(resource_exists::<InstanceManager>),
182 );
183 }
184}
185
186#[derive(Resource, Debug)]
188pub struct PrepassEnabled<M: Material>(PhantomData<M>);
189
190impl<M: Material> Default for PrepassEnabled<M> {
191 fn default() -> Self {
192 PrepassEnabled(PhantomData)
193 }
194}
195
196#[derive(Resource)]
197struct AnyPrepassPluginLoaded;
198
199pub fn update_previous_view_data(
200 mut commands: Commands,
201 query: Query<(Entity, &Camera, &GlobalTransform), Or<(With<Camera3d>, With<ShadowView>)>>,
202) {
203 for (entity, camera, camera_transform) in &query {
204 let world_from_view = camera_transform.affine();
205 let view_from_world = Mat4::from(world_from_view.inverse());
206 let view_from_clip = camera.clip_from_view().inverse();
207
208 commands.entity(entity).try_insert(PreviousViewData {
209 view_from_world,
210 clip_from_world: camera.clip_from_view() * view_from_world,
211 clip_from_view: camera.clip_from_view(),
212 world_from_clip: Mat4::from(world_from_view) * view_from_clip,
213 view_from_clip,
214 });
215 }
216}
217
218#[derive(Component, PartialEq, Default)]
219pub struct PreviousGlobalTransform(pub Affine3A);
220
221#[cfg(not(feature = "meshlet"))]
222type PreviousMeshFilter = With<Mesh3d>;
223#[cfg(feature = "meshlet")]
224type PreviousMeshFilter = Or<(With<Mesh3d>, With<MeshletMesh3d>)>;
225
226pub fn update_mesh_previous_global_transforms(
227 mut commands: Commands,
228 views: Query<&Camera, Or<(With<Camera3d>, With<ShadowView>)>>,
229 new_meshes: Query<
230 (Entity, &GlobalTransform),
231 (PreviousMeshFilter, Without<PreviousGlobalTransform>),
232 >,
233 mut meshes: Query<(&GlobalTransform, &mut PreviousGlobalTransform), PreviousMeshFilter>,
234) {
235 let should_run = views.iter().any(|camera| camera.is_active);
236
237 if should_run {
238 for (entity, transform) in &new_meshes {
239 let new_previous_transform = PreviousGlobalTransform(transform.affine());
240 commands.entity(entity).try_insert(new_previous_transform);
241 }
242 meshes.par_iter_mut().for_each(|(transform, mut previous)| {
243 previous.set_if_neq(PreviousGlobalTransform(transform.affine()));
244 });
245 }
246}
247
248#[derive(Resource, Clone)]
249pub struct PrepassPipeline {
250 pub view_layout_motion_vectors: BindGroupLayout,
251 pub view_layout_no_motion_vectors: BindGroupLayout,
252 pub mesh_layouts: MeshLayouts,
253 pub empty_layout: BindGroupLayout,
254 pub default_prepass_shader: Handle<Shader>,
255
256 pub skins_use_uniform_buffers: bool,
259
260 pub depth_clip_control_supported: bool,
261
262 pub binding_arrays_are_usable: bool,
265 pub material_pipeline: MaterialPipeline,
266}
267
268pub fn init_prepass_pipeline(
269 mut commands: Commands,
270 render_device: Res<RenderDevice>,
271 render_adapter: Res<RenderAdapter>,
272 mesh_pipeline: Res<MeshPipeline>,
273 material_pipeline: Res<MaterialPipeline>,
274 asset_server: Res<AssetServer>,
275) {
276 let visibility_ranges_buffer_binding_type =
277 render_device.get_supported_read_only_binding_type(VISIBILITY_RANGES_STORAGE_BUFFER_COUNT);
278
279 let view_layout_motion_vectors = render_device.create_bind_group_layout(
280 "prepass_view_layout_motion_vectors",
281 &BindGroupLayoutEntries::with_indices(
282 ShaderStages::VERTEX_FRAGMENT,
283 (
284 (0, uniform_buffer::<ViewUniform>(true)),
286 (1, uniform_buffer::<GlobalsUniform>(false)),
288 (2, uniform_buffer::<PreviousViewData>(true)),
290 (
292 14,
293 buffer_layout(
294 visibility_ranges_buffer_binding_type,
295 false,
296 Some(Vec4::min_size()),
297 )
298 .visibility(ShaderStages::VERTEX),
299 ),
300 ),
301 ),
302 );
303
304 let view_layout_no_motion_vectors = render_device.create_bind_group_layout(
305 "prepass_view_layout_no_motion_vectors",
306 &BindGroupLayoutEntries::with_indices(
307 ShaderStages::VERTEX_FRAGMENT,
308 (
309 (0, uniform_buffer::<ViewUniform>(true)),
311 (1, uniform_buffer::<GlobalsUniform>(false)),
313 (
315 14,
316 buffer_layout(
317 visibility_ranges_buffer_binding_type,
318 false,
319 Some(Vec4::min_size()),
320 )
321 .visibility(ShaderStages::VERTEX),
322 ),
323 ),
324 ),
325 );
326
327 let depth_clip_control_supported = render_device
328 .features()
329 .contains(WgpuFeatures::DEPTH_CLIP_CONTROL);
330 commands.insert_resource(PrepassPipeline {
331 view_layout_motion_vectors,
332 view_layout_no_motion_vectors,
333 mesh_layouts: mesh_pipeline.mesh_layouts.clone(),
334 default_prepass_shader: load_embedded_asset!(asset_server.as_ref(), "prepass.wgsl"),
335 skins_use_uniform_buffers: skin::skins_use_uniform_buffers(&render_device),
336 depth_clip_control_supported,
337 binding_arrays_are_usable: binding_arrays_are_usable(&render_device, &render_adapter),
338 empty_layout: render_device.create_bind_group_layout("prepass_empty_layout", &[]),
339 material_pipeline: material_pipeline.clone(),
340 });
341}
342
343pub struct PrepassPipelineSpecializer {
344 pub(crate) pipeline: PrepassPipeline,
345 pub(crate) properties: Arc<MaterialProperties>,
346}
347
348impl SpecializedMeshPipeline for PrepassPipelineSpecializer {
349 type Key = ErasedMaterialPipelineKey;
350
351 fn specialize(
352 &self,
353 key: Self::Key,
354 layout: &MeshVertexBufferLayoutRef,
355 ) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
356 let mut shader_defs = Vec::new();
357 if self.properties.bindless {
358 shader_defs.push("BINDLESS".into());
359 }
360 let mut descriptor =
361 self.pipeline
362 .specialize(key.mesh_key, shader_defs, layout, &self.properties)?;
363
364 if let Some(specialize) = self.properties.specialize {
368 specialize(
369 &self.pipeline.material_pipeline,
370 &mut descriptor,
371 layout,
372 key,
373 )?;
374 }
375
376 Ok(descriptor)
377 }
378}
379
380impl PrepassPipeline {
381 fn specialize(
382 &self,
383 mesh_key: MeshPipelineKey,
384 shader_defs: Vec<ShaderDefVal>,
385 layout: &MeshVertexBufferLayoutRef,
386 material_properties: &MaterialProperties,
387 ) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
388 let mut shader_defs = shader_defs;
389 let mut bind_group_layouts = vec![
390 if mesh_key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {
391 self.view_layout_motion_vectors.clone()
392 } else {
393 self.view_layout_no_motion_vectors.clone()
394 },
395 self.empty_layout.clone(),
396 ];
397 let mut vertex_attributes = Vec::new();
398
399 shader_defs.push("PREPASS_PIPELINE".into());
403
404 shader_defs.push(ShaderDefVal::UInt(
405 "MATERIAL_BIND_GROUP".into(),
406 crate::MATERIAL_BIND_GROUP_INDEX as u32,
407 ));
408 bind_group_layouts.push(
411 material_properties
412 .material_layout
413 .as_ref()
414 .unwrap()
415 .clone(),
416 );
417 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
418 shader_defs.push("WEBGL2".into());
419 shader_defs.push("VERTEX_OUTPUT_INSTANCE_INDEX".into());
420 if mesh_key.contains(MeshPipelineKey::DEPTH_PREPASS) {
421 shader_defs.push("DEPTH_PREPASS".into());
422 }
423 if mesh_key.contains(MeshPipelineKey::MAY_DISCARD) {
424 shader_defs.push("MAY_DISCARD".into());
425 }
426 let blend_key = mesh_key.intersection(MeshPipelineKey::BLEND_RESERVED_BITS);
427 if blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA {
428 shader_defs.push("BLEND_PREMULTIPLIED_ALPHA".into());
429 }
430 if blend_key == MeshPipelineKey::BLEND_ALPHA {
431 shader_defs.push("BLEND_ALPHA".into());
432 }
433 if layout.0.contains(Mesh::ATTRIBUTE_POSITION) {
434 shader_defs.push("VERTEX_POSITIONS".into());
435 vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
436 }
437 let emulate_unclipped_depth = mesh_key.contains(MeshPipelineKey::UNCLIPPED_DEPTH_ORTHO)
440 && !self.depth_clip_control_supported;
441 if emulate_unclipped_depth {
442 shader_defs.push("UNCLIPPED_DEPTH_ORTHO_EMULATION".into());
443 shader_defs.push("PREPASS_FRAGMENT".into());
450 }
451 let unclipped_depth = mesh_key.contains(MeshPipelineKey::UNCLIPPED_DEPTH_ORTHO)
452 && self.depth_clip_control_supported;
453 if layout.0.contains(Mesh::ATTRIBUTE_UV_0) {
454 shader_defs.push("VERTEX_UVS".into());
455 shader_defs.push("VERTEX_UVS_A".into());
456 vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(1));
457 }
458 if layout.0.contains(Mesh::ATTRIBUTE_UV_1) {
459 shader_defs.push("VERTEX_UVS".into());
460 shader_defs.push("VERTEX_UVS_B".into());
461 vertex_attributes.push(Mesh::ATTRIBUTE_UV_1.at_shader_location(2));
462 }
463 if mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS) {
464 shader_defs.push("NORMAL_PREPASS".into());
465 }
466 if mesh_key.intersects(MeshPipelineKey::NORMAL_PREPASS | MeshPipelineKey::DEFERRED_PREPASS)
467 {
468 shader_defs.push("NORMAL_PREPASS_OR_DEFERRED_PREPASS".into());
469 if layout.0.contains(Mesh::ATTRIBUTE_NORMAL) {
470 shader_defs.push("VERTEX_NORMALS".into());
471 vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(3));
472 } else if mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS) {
473 warn!(
474 "The default normal prepass expects the mesh to have vertex normal attributes."
475 );
476 }
477 if layout.0.contains(Mesh::ATTRIBUTE_TANGENT) {
478 shader_defs.push("VERTEX_TANGENTS".into());
479 vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(4));
480 }
481 }
482 if mesh_key
483 .intersects(MeshPipelineKey::MOTION_VECTOR_PREPASS | MeshPipelineKey::DEFERRED_PREPASS)
484 {
485 shader_defs.push("MOTION_VECTOR_PREPASS_OR_DEFERRED_PREPASS".into());
486 }
487 if mesh_key.contains(MeshPipelineKey::DEFERRED_PREPASS) {
488 shader_defs.push("DEFERRED_PREPASS".into());
489 }
490 if mesh_key.contains(MeshPipelineKey::LIGHTMAPPED) {
491 shader_defs.push("LIGHTMAP".into());
492 }
493 if mesh_key.contains(MeshPipelineKey::LIGHTMAP_BICUBIC_SAMPLING) {
494 shader_defs.push("LIGHTMAP_BICUBIC_SAMPLING".into());
495 }
496 if layout.0.contains(Mesh::ATTRIBUTE_COLOR) {
497 shader_defs.push("VERTEX_COLORS".into());
498 vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(7));
499 }
500 if mesh_key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {
501 shader_defs.push("MOTION_VECTOR_PREPASS".into());
502 }
503 if mesh_key.contains(MeshPipelineKey::HAS_PREVIOUS_SKIN) {
504 shader_defs.push("HAS_PREVIOUS_SKIN".into());
505 }
506 if mesh_key.contains(MeshPipelineKey::HAS_PREVIOUS_MORPH) {
507 shader_defs.push("HAS_PREVIOUS_MORPH".into());
508 }
509 if self.binding_arrays_are_usable {
510 shader_defs.push("MULTIPLE_LIGHTMAPS_IN_ARRAY".into());
511 }
512 if mesh_key.contains(MeshPipelineKey::VISIBILITY_RANGE_DITHER) {
513 shader_defs.push("VISIBILITY_RANGE_DITHER".into());
514 }
515 if mesh_key.intersects(
516 MeshPipelineKey::NORMAL_PREPASS
517 | MeshPipelineKey::MOTION_VECTOR_PREPASS
518 | MeshPipelineKey::DEFERRED_PREPASS,
519 ) {
520 shader_defs.push("PREPASS_FRAGMENT".into());
521 }
522 let bind_group = setup_morph_and_skinning_defs(
523 &self.mesh_layouts,
524 layout,
525 5,
526 &mesh_key,
527 &mut shader_defs,
528 &mut vertex_attributes,
529 self.skins_use_uniform_buffers,
530 );
531 bind_group_layouts.insert(2, bind_group);
532 let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?;
533 let mut targets = prepass_target_descriptors(
535 mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS),
536 mesh_key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS),
537 mesh_key.contains(MeshPipelineKey::DEFERRED_PREPASS),
538 );
539
540 if targets.iter().all(Option::is_none) {
541 targets.clear();
544 }
545
546 let fragment_required = !targets.is_empty()
550 || emulate_unclipped_depth
551 || (mesh_key.contains(MeshPipelineKey::MAY_DISCARD)
552 && material_properties
553 .get_shader(PrepassFragmentShader)
554 .is_some());
555
556 let fragment = fragment_required.then(|| {
557 let frag_shader_handle = if mesh_key.contains(MeshPipelineKey::DEFERRED_PREPASS) {
559 match material_properties.get_shader(DeferredFragmentShader) {
560 Some(frag_shader_handle) => frag_shader_handle,
561 None => self.default_prepass_shader.clone(),
562 }
563 } else {
564 match material_properties.get_shader(PrepassFragmentShader) {
565 Some(frag_shader_handle) => frag_shader_handle,
566 None => self.default_prepass_shader.clone(),
567 }
568 };
569
570 FragmentState {
571 shader: frag_shader_handle,
572 shader_defs: shader_defs.clone(),
573 targets,
574 ..default()
575 }
576 });
577
578 let vert_shader_handle = if mesh_key.contains(MeshPipelineKey::DEFERRED_PREPASS) {
580 if let Some(handle) = material_properties.get_shader(DeferredVertexShader) {
581 handle
582 } else {
583 self.default_prepass_shader.clone()
584 }
585 } else if let Some(handle) = material_properties.get_shader(PrepassVertexShader) {
586 handle
587 } else {
588 self.default_prepass_shader.clone()
589 };
590 let descriptor = RenderPipelineDescriptor {
591 vertex: VertexState {
592 shader: vert_shader_handle,
593 shader_defs,
594 buffers: vec![vertex_buffer_layout],
595 ..default()
596 },
597 fragment,
598 layout: bind_group_layouts,
599 primitive: PrimitiveState {
600 topology: mesh_key.primitive_topology(),
601 unclipped_depth,
602 ..default()
603 },
604 depth_stencil: Some(DepthStencilState {
605 format: CORE_3D_DEPTH_FORMAT,
606 depth_write_enabled: true,
607 depth_compare: CompareFunction::GreaterEqual,
608 stencil: StencilState {
609 front: StencilFaceState::IGNORE,
610 back: StencilFaceState::IGNORE,
611 read_mask: 0,
612 write_mask: 0,
613 },
614 bias: DepthBiasState {
615 constant: 0,
616 slope_scale: 0.0,
617 clamp: 0.0,
618 },
619 }),
620 multisample: MultisampleState {
621 count: mesh_key.msaa_samples(),
622 mask: !0,
623 alpha_to_coverage_enabled: false,
624 },
625 label: Some("prepass_pipeline".into()),
626 ..default()
627 };
628 Ok(descriptor)
629 }
630}
631
632pub fn extract_camera_previous_view_data(
634 mut commands: Commands,
635 cameras_3d: Extract<Query<(RenderEntity, &Camera, Option<&PreviousViewData>), With<Camera3d>>>,
636) {
637 for (entity, camera, maybe_previous_view_data) in cameras_3d.iter() {
638 let mut entity = commands
639 .get_entity(entity)
640 .expect("Camera entity wasn't synced.");
641 if camera.is_active {
642 if let Some(previous_view_data) = maybe_previous_view_data {
643 entity.insert(previous_view_data.clone());
644 }
645 } else {
646 entity.remove::<PreviousViewData>();
647 }
648 }
649}
650
651pub fn prepare_previous_view_uniforms(
652 mut commands: Commands,
653 render_device: Res<RenderDevice>,
654 render_queue: Res<RenderQueue>,
655 mut previous_view_uniforms: ResMut<PreviousViewUniforms>,
656 views: Query<
657 (Entity, &ExtractedView, Option<&PreviousViewData>),
658 Or<(With<Camera3d>, With<ShadowView>)>,
659 >,
660) {
661 let views_iter = views.iter();
662 let view_count = views_iter.len();
663 let Some(mut writer) =
664 previous_view_uniforms
665 .uniforms
666 .get_writer(view_count, &render_device, &render_queue)
667 else {
668 return;
669 };
670
671 for (entity, camera, maybe_previous_view_uniforms) in views_iter {
672 let prev_view_data = match maybe_previous_view_uniforms {
673 Some(previous_view) => previous_view.clone(),
674 None => {
675 let world_from_view = camera.world_from_view.affine();
676 let view_from_world = Mat4::from(world_from_view.inverse());
677 let view_from_clip = camera.clip_from_view.inverse();
678
679 PreviousViewData {
680 view_from_world,
681 clip_from_world: camera.clip_from_view * view_from_world,
682 clip_from_view: camera.clip_from_view,
683 world_from_clip: Mat4::from(world_from_view) * view_from_clip,
684 view_from_clip,
685 }
686 }
687 };
688
689 commands.entity(entity).insert(PreviousViewUniformOffset {
690 offset: writer.write(&prev_view_data),
691 });
692 }
693}
694
695#[derive(Resource)]
696pub struct PrepassViewBindGroup {
697 pub motion_vectors: Option<BindGroup>,
698 pub no_motion_vectors: Option<BindGroup>,
699 pub empty_bind_group: BindGroup,
700}
701
702pub fn init_prepass_view_bind_group(
703 mut commands: Commands,
704 render_device: Res<RenderDevice>,
705 pipeline: Res<PrepassPipeline>,
706) {
707 let empty_bind_group = render_device.create_bind_group(
708 "prepass_view_empty_bind_group",
709 &pipeline.empty_layout,
710 &[],
711 );
712 commands.insert_resource(PrepassViewBindGroup {
713 motion_vectors: None,
714 no_motion_vectors: None,
715 empty_bind_group,
716 });
717}
718
719pub fn prepare_prepass_view_bind_group(
720 render_device: Res<RenderDevice>,
721 prepass_pipeline: Res<PrepassPipeline>,
722 view_uniforms: Res<ViewUniforms>,
723 globals_buffer: Res<GlobalsBuffer>,
724 previous_view_uniforms: Res<PreviousViewUniforms>,
725 visibility_ranges: Res<RenderVisibilityRanges>,
726 mut prepass_view_bind_group: ResMut<PrepassViewBindGroup>,
727) {
728 if let (Some(view_binding), Some(globals_binding), Some(visibility_ranges_buffer)) = (
729 view_uniforms.uniforms.binding(),
730 globals_buffer.buffer.binding(),
731 visibility_ranges.buffer().buffer(),
732 ) {
733 prepass_view_bind_group.no_motion_vectors = Some(render_device.create_bind_group(
734 "prepass_view_no_motion_vectors_bind_group",
735 &prepass_pipeline.view_layout_no_motion_vectors,
736 &BindGroupEntries::with_indices((
737 (0, view_binding.clone()),
738 (1, globals_binding.clone()),
739 (14, visibility_ranges_buffer.as_entire_binding()),
740 )),
741 ));
742
743 if let Some(previous_view_uniforms_binding) = previous_view_uniforms.uniforms.binding() {
744 prepass_view_bind_group.motion_vectors = Some(render_device.create_bind_group(
745 "prepass_view_motion_vectors_bind_group",
746 &prepass_pipeline.view_layout_motion_vectors,
747 &BindGroupEntries::with_indices((
748 (0, view_binding),
749 (1, globals_binding),
750 (2, previous_view_uniforms_binding),
751 (14, visibility_ranges_buffer.as_entire_binding()),
752 )),
753 ));
754 }
755 }
756}
757
758#[derive(Resource, Deref, DerefMut, Default)]
760pub struct SpecializedPrepassMaterialPipelineCache {
761 #[deref]
763 map: HashMap<RetainedViewEntity, SpecializedPrepassMaterialViewPipelineCache>,
764}
765
766#[derive(Deref, DerefMut, Default)]
769pub struct SpecializedPrepassMaterialViewPipelineCache {
770 #[deref]
772 map: MainEntityHashMap<(Tick, CachedRenderPipelineId)>,
773}
774
775#[derive(Resource, Deref, DerefMut, Default, Clone)]
776pub struct ViewKeyPrepassCache(HashMap<RetainedViewEntity, MeshPipelineKey>);
777
778#[derive(Resource, Deref, DerefMut, Default, Clone)]
779pub struct ViewPrepassSpecializationTicks(HashMap<RetainedViewEntity, Tick>);
780
781pub fn check_prepass_views_need_specialization(
782 mut view_key_cache: ResMut<ViewKeyPrepassCache>,
783 mut view_specialization_ticks: ResMut<ViewPrepassSpecializationTicks>,
784 mut views: Query<(
785 &ExtractedView,
786 &Msaa,
787 Option<&DepthPrepass>,
788 Option<&NormalPrepass>,
789 Option<&MotionVectorPrepass>,
790 )>,
791 ticks: SystemChangeTick,
792) {
793 for (view, msaa, depth_prepass, normal_prepass, motion_vector_prepass) in views.iter_mut() {
794 let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples());
795 if depth_prepass.is_some() {
796 view_key |= MeshPipelineKey::DEPTH_PREPASS;
797 }
798 if normal_prepass.is_some() {
799 view_key |= MeshPipelineKey::NORMAL_PREPASS;
800 }
801 if motion_vector_prepass.is_some() {
802 view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;
803 }
804
805 if let Some(current_key) = view_key_cache.get_mut(&view.retained_view_entity) {
806 if *current_key != view_key {
807 view_key_cache.insert(view.retained_view_entity, view_key);
808 view_specialization_ticks.insert(view.retained_view_entity, ticks.this_run());
809 }
810 } else {
811 view_key_cache.insert(view.retained_view_entity, view_key);
812 view_specialization_ticks.insert(view.retained_view_entity, ticks.this_run());
813 }
814 }
815}
816
817pub fn specialize_prepass_material_meshes(
818 render_meshes: Res<RenderAssets<RenderMesh>>,
819 render_materials: Res<ErasedRenderAssets<PreparedMaterial>>,
820 render_mesh_instances: Res<RenderMeshInstances>,
821 render_material_instances: Res<RenderMaterialInstances>,
822 render_lightmaps: Res<RenderLightmaps>,
823 render_visibility_ranges: Res<RenderVisibilityRanges>,
824 view_key_cache: Res<ViewKeyPrepassCache>,
825 views: Query<(
826 &ExtractedView,
827 &RenderVisibleEntities,
828 &Msaa,
829 Option<&MotionVectorPrepass>,
830 Option<&DeferredPrepass>,
831 )>,
832 (
833 opaque_prepass_render_phases,
834 alpha_mask_prepass_render_phases,
835 opaque_deferred_render_phases,
836 alpha_mask_deferred_render_phases,
837 ): (
838 Res<ViewBinnedRenderPhases<Opaque3dPrepass>>,
839 Res<ViewBinnedRenderPhases<AlphaMask3dPrepass>>,
840 Res<ViewBinnedRenderPhases<Opaque3dDeferred>>,
841 Res<ViewBinnedRenderPhases<AlphaMask3dDeferred>>,
842 ),
843 (
844 mut specialized_material_pipeline_cache,
845 ticks,
846 prepass_pipeline,
847 mut pipelines,
848 pipeline_cache,
849 view_specialization_ticks,
850 entity_specialization_ticks,
851 ): (
852 ResMut<SpecializedPrepassMaterialPipelineCache>,
853 SystemChangeTick,
854 Res<PrepassPipeline>,
855 ResMut<SpecializedMeshPipelines<PrepassPipelineSpecializer>>,
856 Res<PipelineCache>,
857 Res<ViewPrepassSpecializationTicks>,
858 Res<EntitySpecializationTicks>,
859 ),
860) {
861 for (extracted_view, visible_entities, msaa, motion_vector_prepass, deferred_prepass) in &views
862 {
863 if !opaque_deferred_render_phases.contains_key(&extracted_view.retained_view_entity)
864 && !alpha_mask_deferred_render_phases.contains_key(&extracted_view.retained_view_entity)
865 && !opaque_prepass_render_phases.contains_key(&extracted_view.retained_view_entity)
866 && !alpha_mask_prepass_render_phases.contains_key(&extracted_view.retained_view_entity)
867 {
868 continue;
869 }
870
871 let Some(view_key) = view_key_cache.get(&extracted_view.retained_view_entity) else {
872 continue;
873 };
874
875 let view_tick = view_specialization_ticks
876 .get(&extracted_view.retained_view_entity)
877 .unwrap();
878 let view_specialized_material_pipeline_cache = specialized_material_pipeline_cache
879 .entry(extracted_view.retained_view_entity)
880 .or_default();
881
882 for (_, visible_entity) in visible_entities.iter::<Mesh3d>() {
883 let Some(material_instance) = render_material_instances.instances.get(visible_entity)
884 else {
885 continue;
886 };
887 let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(*visible_entity)
888 else {
889 continue;
890 };
891 let entity_tick = entity_specialization_ticks.get(visible_entity).unwrap();
892 let last_specialized_tick = view_specialized_material_pipeline_cache
893 .get(visible_entity)
894 .map(|(tick, _)| *tick);
895 let needs_specialization = last_specialized_tick.is_none_or(|tick| {
896 view_tick.is_newer_than(tick, ticks.this_run())
897 || entity_tick.is_newer_than(tick, ticks.this_run())
898 });
899 if !needs_specialization {
900 continue;
901 }
902 let Some(material) = render_materials.get(material_instance.asset_id) else {
903 continue;
904 };
905 if !material.properties.prepass_enabled && !material.properties.shadows_enabled {
906 view_specialized_material_pipeline_cache.remove(visible_entity);
908 continue;
909 }
910 let Some(mesh) = render_meshes.get(mesh_instance.mesh_asset_id) else {
911 continue;
912 };
913
914 let mut mesh_key = *view_key | MeshPipelineKey::from_bits_retain(mesh.key_bits.bits());
915
916 let alpha_mode = material.properties.alpha_mode;
917 match alpha_mode {
918 AlphaMode::Opaque | AlphaMode::AlphaToCoverage | AlphaMode::Mask(_) => {
919 mesh_key |= alpha_mode_pipeline_key(alpha_mode, msaa);
920 }
921 AlphaMode::Blend
922 | AlphaMode::Premultiplied
923 | AlphaMode::Add
924 | AlphaMode::Multiply => {
925 view_specialized_material_pipeline_cache.remove(visible_entity);
928 continue;
929 }
930 }
931
932 if material.properties.reads_view_transmission_texture {
933 view_specialized_material_pipeline_cache.remove(visible_entity);
936 continue;
937 }
938
939 let forward = match material.properties.render_method {
940 OpaqueRendererMethod::Forward => true,
941 OpaqueRendererMethod::Deferred => false,
942 OpaqueRendererMethod::Auto => unreachable!(),
943 };
944
945 let deferred = deferred_prepass.is_some() && !forward;
946
947 if deferred {
948 mesh_key |= MeshPipelineKey::DEFERRED_PREPASS;
949 }
950
951 if let Some(lightmap) = render_lightmaps.render_lightmaps.get(visible_entity) {
952 mesh_key |= MeshPipelineKey::LIGHTMAPPED;
958
959 if lightmap.bicubic_sampling && deferred {
960 mesh_key |= MeshPipelineKey::LIGHTMAP_BICUBIC_SAMPLING;
961 }
962 }
963
964 if render_visibility_ranges.entity_has_crossfading_visibility_ranges(*visible_entity) {
965 mesh_key |= MeshPipelineKey::VISIBILITY_RANGE_DITHER;
966 }
967
968 if motion_vector_prepass.is_some() {
970 if mesh_instance
971 .flags
972 .contains(RenderMeshInstanceFlags::HAS_PREVIOUS_SKIN)
973 {
974 mesh_key |= MeshPipelineKey::HAS_PREVIOUS_SKIN;
975 }
976 if mesh_instance
977 .flags
978 .contains(RenderMeshInstanceFlags::HAS_PREVIOUS_MORPH)
979 {
980 mesh_key |= MeshPipelineKey::HAS_PREVIOUS_MORPH;
981 }
982 }
983
984 let erased_key = ErasedMaterialPipelineKey {
985 mesh_key,
986 material_key: material.properties.material_key.clone(),
987 type_id: material_instance.asset_id.type_id(),
988 };
989 let prepass_pipeline_specializer = PrepassPipelineSpecializer {
990 pipeline: prepass_pipeline.clone(),
991 properties: material.properties.clone(),
992 };
993 let pipeline_id = pipelines.specialize(
994 &pipeline_cache,
995 &prepass_pipeline_specializer,
996 erased_key,
997 &mesh.layout,
998 );
999 let pipeline_id = match pipeline_id {
1000 Ok(id) => id,
1001 Err(err) => {
1002 error!("{}", err);
1003 continue;
1004 }
1005 };
1006
1007 view_specialized_material_pipeline_cache
1008 .insert(*visible_entity, (ticks.this_run(), pipeline_id));
1009 }
1010 }
1011}
1012
1013pub fn queue_prepass_material_meshes(
1014 render_mesh_instances: Res<RenderMeshInstances>,
1015 render_materials: Res<ErasedRenderAssets<PreparedMaterial>>,
1016 render_material_instances: Res<RenderMaterialInstances>,
1017 mesh_allocator: Res<MeshAllocator>,
1018 gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
1019 mut opaque_prepass_render_phases: ResMut<ViewBinnedRenderPhases<Opaque3dPrepass>>,
1020 mut alpha_mask_prepass_render_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3dPrepass>>,
1021 mut opaque_deferred_render_phases: ResMut<ViewBinnedRenderPhases<Opaque3dDeferred>>,
1022 mut alpha_mask_deferred_render_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3dDeferred>>,
1023 views: Query<(&ExtractedView, &RenderVisibleEntities)>,
1024 specialized_material_pipeline_cache: Res<SpecializedPrepassMaterialPipelineCache>,
1025) {
1026 for (extracted_view, visible_entities) in &views {
1027 let (
1028 mut opaque_phase,
1029 mut alpha_mask_phase,
1030 mut opaque_deferred_phase,
1031 mut alpha_mask_deferred_phase,
1032 ) = (
1033 opaque_prepass_render_phases.get_mut(&extracted_view.retained_view_entity),
1034 alpha_mask_prepass_render_phases.get_mut(&extracted_view.retained_view_entity),
1035 opaque_deferred_render_phases.get_mut(&extracted_view.retained_view_entity),
1036 alpha_mask_deferred_render_phases.get_mut(&extracted_view.retained_view_entity),
1037 );
1038
1039 let Some(view_specialized_material_pipeline_cache) =
1040 specialized_material_pipeline_cache.get(&extracted_view.retained_view_entity)
1041 else {
1042 continue;
1043 };
1044
1045 if opaque_phase.is_none()
1047 && alpha_mask_phase.is_none()
1048 && opaque_deferred_phase.is_none()
1049 && alpha_mask_deferred_phase.is_none()
1050 {
1051 continue;
1052 }
1053
1054 for (render_entity, visible_entity) in visible_entities.iter::<Mesh3d>() {
1055 let Some((current_change_tick, pipeline_id)) =
1056 view_specialized_material_pipeline_cache.get(visible_entity)
1057 else {
1058 continue;
1059 };
1060
1061 if opaque_phase.as_mut().is_some_and(|phase| {
1063 phase.validate_cached_entity(*visible_entity, *current_change_tick)
1064 }) || alpha_mask_phase.as_mut().is_some_and(|phase| {
1065 phase.validate_cached_entity(*visible_entity, *current_change_tick)
1066 }) || opaque_deferred_phase.as_mut().is_some_and(|phase| {
1067 phase.validate_cached_entity(*visible_entity, *current_change_tick)
1068 }) || alpha_mask_deferred_phase.as_mut().is_some_and(|phase| {
1069 phase.validate_cached_entity(*visible_entity, *current_change_tick)
1070 }) {
1071 continue;
1072 }
1073
1074 let Some(material_instance) = render_material_instances.instances.get(visible_entity)
1075 else {
1076 continue;
1077 };
1078 let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(*visible_entity)
1079 else {
1080 continue;
1081 };
1082 let Some(material) = render_materials.get(material_instance.asset_id) else {
1083 continue;
1084 };
1085 let (vertex_slab, index_slab) = mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id);
1086
1087 let deferred = match material.properties.render_method {
1088 OpaqueRendererMethod::Forward => false,
1089 OpaqueRendererMethod::Deferred => true,
1090 OpaqueRendererMethod::Auto => unreachable!(),
1091 };
1092
1093 match material.properties.render_phase_type {
1094 RenderPhaseType::Opaque => {
1095 if deferred {
1096 opaque_deferred_phase.as_mut().unwrap().add(
1097 OpaqueNoLightmap3dBatchSetKey {
1098 draw_function: material
1099 .properties
1100 .get_draw_function(DeferredDrawFunction)
1101 .unwrap(),
1102 pipeline: *pipeline_id,
1103 material_bind_group_index: Some(material.binding.group.0),
1104 vertex_slab: vertex_slab.unwrap_or_default(),
1105 index_slab,
1106 },
1107 OpaqueNoLightmap3dBinKey {
1108 asset_id: mesh_instance.mesh_asset_id.into(),
1109 },
1110 (*render_entity, *visible_entity),
1111 mesh_instance.current_uniform_index,
1112 BinnedRenderPhaseType::mesh(
1113 mesh_instance.should_batch(),
1114 &gpu_preprocessing_support,
1115 ),
1116 *current_change_tick,
1117 );
1118 } else if let Some(opaque_phase) = opaque_phase.as_mut() {
1119 let (vertex_slab, index_slab) =
1120 mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id);
1121 opaque_phase.add(
1122 OpaqueNoLightmap3dBatchSetKey {
1123 draw_function: material
1124 .properties
1125 .get_draw_function(PrepassDrawFunction)
1126 .unwrap(),
1127 pipeline: *pipeline_id,
1128 material_bind_group_index: Some(material.binding.group.0),
1129 vertex_slab: vertex_slab.unwrap_or_default(),
1130 index_slab,
1131 },
1132 OpaqueNoLightmap3dBinKey {
1133 asset_id: mesh_instance.mesh_asset_id.into(),
1134 },
1135 (*render_entity, *visible_entity),
1136 mesh_instance.current_uniform_index,
1137 BinnedRenderPhaseType::mesh(
1138 mesh_instance.should_batch(),
1139 &gpu_preprocessing_support,
1140 ),
1141 *current_change_tick,
1142 );
1143 }
1144 }
1145 RenderPhaseType::AlphaMask => {
1146 if deferred {
1147 let (vertex_slab, index_slab) =
1148 mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id);
1149 let batch_set_key = OpaqueNoLightmap3dBatchSetKey {
1150 draw_function: material
1151 .properties
1152 .get_draw_function(DeferredDrawFunction)
1153 .unwrap(),
1154 pipeline: *pipeline_id,
1155 material_bind_group_index: Some(material.binding.group.0),
1156 vertex_slab: vertex_slab.unwrap_or_default(),
1157 index_slab,
1158 };
1159 let bin_key = OpaqueNoLightmap3dBinKey {
1160 asset_id: mesh_instance.mesh_asset_id.into(),
1161 };
1162 alpha_mask_deferred_phase.as_mut().unwrap().add(
1163 batch_set_key,
1164 bin_key,
1165 (*render_entity, *visible_entity),
1166 mesh_instance.current_uniform_index,
1167 BinnedRenderPhaseType::mesh(
1168 mesh_instance.should_batch(),
1169 &gpu_preprocessing_support,
1170 ),
1171 *current_change_tick,
1172 );
1173 } else if let Some(alpha_mask_phase) = alpha_mask_phase.as_mut() {
1174 let (vertex_slab, index_slab) =
1175 mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id);
1176 let batch_set_key = OpaqueNoLightmap3dBatchSetKey {
1177 draw_function: material
1178 .properties
1179 .get_draw_function(PrepassDrawFunction)
1180 .unwrap(),
1181 pipeline: *pipeline_id,
1182 material_bind_group_index: Some(material.binding.group.0),
1183 vertex_slab: vertex_slab.unwrap_or_default(),
1184 index_slab,
1185 };
1186 let bin_key = OpaqueNoLightmap3dBinKey {
1187 asset_id: mesh_instance.mesh_asset_id.into(),
1188 };
1189 alpha_mask_phase.add(
1190 batch_set_key,
1191 bin_key,
1192 (*render_entity, *visible_entity),
1193 mesh_instance.current_uniform_index,
1194 BinnedRenderPhaseType::mesh(
1195 mesh_instance.should_batch(),
1196 &gpu_preprocessing_support,
1197 ),
1198 *current_change_tick,
1199 );
1200 }
1201 }
1202 _ => {}
1203 }
1204 }
1205 }
1206}
1207
1208pub struct SetPrepassViewBindGroup<const I: usize>;
1209impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassViewBindGroup<I> {
1210 type Param = SRes<PrepassViewBindGroup>;
1211 type ViewQuery = (
1212 Read<ViewUniformOffset>,
1213 Has<MotionVectorPrepass>,
1214 Option<Read<PreviousViewUniformOffset>>,
1215 );
1216 type ItemQuery = ();
1217
1218 #[inline]
1219 fn render<'w>(
1220 _item: &P,
1221 (view_uniform_offset, has_motion_vector_prepass, previous_view_uniform_offset): (
1222 &'_ ViewUniformOffset,
1223 bool,
1224 Option<&'_ PreviousViewUniformOffset>,
1225 ),
1226 _entity: Option<()>,
1227 prepass_view_bind_group: SystemParamItem<'w, '_, Self::Param>,
1228 pass: &mut TrackedRenderPass<'w>,
1229 ) -> RenderCommandResult {
1230 let prepass_view_bind_group = prepass_view_bind_group.into_inner();
1231
1232 match previous_view_uniform_offset {
1233 Some(previous_view_uniform_offset) if has_motion_vector_prepass => {
1234 pass.set_bind_group(
1235 I,
1236 prepass_view_bind_group.motion_vectors.as_ref().unwrap(),
1237 &[
1238 view_uniform_offset.offset,
1239 previous_view_uniform_offset.offset,
1240 ],
1241 );
1242 }
1243 _ => {
1244 pass.set_bind_group(
1245 I,
1246 prepass_view_bind_group.no_motion_vectors.as_ref().unwrap(),
1247 &[view_uniform_offset.offset],
1248 );
1249 }
1250 }
1251 RenderCommandResult::Success
1252 }
1253}
1254
1255pub struct SetPrepassViewEmptyBindGroup<const I: usize>;
1256impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassViewEmptyBindGroup<I> {
1257 type Param = SRes<PrepassViewBindGroup>;
1258 type ViewQuery = ();
1259 type ItemQuery = ();
1260
1261 #[inline]
1262 fn render<'w>(
1263 _item: &P,
1264 _view: (),
1265 _entity: Option<()>,
1266 prepass_view_bind_group: SystemParamItem<'w, '_, Self::Param>,
1267 pass: &mut TrackedRenderPass<'w>,
1268 ) -> RenderCommandResult {
1269 let prepass_view_bind_group = prepass_view_bind_group.into_inner();
1270 pass.set_bind_group(I, &prepass_view_bind_group.empty_bind_group, &[]);
1271 RenderCommandResult::Success
1272 }
1273}
1274
1275pub type DrawPrepass = (
1276 SetItemPipeline,
1277 SetPrepassViewBindGroup<0>,
1278 SetPrepassViewEmptyBindGroup<1>,
1279 SetMeshBindGroup<2>,
1280 SetMaterialBindGroup<3>,
1281 DrawMesh,
1282);