Path: blob/main/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs
9492 views
use super::{1instance_manager::InstanceManager, pipelines::MeshletPipelines,2resource_manager::ResourceManager,3};4use crate::*;5use bevy_camera::{Camera3d, Projection};6use bevy_core_pipeline::{7prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass},8tonemapping::{DebandDither, Tonemapping},9};10use bevy_derive::{Deref, DerefMut};11use bevy_light::{EnvironmentMapLight, IrradianceVolume, ShadowFilteringMethod};12use bevy_material::{13key::{ErasedMaterialPipelineKey, ErasedMeshPipelineKey},14OpaqueRendererMethod,15};16use bevy_mesh::VertexBufferLayout;17use bevy_mesh::{Mesh, MeshVertexBufferLayout, MeshVertexBufferLayoutRef, MeshVertexBufferLayouts};18use bevy_platform::collections::{HashMap, HashSet};19use bevy_render::erased_render_asset::ErasedRenderAssets;20use bevy_render::{camera::TemporalJitter, render_resource::*, view::ExtractedView};21use bevy_utils::default;22use core::any::{Any, TypeId};2324/// A list of `(Material ID, Pipeline, BindGroup)` for a view for use in [`meshlet_main_opaque_pass`](`super::meshlet_main_opaque_pass`).25#[derive(Component, Deref, DerefMut, Default)]26pub struct MeshletViewMaterialsMainOpaquePass(pub Vec<(u32, CachedRenderPipelineId, BindGroup)>);2728/// Prepare [`Material`] pipelines for [`MeshletMesh`](`super::MeshletMesh`) entities for use in [`meshlet_main_opaque_pass`](`super::meshlet_main_opaque_pass`),29/// and register the material with [`InstanceManager`].30pub fn prepare_material_meshlet_meshes_main_opaque_pass(31resource_manager: ResMut<ResourceManager>,32mut instance_manager: ResMut<InstanceManager>,33mut cache: Local<HashMap<(MeshPipelineKey, TypeId), CachedRenderPipelineId>>,34pipeline_cache: Res<PipelineCache>,35material_pipeline: Res<MaterialPipeline>,36mesh_pipeline: Res<MeshPipeline>,37render_materials: Res<ErasedRenderAssets<PreparedMaterial>>,38meshlet_pipelines: Res<MeshletPipelines>,39render_material_instances: Res<RenderMaterialInstances>,40material_bind_group_allocators: Res<MaterialBindGroupAllocators>,41mut mesh_vertex_buffer_layouts: ResMut<MeshVertexBufferLayouts>,42mut views: Query<43(44&mut MeshletViewMaterialsMainOpaquePass,45&ExtractedView,46Option<&Tonemapping>,47Option<&DebandDither>,48Option<&ShadowFilteringMethod>,49(Has<ScreenSpaceAmbientOcclusion>, Has<DistanceFog>),50(51Has<NormalPrepass>,52Has<DepthPrepass>,53Has<MotionVectorPrepass>,54Has<DeferredPrepass>,55),56Has<TemporalJitter>,57Option<&Projection>,58Has<RenderViewLightProbes<EnvironmentMapLight>>,59Has<RenderViewLightProbes<IrradianceVolume>>,60),61With<Camera3d>,62>,63) {64let fake_vertex_buffer_layout = &fake_vertex_buffer_layout(&mut mesh_vertex_buffer_layouts);6566for (67mut materials,68view,69tonemapping,70dither,71shadow_filter_method,72(ssao, distance_fog),73(normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass),74temporal_jitter,75projection,76has_environment_maps,77has_irradiance_volumes,78) in &mut views79{80let mut view_key =81MeshPipelineKey::from_msaa_samples(1) | MeshPipelineKey::from_hdr(view.hdr);8283if normal_prepass {84view_key |= MeshPipelineKey::NORMAL_PREPASS;85}86if depth_prepass {87view_key |= MeshPipelineKey::DEPTH_PREPASS;88}89if motion_vector_prepass {90view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;91}92if deferred_prepass {93view_key |= MeshPipelineKey::DEFERRED_PREPASS;94}9596if temporal_jitter {97view_key |= MeshPipelineKey::TEMPORAL_JITTER;98}99100if has_environment_maps {101view_key |= MeshPipelineKey::ENVIRONMENT_MAP;102}103104if has_irradiance_volumes {105view_key |= MeshPipelineKey::IRRADIANCE_VOLUME;106}107108if let Some(projection) = projection {109view_key |= match projection {110Projection::Perspective(_) => MeshPipelineKey::VIEW_PROJECTION_PERSPECTIVE,111Projection::Orthographic(_) => MeshPipelineKey::VIEW_PROJECTION_ORTHOGRAPHIC,112Projection::Custom(_) => MeshPipelineKey::VIEW_PROJECTION_NONSTANDARD,113};114}115116match shadow_filter_method.unwrap_or(&ShadowFilteringMethod::default()) {117ShadowFilteringMethod::Hardware2x2 => {118view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_HARDWARE_2X2;119}120ShadowFilteringMethod::Gaussian => {121view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_GAUSSIAN;122}123ShadowFilteringMethod::Temporal => {124view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_TEMPORAL;125}126}127128if !view.hdr {129if let Some(tonemapping) = tonemapping {130view_key |= MeshPipelineKey::TONEMAP_IN_SHADER;131view_key |= tonemapping_pipeline_key(*tonemapping);132}133if let Some(DebandDither::Enabled) = dither {134view_key |= MeshPipelineKey::DEBAND_DITHER;135}136}137138if ssao {139view_key |= MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION;140}141if distance_fog {142view_key |= MeshPipelineKey::DISTANCE_FOG;143}144145view_key |= MeshPipelineKey::from_primitive_topology(PrimitiveTopology::TriangleList);146147for material_id in render_material_instances148.instances149.values()150.map(|instance| instance.asset_id)151.collect::<HashSet<_>>()152{153let Some(material) = render_materials.get(material_id) else {154continue;155};156157if material.properties.render_method != OpaqueRendererMethod::Forward158|| material.properties.alpha_mode != AlphaMode::Opaque159|| material.properties.reads_view_transmission_texture160{161continue;162}163164let erased_key = ErasedMaterialPipelineKey {165mesh_key: ErasedMeshPipelineKey::new(view_key),166material_key: material.properties.material_key.clone(),167type_id: material_id.type_id(),168};169let material_pipeline_specializer = MaterialPipelineSpecializer {170pipeline: material_pipeline.clone(),171properties: material.properties.clone(),172};173let Ok(material_pipeline_descriptor) =174material_pipeline_specializer.specialize(erased_key, fake_vertex_buffer_layout)175else {176continue;177};178let material_fragment = material_pipeline_descriptor.fragment.unwrap();179180let mut shader_defs = material_fragment.shader_defs;181shader_defs.push("MESHLET_MESH_MATERIAL_PASS".into());182183let layout = mesh_pipeline.get_view_layout(view_key.into());184let layout = vec![185layout.main_layout.clone(),186layout.binding_array_layout.clone(),187resource_manager.material_shade_bind_group_layout.clone(),188material189.properties190.material_layout191.as_ref()192.unwrap()193.clone(),194];195196let pipeline_descriptor = RenderPipelineDescriptor {197label: material_pipeline_descriptor.label,198layout,199immediate_size: 0,200vertex: VertexState {201shader: meshlet_pipelines.meshlet_mesh_material.clone(),202shader_defs: shader_defs.clone(),203entry_point: material_pipeline_descriptor.vertex.entry_point,204buffers: Vec::new(),205},206primitive: PrimitiveState::default(),207depth_stencil: Some(DepthStencilState {208format: TextureFormat::Depth16Unorm,209depth_write_enabled: false,210depth_compare: CompareFunction::Equal,211stencil: StencilState::default(),212bias: DepthBiasState::default(),213}),214multisample: MultisampleState::default(),215fragment: Some(FragmentState {216shader: match material.properties.get_shader(MeshletFragmentShader) {217Some(shader) => shader.clone(),218None => meshlet_pipelines.meshlet_mesh_material.clone(),219},220shader_defs,221entry_point: material_fragment.entry_point,222targets: material_fragment.targets,223}),224zero_initialize_workgroup_memory: false,225};226let type_id = material_id.type_id();227let Some(material_bind_group_allocator) = material_bind_group_allocators.get(&type_id)228else {229continue;230};231let material_id = instance_manager.get_material_id(material_id);232233let pipeline_id = *cache.entry((view_key, type_id)).or_insert_with(|| {234pipeline_cache.queue_render_pipeline(pipeline_descriptor.clone())235});236237let Some(material_bind_group) =238material_bind_group_allocator.get(material.binding.group)239else {240continue;241};242let Some(bind_group) = material_bind_group.bind_group() else {243continue;244};245246materials.push((material_id, pipeline_id, (*bind_group).clone()));247}248}249}250251/// A list of `(Material ID, Pipeline, BindGroup)` for a view for use in [`meshlet_prepass`](`super::meshlet_prepass`).252#[derive(Component, Deref, DerefMut, Default)]253pub struct MeshletViewMaterialsPrepass(pub Vec<(u32, CachedRenderPipelineId, BindGroup)>);254255/// A list of `(Material ID, Pipeline, BindGroup)` for a view for use in [`meshlet_deferred_gbuffer_prepass`](`super::meshlet_deferred_gbuffer_prepass`).256#[derive(Component, Deref, DerefMut, Default)]257pub struct MeshletViewMaterialsDeferredGBufferPrepass(258pub Vec<(u32, CachedRenderPipelineId, BindGroup)>,259);260261/// Prepare [`Material`] pipelines for [`MeshletMesh`](`super::MeshletMesh`) entities for use in [`meshlet_prepass`](`super::meshlet_prepass`),262/// and [`meshlet_deferred_gbuffer_prepass`](`super::meshlet_deferred_gbuffer_prepass`) and register the material with [`InstanceManager`].263pub fn prepare_material_meshlet_meshes_prepass(264resource_manager: ResMut<ResourceManager>,265mut instance_manager: ResMut<InstanceManager>,266mut cache: Local<HashMap<(MeshPipelineKey, TypeId), CachedRenderPipelineId>>,267pipeline_cache: Res<PipelineCache>,268prepass_pipeline: Res<PrepassPipeline>,269material_bind_group_allocators: Res<MaterialBindGroupAllocators>,270render_materials: Res<ErasedRenderAssets<PreparedMaterial>>,271meshlet_pipelines: Res<MeshletPipelines>,272render_material_instances: Res<RenderMaterialInstances>,273mut mesh_vertex_buffer_layouts: ResMut<MeshVertexBufferLayouts>,274mut views: Query<275(276&mut MeshletViewMaterialsPrepass,277&mut MeshletViewMaterialsDeferredGBufferPrepass,278&ExtractedView,279AnyOf<(&NormalPrepass, &MotionVectorPrepass, &DeferredPrepass)>,280),281With<Camera3d>,282>,283) {284let fake_vertex_buffer_layout = &fake_vertex_buffer_layout(&mut mesh_vertex_buffer_layouts);285286for (287mut materials,288mut deferred_materials,289view,290(normal_prepass, motion_vector_prepass, deferred_prepass),291) in &mut views292{293let mut view_key =294MeshPipelineKey::from_msaa_samples(1) | MeshPipelineKey::from_hdr(view.hdr);295296if normal_prepass.is_some() {297view_key |= MeshPipelineKey::NORMAL_PREPASS;298}299if motion_vector_prepass.is_some() {300view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;301}302303view_key |= MeshPipelineKey::from_primitive_topology(PrimitiveTopology::TriangleList);304305for material_id in render_material_instances306.instances307.values()308.map(|instance| instance.asset_id)309.collect::<HashSet<_>>()310{311let Some(material) = render_materials.get(material_id) else {312continue;313};314let Some(material_bind_group_allocator) =315material_bind_group_allocators.get(&material_id.type_id())316else {317continue;318};319320if material.properties.alpha_mode != AlphaMode::Opaque321|| material.properties.reads_view_transmission_texture322{323continue;324}325326let material_wants_deferred = matches!(327material.properties.render_method,328OpaqueRendererMethod::Deferred329);330if deferred_prepass.is_some() && material_wants_deferred {331view_key |= MeshPipelineKey::DEFERRED_PREPASS;332} else if normal_prepass.is_none() && motion_vector_prepass.is_none() {333continue;334}335336let erased_key = ErasedMaterialPipelineKey {337mesh_key: ErasedMeshPipelineKey::new(view_key),338material_key: material.properties.material_key.clone(),339type_id: material_id.type_id(),340};341let material_pipeline_specializer = PrepassPipelineSpecializer {342pipeline: prepass_pipeline.clone(),343properties: material.properties.clone(),344};345let Ok(material_pipeline_descriptor) =346material_pipeline_specializer.specialize(erased_key, fake_vertex_buffer_layout)347else {348continue;349};350let material_fragment = material_pipeline_descriptor.fragment.unwrap();351352let mut shader_defs = material_fragment.shader_defs;353shader_defs.push("MESHLET_MESH_MATERIAL_PASS".into());354355let view_layout = if view_key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {356prepass_pipeline.view_layout_motion_vectors.clone()357} else {358prepass_pipeline.view_layout_no_motion_vectors.clone()359};360361let fragment_shader = if view_key.contains(MeshPipelineKey::DEFERRED_PREPASS) {362material363.properties364.get_shader(MeshletDeferredFragmentShader)365.unwrap_or(meshlet_pipelines.meshlet_mesh_material.clone())366} else {367material368.properties369.get_shader(MeshletPrepassFragmentShader)370.unwrap_or(meshlet_pipelines.meshlet_mesh_material.clone())371};372373let entry_point = if fragment_shader == meshlet_pipelines.meshlet_mesh_material {374material_fragment.entry_point.clone()375} else {376None377};378379let pipeline_descriptor = RenderPipelineDescriptor {380label: material_pipeline_descriptor.label,381layout: vec![382view_layout,383prepass_pipeline.empty_layout.clone(),384resource_manager.material_shade_bind_group_layout.clone(),385material386.properties387.material_layout388.as_ref()389.unwrap()390.clone(),391],392vertex: VertexState {393shader: meshlet_pipelines.meshlet_mesh_material.clone(),394shader_defs: shader_defs.clone(),395entry_point: material_pipeline_descriptor.vertex.entry_point,396..default()397},398primitive: PrimitiveState::default(),399depth_stencil: Some(DepthStencilState {400format: TextureFormat::Depth16Unorm,401depth_write_enabled: false,402depth_compare: CompareFunction::Equal,403stencil: StencilState::default(),404bias: DepthBiasState::default(),405}),406fragment: Some(FragmentState {407shader: fragment_shader,408shader_defs,409entry_point,410targets: material_fragment.targets,411}),412..default()413};414415let material_id = instance_manager.get_material_id(material_id);416417let pipeline_id = *cache418.entry((view_key, material_id.type_id()))419.or_insert_with(|| {420pipeline_cache.queue_render_pipeline(pipeline_descriptor.clone())421});422423let Some(material_bind_group) =424material_bind_group_allocator.get(material.binding.group)425else {426continue;427};428let Some(bind_group) = material_bind_group.bind_group() else {429continue;430};431432let item = (material_id, pipeline_id, (*bind_group).clone());433if view_key.contains(MeshPipelineKey::DEFERRED_PREPASS) {434deferred_materials.push(item);435} else {436materials.push(item);437}438}439}440}441442// Meshlet materials don't use a traditional vertex buffer, but the material specialization requires one.443fn fake_vertex_buffer_layout(layouts: &mut MeshVertexBufferLayouts) -> MeshVertexBufferLayoutRef {444layouts.insert(MeshVertexBufferLayout::new(445vec![446Mesh::ATTRIBUTE_POSITION.id,447Mesh::ATTRIBUTE_NORMAL.id,448Mesh::ATTRIBUTE_UV_0.id,449Mesh::ATTRIBUTE_TANGENT.id,450],451VertexBufferLayout {452array_stride: 48,453step_mode: VertexStepMode::Vertex,454attributes: vec![455VertexAttribute {456format: Mesh::ATTRIBUTE_POSITION.format,457offset: 0,458shader_location: 0,459},460VertexAttribute {461format: Mesh::ATTRIBUTE_NORMAL.format,462offset: 12,463shader_location: 1,464},465VertexAttribute {466format: Mesh::ATTRIBUTE_UV_0.format,467offset: 24,468shader_location: 2,469},470VertexAttribute {471format: Mesh::ATTRIBUTE_TANGENT.format,472offset: 32,473shader_location: 3,474},475],476},477))478}479480481