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