Revert default mesh materials (#15930)

# Objective

Closes #15799.

Many rendering people and maintainers are in favor of reverting default
mesh materials added in #15524, especially as the migration to required
component is already large and heavily breaking.

## Solution

Revert default mesh materials, and adjust docs accordingly.

- Remove `extract_default_materials`
- Remove `clear_material_instances`, and move the logic back into
`extract_mesh_materials`
- Remove `HasMaterial2d` and `HasMaterial3d`
- Change default material handles back to pink instead of white
- 2D uses `Color::srgb(1.0, 0.0, 1.0)`, while 3D uses `Color::srgb(1.0,
0.0, 0.5)`. Not sure if this is intended.

There is now no indication at all about missing materials for `Mesh2d`
and `Mesh3d`. Having a mesh without a material renders nothing.

## Testing

I ran `2d_shapes`, `mesh2d_manual`, and `3d_shapes`, with and without
mesh material components.
This commit is contained in:
Joona Aalto 2024-10-15 22:47:40 +03:00 committed by GitHub
parent 424e563184
commit c1a4b82762
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 18 additions and 178 deletions

View File

@ -422,13 +422,13 @@ impl Plugin for PbrPlugin {
app.add_plugins(DeferredPbrLightingPlugin); app.add_plugins(DeferredPbrLightingPlugin);
} }
// Initialize the default material. // Initialize the default material handle.
app.world_mut() app.world_mut()
.resource_mut::<Assets<StandardMaterial>>() .resource_mut::<Assets<StandardMaterial>>()
.insert( .insert(
&Handle::<StandardMaterial>::default(), &Handle::<StandardMaterial>::default(),
StandardMaterial { StandardMaterial {
base_color: Color::WHITE, base_color: Color::srgb(1.0, 0.0, 0.5),
..Default::default() ..Default::default()
}, },
); );
@ -439,14 +439,7 @@ impl Plugin for PbrPlugin {
// Extract the required data from the main world // Extract the required data from the main world
render_app render_app
.add_systems( .add_systems(ExtractSchedule, (extract_clusters, extract_lights))
ExtractSchedule,
(
extract_clusters,
extract_lights,
extract_default_materials.after(clear_material_instances::<StandardMaterial>),
),
)
.add_systems( .add_systems(
Render, Render,
( (

View File

@ -270,7 +270,6 @@ where
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.init_asset::<M>() app.init_asset::<M>()
.register_type::<MeshMaterial3d<M>>() .register_type::<MeshMaterial3d<M>>()
.register_type::<HasMaterial3d>()
.add_plugins(RenderAssetPlugin::<PreparedMaterial<M>>::default()); .add_plugins(RenderAssetPlugin::<PreparedMaterial<M>>::default());
if let Some(render_app) = app.get_sub_app_mut(RenderApp) { if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
@ -283,10 +282,7 @@ where
.add_render_command::<Opaque3d, DrawMaterial<M>>() .add_render_command::<Opaque3d, DrawMaterial<M>>()
.add_render_command::<AlphaMask3d, DrawMaterial<M>>() .add_render_command::<AlphaMask3d, DrawMaterial<M>>()
.init_resource::<SpecializedMeshPipelines<MaterialPipeline<M>>>() .init_resource::<SpecializedMeshPipelines<MaterialPipeline<M>>>()
.add_systems( .add_systems(ExtractSchedule, extract_mesh_materials::<M>)
ExtractSchedule,
(clear_material_instances::<M>, extract_mesh_materials::<M>).chain(),
)
.add_systems( .add_systems(
Render, Render,
queue_material_meshes::<M> queue_material_meshes::<M>
@ -550,16 +546,12 @@ pub const fn screen_space_specular_transmission_pipeline_key(
} }
} }
pub(super) fn clear_material_instances<M: Material>(
mut material_instances: ResMut<RenderMaterialInstances<M>>,
) {
material_instances.clear();
}
fn extract_mesh_materials<M: Material>( fn extract_mesh_materials<M: Material>(
mut material_instances: ResMut<RenderMaterialInstances<M>>, mut material_instances: ResMut<RenderMaterialInstances<M>>,
query: Extract<Query<(Entity, &ViewVisibility, &MeshMaterial3d<M>)>>, query: Extract<Query<(Entity, &ViewVisibility, &MeshMaterial3d<M>)>>,
) { ) {
material_instances.clear();
for (entity, view_visibility, material) in &query { for (entity, view_visibility, material) in &query {
if view_visibility.get() { if view_visibility.get() {
material_instances.insert(entity.into(), material.id()); material_instances.insert(entity.into(), material.id());
@ -567,18 +559,6 @@ fn extract_mesh_materials<M: Material>(
} }
} }
/// Extracts default materials for 3D meshes with no [`MeshMaterial3d`].
pub(super) fn extract_default_materials(
mut material_instances: ResMut<RenderMaterialInstances<StandardMaterial>>,
query: Extract<Query<(Entity, &ViewVisibility), (With<Mesh3d>, Without<HasMaterial3d>)>>,
) {
for (entity, view_visibility) in &query {
if view_visibility.get() {
material_instances.insert(entity.into(), AssetId::default());
}
}
}
/// For each view, iterates over all the meshes visible from that view and adds /// For each view, iterates over all the meshes visible from that view and adds
/// them to [`BinnedRenderPhase`]s or [`SortedRenderPhase`]s as appropriate. /// them to [`BinnedRenderPhase`]s or [`SortedRenderPhase`]s as appropriate.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]

View File

@ -5,7 +5,7 @@ use bevy_ecs::{component::Component, reflect::ReflectComponent};
use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use derive_more::derive::From; use derive_more::derive::From;
/// A [material](Material) for a [`Mesh3d`]. /// A [material](Material) used for rendering a [`Mesh3d`].
/// ///
/// See [`Material`] for general information about 3D materials and how to implement your own materials. /// See [`Material`] for general information about 3D materials and how to implement your own materials.
/// ///
@ -36,41 +36,8 @@ use derive_more::derive::From;
/// )); /// ));
/// } /// }
/// ``` /// ```
///
/// ## Default Material
///
/// Meshes without a [`MeshMaterial3d`] are rendered with a default [`StandardMaterial`].
/// This material can be overridden by inserting a custom material for the default asset handle.
///
/// ```
/// # use bevy_pbr::{Material, MeshMaterial3d, StandardMaterial};
/// # use bevy_ecs::prelude::*;
/// # use bevy_render::mesh::{Mesh, Mesh3d};
/// # use bevy_color::Color;
/// # use bevy_asset::{Assets, Handle};
/// # use bevy_math::primitives::Capsule3d;
/// #
/// fn setup(
/// mut commands: Commands,
/// mut meshes: ResMut<Assets<Mesh>>,
/// mut materials: ResMut<Assets<StandardMaterial>>,
/// ) {
/// // Optional: Insert a custom default material.
/// materials.insert(
/// &Handle::<StandardMaterial>::default(),
/// StandardMaterial::from(Color::srgb(1.0, 0.0, 1.0)),
/// );
///
/// // Spawn a capsule with no material.
/// // The mesh will be rendered with the default material.
/// commands.spawn(Mesh3d(meshes.add(Capsule3d::default())));
/// }
/// ```
///
/// [`StandardMaterial`]: crate::StandardMaterial
#[derive(Component, Clone, Debug, Deref, DerefMut, Reflect, PartialEq, Eq, From)] #[derive(Component, Clone, Debug, Deref, DerefMut, Reflect, PartialEq, Eq, From)]
#[reflect(Component, Default)] #[reflect(Component, Default)]
#[require(HasMaterial3d)]
pub struct MeshMaterial3d<M: Material>(pub Handle<M>); pub struct MeshMaterial3d<M: Material>(pub Handle<M>);
impl<M: Material> Default for MeshMaterial3d<M> { impl<M: Material> Default for MeshMaterial3d<M> {
@ -90,12 +57,3 @@ impl<M: Material> From<&MeshMaterial3d<M>> for AssetId<M> {
material.id() material.id()
} }
} }
/// A component that marks an entity as having a [`MeshMaterial3d`].
/// [`Mesh3d`] entities without this component are rendered with a [default material].
///
/// [`Mesh3d`]: bevy_render::mesh::Mesh3d
/// [default material]: crate::MeshMaterial3d#default-material
#[derive(Component, Clone, Debug, Default, Reflect)]
#[reflect(Component, Default)]
pub struct HasMaterial3d;

View File

@ -6,13 +6,10 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_transform::components::Transform; use bevy_transform::components::Transform;
use derive_more::derive::From; use derive_more::derive::From;
/// A component for rendering 2D meshes, typically with a [`MeshMaterial2d`] using a [`ColorMaterial`]. /// A component for 2D meshes. Requires a [`MeshMaterial2d`] to be rendered, commonly using a [`ColorMaterial`].
///
/// Meshes without a [`MeshMaterial2d`] will be rendered with a [default material].
/// ///
/// [`MeshMaterial2d`]: <https://docs.rs/bevy/latest/bevy/sprite/struct.MeshMaterial2d.html> /// [`MeshMaterial2d`]: <https://docs.rs/bevy/latest/bevy/sprite/struct.MeshMaterial2d.html>
/// [`ColorMaterial`]: <https://docs.rs/bevy/latest/bevy/sprite/struct.ColorMaterial.html> /// [`ColorMaterial`]: <https://docs.rs/bevy/latest/bevy/sprite/struct.ColorMaterial.html>
/// [default material]: <https://docs.rs/bevy/latest/bevy/sprite/struct.MeshMaterial2d.html#default-material>
/// ///
/// # Example /// # Example
/// ///
@ -53,13 +50,10 @@ impl From<&Mesh2d> for AssetId<Mesh> {
} }
} }
/// A component for rendering 3D meshes, typically with a [`MeshMaterial3d`] using a [`StandardMaterial`]. /// A component for 3D meshes. Requires a [`MeshMaterial3d`] to be rendered, commonly using a [`StandardMaterial`].
///
/// Meshes without a [`MeshMaterial3d`] will be rendered with a [default material].
/// ///
/// [`MeshMaterial3d`]: <https://docs.rs/bevy/latest/bevy/pbr/struct.MeshMaterial3d.html> /// [`MeshMaterial3d`]: <https://docs.rs/bevy/latest/bevy/pbr/struct.MeshMaterial3d.html>
/// [`StandardMaterial`]: <https://docs.rs/bevy/latest/bevy/pbr/struct.StandardMaterial.html> /// [`StandardMaterial`]: <https://docs.rs/bevy/latest/bevy/pbr/struct.StandardMaterial.html>
/// [default material]: <https://docs.rs/bevy/latest/bevy/pbr/struct.MeshMaterial3d.html#default-material>
/// ///
/// # Example /// # Example
/// ///

View File

@ -1,20 +1,15 @@
#![expect(deprecated)] #![expect(deprecated)]
use crate::{ use crate::{AlphaMode2d, Material2d, Material2dPlugin, MaterialMesh2dBundle};
clear_material_2d_instances, extract_default_materials_2d, AlphaMode2d, Material2d,
Material2dPlugin, MaterialMesh2dBundle,
};
use bevy_app::{App, Plugin}; use bevy_app::{App, Plugin};
use bevy_asset::{load_internal_asset, Asset, AssetApp, Assets, Handle}; use bevy_asset::{load_internal_asset, Asset, AssetApp, Assets, Handle};
use bevy_color::{Alpha, Color, ColorToComponents, LinearRgba}; use bevy_color::{Alpha, Color, ColorToComponents, LinearRgba};
use bevy_ecs::schedule::IntoSystemConfigs;
use bevy_math::Vec4; use bevy_math::Vec4;
use bevy_reflect::prelude::*; use bevy_reflect::prelude::*;
use bevy_render::{ use bevy_render::{
render_asset::RenderAssets, render_asset::RenderAssets,
render_resource::*, render_resource::*,
texture::{GpuImage, Image}, texture::{GpuImage, Image},
ExtractSchedule, RenderApp,
}; };
pub const COLOR_MATERIAL_SHADER_HANDLE: Handle<Shader> = pub const COLOR_MATERIAL_SHADER_HANDLE: Handle<Shader> =
@ -35,26 +30,16 @@ impl Plugin for ColorMaterialPlugin {
app.add_plugins(Material2dPlugin::<ColorMaterial>::default()) app.add_plugins(Material2dPlugin::<ColorMaterial>::default())
.register_asset_reflect::<ColorMaterial>(); .register_asset_reflect::<ColorMaterial>();
// Initialize the default material. // Initialize the default material handle.
app.world_mut() app.world_mut()
.resource_mut::<Assets<ColorMaterial>>() .resource_mut::<Assets<ColorMaterial>>()
.insert( .insert(
&Handle::<ColorMaterial>::default(), &Handle::<ColorMaterial>::default(),
ColorMaterial { ColorMaterial {
color: Color::WHITE, color: Color::srgb(1.0, 0.0, 1.0),
..Default::default() ..Default::default()
}, },
); );
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
};
// Extract default materials for entities with no material.
render_app.add_systems(
ExtractSchedule,
extract_default_materials_2d.after(clear_material_2d_instances::<ColorMaterial>),
);
} }
} }

