
# Objective A big step in the migration to required components: meshes and materials! ## Solution As per the [selected proposal](https://hackmd.io/@bevy/required_components/%2Fj9-PnF-2QKK0on1KQ29UWQ): - Deprecate `MaterialMesh2dBundle`, `MaterialMeshBundle`, and `PbrBundle`. - Add `Mesh2d` and `Mesh3d` components, which wrap a `Handle<Mesh>`. - Add `MeshMaterial2d<M: Material2d>` and `MeshMaterial3d<M: Material>`, which wrap a `Handle<M>`. - Meshes *without* a mesh material should be rendered with a default material. The existence of a material is determined by `HasMaterial2d`/`HasMaterial3d`, which is required by `MeshMaterial2d`/`MeshMaterial3d`. This gets around problems with the generics. Previously: ```rust commands.spawn(MaterialMesh2dBundle { mesh: meshes.add(Circle::new(100.0)).into(), material: materials.add(Color::srgb(7.5, 0.0, 7.5)), transform: Transform::from_translation(Vec3::new(-200., 0., 0.)), ..default() }); ``` Now: ```rust commands.spawn(( Mesh2d(meshes.add(Circle::new(100.0))), MeshMaterial2d(materials.add(Color::srgb(7.5, 0.0, 7.5))), Transform::from_translation(Vec3::new(-200., 0., 0.)), )); ``` If the mesh material is missing, previously nothing was rendered. Now, it renders a white default `ColorMaterial` in 2D and a `StandardMaterial` in 3D (this can be overridden). Below, only every other entity has a material:   Why white? This is still open for discussion, but I think white makes sense for a *default* material, while *invalid* asset handles pointing to nothing should have something like a pink material to indicate that something is broken (I don't handle that in this PR yet). This is kind of a mix of Godot and Unity: Godot just renders a white material for non-existent materials, while Unity renders nothing when no materials exist, but renders pink for invalid materials. I can also change the default material to pink if that is preferable though. ## Testing I ran some 2D and 3D examples to test if anything changed visually. I have not tested all examples or features yet however. If anyone wants to test more extensively, it would be appreciated! ## Implementation Notes - The relationship between `bevy_render` and `bevy_pbr` is weird here. `bevy_render` needs `Mesh3d` for its own systems, but `bevy_pbr` has all of the material logic, and `bevy_render` doesn't depend on it. I feel like the two crates should be refactored in some way, but I think that's out of scope for this PR. - I didn't migrate meshlets to required components yet. That can probably be done in a follow-up, as this is already a huge PR. - It is becoming increasingly clear to me that we really, *really* want to disallow raw asset handles as components. They caused me a *ton* of headache here already, and it took me a long time to find every place that queried for them or inserted them directly on entities, since there were no compiler errors for it. If we don't remove the `Component` derive, I expect raw asset handles to be a *huge* footgun for users as we transition to wrapper components, especially as handles as components have been the norm so far. I personally consider this to be a blocker for 0.15: we need to migrate to wrapper components for asset handles everywhere, and remove the `Component` derive. Also see https://github.com/bevyengine/bevy/issues/14124. --- ## Migration Guide Asset handles for meshes and mesh materials must now be wrapped in the `Mesh2d` and `MeshMaterial2d` or `Mesh3d` and `MeshMaterial3d` components for 2D and 3D respectively. Raw handles as components no longer render meshes. Additionally, `MaterialMesh2dBundle`, `MaterialMeshBundle`, and `PbrBundle` have been deprecated. Instead, use the mesh and material components directly. Previously: ```rust commands.spawn(MaterialMesh2dBundle { mesh: meshes.add(Circle::new(100.0)).into(), material: materials.add(Color::srgb(7.5, 0.0, 7.5)), transform: Transform::from_translation(Vec3::new(-200., 0., 0.)), ..default() }); ``` Now: ```rust commands.spawn(( Mesh2d(meshes.add(Circle::new(100.0))), MeshMaterial2d(materials.add(Color::srgb(7.5, 0.0, 7.5))), Transform::from_translation(Vec3::new(-200., 0., 0.)), )); ``` If the mesh material is missing, a white default material is now used. Previously, nothing was rendered if the material was missing. The `WithMesh2d` and `WithMesh3d` query filter type aliases have also been removed. Simply use `With<Mesh2d>` or `With<Mesh3d>`. --------- Co-authored-by: Tim Blackbird <justthecooldude@gmail.com> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
107 lines
3.3 KiB
Rust
107 lines
3.3 KiB
Rust
use crate::Material;
|
|
use bevy_asset::{AssetId, Handle};
|
|
use bevy_derive::{Deref, DerefMut};
|
|
use bevy_ecs::{component::Component, reflect::ReflectComponent};
|
|
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
|
|
|
/// A [material](Material) for a [`Mesh3d`].
|
|
///
|
|
/// See [`Material`] for general information about 3D materials and how to implement your own materials.
|
|
///
|
|
/// [`Mesh3d`]: bevy_render::mesh::Mesh3d
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// # use bevy_pbr::{Material, MeshMaterial3d, StandardMaterial};
|
|
/// # use bevy_ecs::prelude::*;
|
|
/// # use bevy_render::mesh::{Mesh, Mesh3d};
|
|
/// # use bevy_color::palettes::basic::RED;
|
|
/// # use bevy_asset::Assets;
|
|
/// # use bevy_math::primitives::Capsule3d;
|
|
/// #
|
|
/// // Spawn an entity with a mesh using `StandardMaterial`.
|
|
/// fn setup(
|
|
/// mut commands: Commands,
|
|
/// mut meshes: ResMut<Assets<Mesh>>,
|
|
/// mut materials: ResMut<Assets<StandardMaterial>>,
|
|
/// ) {
|
|
/// commands.spawn((
|
|
/// Mesh3d(meshes.add(Capsule3d::default())),
|
|
/// MeshMaterial3d(materials.add(StandardMaterial {
|
|
/// base_color: RED.into(),
|
|
/// ..Default::default()
|
|
/// })),
|
|
/// ));
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// ## 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)]
|
|
#[reflect(Component, Default)]
|
|
#[require(HasMaterial3d)]
|
|
pub struct MeshMaterial3d<M: Material>(pub Handle<M>);
|
|
|
|
impl<M: Material> Default for MeshMaterial3d<M> {
|
|
fn default() -> Self {
|
|
Self(Handle::default())
|
|
}
|
|
}
|
|
|
|
impl<M: Material> From<Handle<M>> for MeshMaterial3d<M> {
|
|
fn from(handle: Handle<M>) -> Self {
|
|
Self(handle)
|
|
}
|
|
}
|
|
|
|
impl<M: Material> From<MeshMaterial3d<M>> for AssetId<M> {
|
|
fn from(material: MeshMaterial3d<M>) -> Self {
|
|
material.id()
|
|
}
|
|
}
|
|
|
|
impl<M: Material> From<&MeshMaterial3d<M>> for AssetId<M> {
|
|
fn from(material: &MeshMaterial3d<M>) -> Self {
|
|
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;
|