Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 66 additions & 45 deletions crates/bevy_pbr/src/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1218,15 +1218,17 @@ pub fn queue_material_meshes(

// Fetch the slabs that this mesh resides in.
let (vertex_slab, index_slab) = mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id);
let Some(draw_function) = material.properties.get_draw_function(MaterialDrawFunction)
else {
continue;
};

match material.properties.render_phase_type {
RenderPhaseType::Transmissive => {
let distance = rangefinder.distance_translation(&mesh_instance.translation)
+ material.properties.depth_bias;
let Some(draw_function) = material
.properties
.get_draw_function(MainPassTransmissiveDrawFunction)
else {
continue;
};
transmissive_phase.add(Transmissive3d {
entity: (*render_entity, *visible_entity),
draw_function,
Expand All @@ -1246,6 +1248,12 @@ pub fn queue_material_meshes(
opaque_phase.update_cache(*visible_entity, None, current_change_tick);
continue;
}
let Some(draw_function) = material
.properties
.get_draw_function(MainPassOpaqueDrawFunction)
else {
continue;
};
let batch_set_key = Opaque3dBatchSetKey {
pipeline: pipeline_id,
draw_function,
Expand All @@ -1271,6 +1279,12 @@ pub fn queue_material_meshes(
}
// Alpha mask
RenderPhaseType::AlphaMask => {
let Some(draw_function) = material
.properties
.get_draw_function(MainPassAlphaMaskDrawFunction)
else {
continue;
};
let batch_set_key = OpaqueNoLightmap3dBatchSetKey {
draw_function,
pipeline: pipeline_id,
Expand All @@ -1296,6 +1310,12 @@ pub fn queue_material_meshes(
RenderPhaseType::Transparent => {
let distance = rangefinder.distance_translation(&mesh_instance.translation)
+ material.properties.depth_bias;
let Some(draw_function) = material
.properties
.get_draw_function(MainPassTransparentDrawFunction)
else {
continue;
};
transparent_phase.add(Transparent3d {
entity: (*render_entity, *visible_entity),
draw_function,
Expand Down Expand Up @@ -1389,13 +1409,23 @@ pub struct MeshletPrepassFragmentShader;
pub struct MeshletDeferredFragmentShader;

#[derive(DrawFunctionLabel, Debug, Hash, PartialEq, Eq, Clone, Default)]
pub struct MaterialDrawFunction;
pub struct MainPassOpaqueDrawFunction;
#[derive(DrawFunctionLabel, Debug, Hash, PartialEq, Eq, Clone, Default)]
pub struct MainPassAlphaMaskDrawFunction;
#[derive(DrawFunctionLabel, Debug, Hash, PartialEq, Eq, Clone, Default)]
pub struct MainPassTransmissiveDrawFunction;
#[derive(DrawFunctionLabel, Debug, Hash, PartialEq, Eq, Clone, Default)]
pub struct MainPassTransparentDrawFunction;

#[derive(DrawFunctionLabel, Debug, Hash, PartialEq, Eq, Clone, Default)]
pub struct PrepassDrawFunction;
pub struct PrepassOpaqueDrawFunction;
#[derive(DrawFunctionLabel, Debug, Hash, PartialEq, Eq, Clone, Default)]
pub struct PrepassAlphaMaskDrawFunction;

#[derive(DrawFunctionLabel, Debug, Hash, PartialEq, Eq, Clone, Default)]
pub struct DeferredDrawFunction;
pub struct DeferredOpaqueDrawFunction;
#[derive(DrawFunctionLabel, Debug, Hash, PartialEq, Eq, Clone, Default)]
pub struct DeferredAlphaMaskDrawFunction;

#[derive(DrawFunctionLabel, Debug, Hash, PartialEq, Eq, Clone, Default)]
pub struct ShadowsDrawFunction;
Expand Down Expand Up @@ -1637,17 +1667,37 @@ where
let draw_alpha_mask_pbr = alpha_mask_draw_functions.read().id::<DrawMaterial>();
let draw_transmissive_pbr = transmissive_draw_functions.read().id::<DrawMaterial>();
let draw_transparent_pbr = transparent_draw_functions.read().id::<DrawMaterial>();
let draw_opaque_prepass = opaque_prepass_draw_functions.read().get_id::<DrawPrepass>();
let draw_alpha_mask_prepass = alpha_mask_prepass_draw_functions
.read()
.get_id::<DrawPrepass>();
let draw_opaque_deferred = opaque_deferred_draw_functions
.read()
.get_id::<DrawPrepass>();
let draw_opaque_prepass = opaque_prepass_draw_functions.read().id::<DrawPrepass>();
let draw_alpha_mask_prepass = alpha_mask_prepass_draw_functions.read().id::<DrawPrepass>();
let draw_opaque_deferred = opaque_deferred_draw_functions.read().id::<DrawPrepass>();
let draw_alpha_mask_deferred = alpha_mask_deferred_draw_functions
.read()
.get_id::<DrawPrepass>();
let shadow_draw_function_id = shadow_draw_functions.read().get_id::<DrawPrepass>();
.id::<DrawPrepass>();
let draw_shadows = shadow_draw_functions.read().id::<DrawPrepass>();

let draw_functions = SmallVec::from_iter([
(MainPassOpaqueDrawFunction.intern(), draw_opaque_pbr),
(MainPassAlphaMaskDrawFunction.intern(), draw_alpha_mask_pbr),
(
MainPassTransmissiveDrawFunction.intern(),
draw_transmissive_pbr,
),
(
MainPassTransparentDrawFunction.intern(),
draw_transparent_pbr,
),
(PrepassOpaqueDrawFunction.intern(), draw_opaque_prepass),
(
PrepassAlphaMaskDrawFunction.intern(),
draw_alpha_mask_prepass,
),
(DeferredOpaqueDrawFunction.intern(), draw_opaque_deferred),
(
DeferredAlphaMaskDrawFunction.intern(),
draw_alpha_mask_deferred,
),
(ShadowsDrawFunction.intern(), draw_shadows),
]);

let render_method = match material.opaque_render_method() {
OpaqueRendererMethod::Forward => OpaqueRendererMethod::Forward,
Expand All @@ -1673,35 +1723,6 @@ where
AlphaMode::Mask(_) => RenderPhaseType::AlphaMask,
};

let draw_function_id = match render_phase_type {
RenderPhaseType::Opaque => draw_opaque_pbr,
RenderPhaseType::AlphaMask => draw_alpha_mask_pbr,
RenderPhaseType::Transmissive => draw_transmissive_pbr,
RenderPhaseType::Transparent => draw_transparent_pbr,
};
let prepass_draw_function_id = match render_phase_type {
RenderPhaseType::Opaque => draw_opaque_prepass,
RenderPhaseType::AlphaMask => draw_alpha_mask_prepass,
_ => None,
};
let deferred_draw_function_id = match render_phase_type {
RenderPhaseType::Opaque => draw_opaque_deferred,
RenderPhaseType::AlphaMask => draw_alpha_mask_deferred,
_ => None,
};

let mut draw_functions = SmallVec::new();
draw_functions.push((MaterialDrawFunction.intern(), draw_function_id));
if let Some(prepass_draw_function_id) = prepass_draw_function_id {
draw_functions.push((PrepassDrawFunction.intern(), prepass_draw_function_id));
}
if let Some(deferred_draw_function_id) = deferred_draw_function_id {
draw_functions.push((DeferredDrawFunction.intern(), deferred_draw_function_id));
}
if let Some(shadow_draw_function_id) = shadow_draw_function_id {
draw_functions.push((ShadowsDrawFunction.intern(), shadow_draw_function_id));
}

let mut shaders = SmallVec::new();
let mut add_shader = |label: InternedShaderLabel, shader_ref: ShaderRef| {
let mayber_shader = match shader_ref {
Expand Down
57 changes: 35 additions & 22 deletions crates/bevy_pbr/src/prepass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ mod prepass_bindings;
use crate::{
alpha_mode_pipeline_key, binding_arrays_are_usable, buffer_layout,
collect_meshes_for_gpu_building, init_material_pipeline, set_mesh_motion_vector_flags,
setup_morph_and_skinning_defs, skin, DeferredDrawFunction, DeferredFragmentShader,
DeferredVertexShader, DrawMesh, EntitySpecializationTicks, ErasedMaterialPipelineKey,
MaterialPipeline, MaterialProperties, MeshLayouts, MeshPipeline, MeshPipelineKey,
OpaqueRendererMethod, PreparedMaterial, PrepassDrawFunction, PrepassFragmentShader,
PrepassVertexShader, RenderLightmaps, RenderMaterialInstances, RenderMeshInstanceFlags,
RenderMeshInstances, RenderPhaseType, SetMaterialBindGroup, SetMeshBindGroup, ShadowView,
setup_morph_and_skinning_defs, skin, DeferredAlphaMaskDrawFunction, DeferredFragmentShader,
DeferredOpaqueDrawFunction, DeferredVertexShader, DrawMesh, EntitySpecializationTicks,
ErasedMaterialPipelineKey, MaterialPipeline, MaterialProperties, MeshLayouts, MeshPipeline,
MeshPipelineKey, OpaqueRendererMethod, PreparedMaterial, PrepassAlphaMaskDrawFunction,
PrepassFragmentShader, PrepassOpaqueDrawFunction, PrepassVertexShader, RenderLightmaps,
RenderMaterialInstances, RenderMeshInstanceFlags, RenderMeshInstances, RenderPhaseType,
SetMaterialBindGroup, SetMeshBindGroup, ShadowView,
};
use bevy_app::{App, Plugin, PreUpdate};
use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
Expand Down Expand Up @@ -1087,12 +1088,15 @@ pub fn queue_prepass_material_meshes(
match material.properties.render_phase_type {
RenderPhaseType::Opaque => {
if deferred {
let Some(draw_function) = material
.properties
.get_draw_function(DeferredOpaqueDrawFunction)
else {
continue;
};
opaque_deferred_phase.as_mut().unwrap().add(
OpaqueNoLightmap3dBatchSetKey {
draw_function: material
.properties
.get_draw_function(DeferredDrawFunction)
.unwrap(),
draw_function,
pipeline: *pipeline_id,
material_bind_group_index: Some(material.binding.group.0),
vertex_slab: vertex_slab.unwrap_or_default(),
Expand All @@ -1112,12 +1116,15 @@ pub fn queue_prepass_material_meshes(
} else if let Some(opaque_phase) = opaque_phase.as_mut() {
let (vertex_slab, index_slab) =
mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id);
let Some(draw_function) = material
.properties
.get_draw_function(PrepassOpaqueDrawFunction)
else {
continue;
};
opaque_phase.add(
OpaqueNoLightmap3dBatchSetKey {
draw_function: material
.properties
.get_draw_function(PrepassDrawFunction)
.unwrap(),
draw_function,
pipeline: *pipeline_id,
material_bind_group_index: Some(material.binding.group.0),
vertex_slab: vertex_slab.unwrap_or_default(),
Expand All @@ -1140,11 +1147,14 @@ pub fn queue_prepass_material_meshes(
if deferred {
let (vertex_slab, index_slab) =
mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id);
let Some(draw_function) = material
.properties
.get_draw_function(DeferredAlphaMaskDrawFunction)
else {
continue;
};
let batch_set_key = OpaqueNoLightmap3dBatchSetKey {
draw_function: material
.properties
.get_draw_function(DeferredDrawFunction)
.unwrap(),
draw_function,
pipeline: *pipeline_id,
material_bind_group_index: Some(material.binding.group.0),
vertex_slab: vertex_slab.unwrap_or_default(),
Expand All @@ -1167,11 +1177,14 @@ pub fn queue_prepass_material_meshes(
} else if let Some(alpha_mask_phase) = alpha_mask_phase.as_mut() {
let (vertex_slab, index_slab) =
mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id);
let Some(draw_function) = material
.properties
.get_draw_function(PrepassAlphaMaskDrawFunction)
else {
continue;
};
let batch_set_key = OpaqueNoLightmap3dBatchSetKey {
draw_function: material
.properties
.get_draw_function(PrepassDrawFunction)
.unwrap(),
draw_function,
pipeline: *pipeline_id,
material_bind_group_index: Some(material.binding.group.0),
vertex_slab: vertex_slab.unwrap_or_default(),
Expand Down
6 changes: 3 additions & 3 deletions examples/3d/manual_material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use bevy::{
},
pbr::{
late_sweep_material_instances, DrawMaterial, EntitiesNeedingSpecialization,
EntitySpecializationTickPair, EntitySpecializationTicks, MaterialBindGroupAllocator,
MaterialBindGroupAllocators, MaterialDrawFunction,
EntitySpecializationTickPair, EntitySpecializationTicks, MainPassOpaqueDrawFunction,
MaterialBindGroupAllocator, MaterialBindGroupAllocators,
MaterialExtractEntitiesNeedingSpecializationSystems, MaterialExtractionSystems,
MaterialFragmentShader, MaterialProperties, PreparedMaterial, RenderMaterialBindings,
RenderMaterialInstance, RenderMaterialInstances, SpecializedMaterialPipelineCache,
Expand Down Expand Up @@ -200,7 +200,7 @@ impl ErasedRenderAsset for ImageMaterial {
material_layout: Some(material_layout),
..Default::default()
};
properties.add_draw_function(MaterialDrawFunction, draw_function_id);
properties.add_draw_function(MainPassOpaqueDrawFunction, draw_function_id);
properties.add_shader(MaterialFragmentShader, asset_server.load(SHADER_ASSET_PATH));

Ok(PreparedMaterial {
Expand Down
24 changes: 24 additions & 0 deletions release-content/migration-guides/draw_functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
title: "Per-RenderPhase Draw Functions"
pull_requests: [21021]
---

This PR makes draw function labels in `MaterialProperties` per-`RenderPhase` instead
of per-pass. This should only affect users of the low-level "manual Material" API,
and not users of the broader Material API. Specifying all draw functions is not
mandatory, but users should specify draw functions for all render phases the
material may queue to, or the material may not render.

- Removed `MaterialDrawFunction` in favor of:
- `MainPassOpaqueDrawFunction`
- `MainPassAlphaMaskDrawFunction`
- `MainPassTransmissiveDrawFunction`
- `MainPassTransparentDrawFunction`

- Removed `PrepassDrawFunction` in favor of:
- `PrepassOpaqueDrawFunction`
- `PrepassAlphaMaskDrawFunction`

- Removed `DeferredDrawFunction` in favor of:
- `DeferredOpaqueDrawFunction`
- `DeferredAlphaMaskDrawFunction`