View File

@ -43,8 +43,6 @@ use bevy_utils::tracing::error;
use core::{hash::Hash, marker::PhantomData}; use core::{hash::Hash, marker::PhantomData};
use derive_more::derive::From; use derive_more::derive::From;
use super::ColorMaterial;
/// Materials are used alongside [`Material2dPlugin`], [`Mesh2d`], and [`MeshMaterial2d`] /// Materials are used alongside [`Material2dPlugin`], [`Mesh2d`], and [`MeshMaterial2d`]
/// to spawn entities that are rendered with a specific [`Material2d`] type. They serve as an easy to use high level /// to spawn entities that are rendered with a specific [`Material2d`] type. They serve as an easy to use high level
/// way to render [`Mesh2d`] entities with custom shader logic. /// way to render [`Mesh2d`] entities with custom shader logic.
@ -151,7 +149,7 @@ pub trait Material2d: AsBindGroup + Asset + Clone + Sized {
} }
} }
/// A [material](Material2d) for a [`Mesh2d`]. /// A [material](Material2d) used for rendering a [`Mesh2d`].
/// ///
/// See [`Material2d`] for general information about 2D materials and how to implement your own materials. /// See [`Material2d`] for general information about 2D materials and how to implement your own materials.
/// ///
@ -179,40 +177,8 @@ pub trait Material2d: AsBindGroup + Asset + Clone + Sized {
/// ``` /// ```
/// ///
/// [`MeshMaterial2d`]: crate::MeshMaterial2d /// [`MeshMaterial2d`]: crate::MeshMaterial2d
/// [`ColorMaterial`]: crate::ColorMaterial
///
/// ## Default Material
///
/// Meshes without a [`MeshMaterial2d`] are rendered with a default [`ColorMaterial`].
/// This material can be overridden by inserting a custom material for the default asset handle.
///
/// ```
/// # use bevy_sprite::ColorMaterial;
/// # use bevy_ecs::prelude::*;
/// # use bevy_render::mesh::{Mesh, Mesh2d};
/// # use bevy_color::Color;
/// # use bevy_asset::{Assets, Handle};
/// # use bevy_math::primitives::Circle;
/// #
/// fn setup(
/// mut commands: Commands,
/// mut meshes: ResMut<Assets<Mesh>>,
/// mut materials: ResMut<Assets<ColorMaterial>>,
/// ) {
/// // Optional: Insert a custom default material.
/// materials.insert(
/// &Handle::<ColorMaterial>::default(),
/// ColorMaterial::from(Color::srgb(1.0, 0.0, 1.0)),
/// );
///
/// // Spawn a circle with no material.
/// // The mesh will be rendered with the default material.
/// commands.spawn(Mesh2d(meshes.add(Circle::new(50.0))));
/// }
/// ```
#[derive(Component, Clone, Debug, Deref, DerefMut, Reflect, PartialEq, Eq, From)] #[derive(Component, Clone, Debug, Deref, DerefMut, Reflect, PartialEq, Eq, From)]
#[reflect(Component, Default)] #[reflect(Component, Default)]
#[require(HasMaterial2d)]
pub struct MeshMaterial2d<M: Material2d>(pub Handle<M>); pub struct MeshMaterial2d<M: Material2d>(pub Handle<M>);
impl<M: Material2d> Default for MeshMaterial2d<M> { impl<M: Material2d> Default for MeshMaterial2d<M> {
@ -233,14 +199,6 @@ impl<M: Material2d> From<&MeshMaterial2d<M>> for AssetId<M> {
} }
} }
/// A component that marks an entity as having a [`MeshMaterial2d`].
/// [`Mesh2d`] entities without this component are rendered with a [default material].
///
/// [default material]: crate::MeshMaterial2d#default-material
#[derive(Component, Clone, Debug, Default, Reflect)]
#[reflect(Component, Default)]
pub struct HasMaterial2d;
/// Sets how a 2d material's base color alpha channel is used for transparency. /// Sets how a 2d material's base color alpha channel is used for transparency.
/// Currently, this only works with [`Mesh2d`]. Sprites are always transparent. /// Currently, this only works with [`Mesh2d`]. Sprites are always transparent.
/// ///
@ -284,7 +242,6 @@ where
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.init_asset::<M>() app.init_asset::<M>()
.register_type::<MeshMaterial2d<M>>() .register_type::<MeshMaterial2d<M>>()
.register_type::<HasMaterial2d>()
.add_plugins(RenderAssetPlugin::<PreparedMaterial2d<M>>::default()); .add_plugins(RenderAssetPlugin::<PreparedMaterial2d<M>>::default());
if let Some(render_app) = app.get_sub_app_mut(RenderApp) { if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
@ -294,14 +251,7 @@ where
.add_render_command::<Transparent2d, DrawMaterial2d<M>>() .add_render_command::<Transparent2d, DrawMaterial2d<M>>()
.init_resource::<RenderMaterial2dInstances<M>>() .init_resource::<RenderMaterial2dInstances<M>>()
.init_resource::<SpecializedMeshPipelines<Material2dPipeline<M>>>() .init_resource::<SpecializedMeshPipelines<Material2dPipeline<M>>>()
.add_systems( .add_systems(ExtractSchedule, extract_mesh_materials_2d::<M>)
ExtractSchedule,
(
clear_material_2d_instances::<M>,
extract_mesh_materials_2d::<M>,
)
.chain(),
)
.add_systems( .add_systems(
Render, Render,
queue_material2d_meshes::<M> queue_material2d_meshes::<M>
@ -327,16 +277,12 @@ impl<M: Material2d> Default for RenderMaterial2dInstances<M> {
} }
} }
pub(crate) fn clear_material_2d_instances<M: Material2d>(
mut material_instances: ResMut<RenderMaterial2dInstances<M>>,
) {
material_instances.clear();
}
fn extract_mesh_materials_2d<M: Material2d>( fn extract_mesh_materials_2d<M: Material2d>(
mut material_instances: ResMut<RenderMaterial2dInstances<M>>, mut material_instances: ResMut<RenderMaterial2dInstances<M>>,
query: Extract<Query<(Entity, &ViewVisibility, &MeshMaterial2d<M>), With<Mesh2d>>>, query: Extract<Query<(Entity, &ViewVisibility, &MeshMaterial2d<M>), With<Mesh2d>>>,
) { ) {
material_instances.clear();
for (entity, view_visibility, material) in &query { for (entity, view_visibility, material) in &query {
if view_visibility.get() { if view_visibility.get() {
material_instances.insert(entity.into(), material.id()); material_instances.insert(entity.into(), material.id());
@ -344,20 +290,6 @@ fn extract_mesh_materials_2d<M: Material2d>(
} }
} }
/// Extracts default materials for 2D meshes with no [`MeshMaterial2d`].
pub(crate) fn extract_default_materials_2d(
mut material_instances: ResMut<RenderMaterial2dInstances<ColorMaterial>>,
query: Extract<Query<(Entity, &ViewVisibility), (With<Mesh2d>, Without<HasMaterial2d>)>>,
) {
let default_material: AssetId<ColorMaterial> = Handle::<ColorMaterial>::default().id();
for (entity, view_visibility) in &query {
if view_visibility.get() {
material_instances.insert(entity.into(), default_material);
}
}
}
/// Render pipeline data for a given [`Material2d`] /// Render pipeline data for a given [`Material2d`]
#[derive(Resource)] #[derive(Resource)]
pub struct Material2dPipeline<M: Material2d> { pub struct Material2dPipeline<M: Material2d> {

View File

@ -30,8 +30,8 @@ use bevy::{
Extract, Render, RenderApp, RenderSet, Extract, Render, RenderApp, RenderSet,
}, },
sprite::{ sprite::{
extract_mesh2d, DrawMesh2d, HasMaterial2d, Material2dBindGroupId, Mesh2dPipeline, extract_mesh2d, DrawMesh2d, Material2dBindGroupId, Mesh2dPipeline, Mesh2dPipelineKey,
Mesh2dPipelineKey, Mesh2dTransforms, MeshFlags, RenderMesh2dInstance, SetMesh2dBindGroup, Mesh2dTransforms, MeshFlags, RenderMesh2dInstance, SetMesh2dBindGroup,
SetMesh2dViewBindGroup, SetMesh2dViewBindGroup,
}, },
}; };
@ -120,10 +120,8 @@ fn star(
commands.spawn(Camera2d); commands.spawn(Camera2d);
} }
// Require `HasMaterial2d` to indicate that no placeholder material should be rendeed.
/// A marker component for colored 2d meshes /// A marker component for colored 2d meshes
#[derive(Component, Default)] #[derive(Component, Default)]
#[require(HasMaterial2d)]
pub struct ColoredMesh2d; pub struct ColoredMesh2d;
/// Custom pipeline for 2d meshes with vertex colors /// Custom pipeline for 2d meshes with vertex colors