Implementing Reflect on *MeshBuilder types (#17600)

# Objective

- Most of the `*MeshBuilder` classes are not implementing `Reflect`

## Solution

- Implementing `Reflect` for all `*MeshBuilder` were is possible.
- Make sure all `*MeshBuilder` implements `Default`.
- Adding new `MeshBuildersPlugin` that registers all `*MeshBuilder`
types.

## Testing

- `cargo run -p ci`
- Tested some examples like `3d_scene` just in case something was
broken.
This commit is contained in:
Erick Z 2025-02-03 22:53:51 +01:00 committed by GitHub
parent f22ea72db0
commit b978b13a7b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 132 additions and 17 deletions

View File

@ -12,10 +12,12 @@ use bevy_math::{
},
FloatExt, Vec2,
};
use bevy_reflect::prelude::*;
use wgpu_types::PrimitiveTopology;
/// A builder used for creating a [`Mesh`] with a [`Circle`] shape.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct CircleMeshBuilder {
/// The [`Circle`] shape.
pub circle: Circle,
@ -98,7 +100,8 @@ impl From<Circle> for Mesh {
/// It's expected that more will be added in the future, such as a variant that causes the texture to be
/// scaled to fit the bounding box of the shape, which would be good for packed textures only including the
/// portion of the circle that is needed to display.
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Reflect)]
#[reflect(Default, Debug)]
#[non_exhaustive]
pub enum CircularMeshUvMode {
/// Treats the shape as a mask over a circle of equal size and radius,
@ -119,7 +122,8 @@ impl Default for CircularMeshUvMode {
///
/// The resulting mesh will have a UV-map such that the center of the circle is
/// at the center of the texture.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct CircularSectorMeshBuilder {
/// The sector shape.
pub sector: CircularSector,
@ -256,7 +260,8 @@ impl From<CircularSector> for Mesh {
///
/// The resulting mesh will have a UV-map such that the center of the circle is
/// at the center of the texture.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct CircularSegmentMeshBuilder {
/// The segment shape.
pub segment: CircularSegment,
@ -402,6 +407,8 @@ impl From<CircularSegment> for Mesh {
///
/// You must verify that the `vertices` are not concave when constructing this type. You can
/// guarantee this by creating a [`ConvexPolygon`] first, then calling [`ConvexPolygon::mesh()`].
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Debug)]
pub struct ConvexPolygonMeshBuilder<const N: usize> {
pub vertices: [Vec2; N],
}
@ -451,11 +458,23 @@ impl<const N: usize> From<ConvexPolygon<N>> for Mesh {
}
/// A builder used for creating a [`Mesh`] with a [`RegularPolygon`] shape.
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct RegularPolygonMeshBuilder {
circumradius: f32,
sides: u32,
}
impl Default for RegularPolygonMeshBuilder {
/// Returns the default [`RegularPolygonMeshBuilder`] with six sides (a hexagon) and a circumradius of `0.5`.
fn default() -> Self {
Self {
circumradius: 0.5,
sides: 6,
}
}
}
impl RegularPolygonMeshBuilder {
/// Creates a new [`RegularPolygonMeshBuilder`] from the radius of a circumcircle and a number
/// of sides.
@ -513,7 +532,8 @@ impl From<RegularPolygon> for Mesh {
}
/// A builder used for creating a [`Mesh`] with an [`Ellipse`] shape.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct EllipseMeshBuilder {
/// The [`Ellipse`] shape.
pub ellipse: Ellipse,
@ -617,6 +637,8 @@ impl From<Ellipse> for Mesh {
}
/// A builder for creating a [`Mesh`] with an [`Annulus`] shape.
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct AnnulusMeshBuilder {
/// The [`Annulus`] shape.
pub annulus: Annulus,
@ -747,10 +769,22 @@ impl From<Annulus> for Mesh {
}
}
/// A builder for creating a [`Mesh`] with an [`Rhombus`] shape.
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct RhombusMeshBuilder {
half_diagonals: Vec2,
}
impl Default for RhombusMeshBuilder {
/// Returns the default [`RhombusMeshBuilder`] with a half-horizontal and half-vertical diagonal of `0.5`.
fn default() -> Self {
Self {
half_diagonals: Vec2::splat(0.5),
}
}
}
impl RhombusMeshBuilder {
/// Creates a new [`RhombusMeshBuilder`] from a horizontal and vertical diagonal size.
///
@ -822,6 +856,8 @@ impl From<Rhombus> for Mesh {
}
/// A builder used for creating a [`Mesh`] with a [`Triangle2d`] shape.
#[derive(Clone, Copy, Debug, Default, Reflect)]
#[reflect(Default, Debug)]
pub struct Triangle2dMeshBuilder {
triangle: Triangle2d,
}
@ -897,10 +933,21 @@ impl From<Triangle2d> for Mesh {
}
/// A builder used for creating a [`Mesh`] with a [`Rectangle`] shape.
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct RectangleMeshBuilder {
half_size: Vec2,
}
impl Default for RectangleMeshBuilder {
/// Returns the default [`RectangleMeshBuilder`] with a half-width and half-height of `0.5`.
fn default() -> Self {
Self {
half_size: Vec2::splat(0.5),
}
}
}
impl RectangleMeshBuilder {
/// Creates a new [`RectangleMeshBuilder`] from a full width and height.
///
@ -966,7 +1013,8 @@ impl From<Rectangle> for Mesh {
}
/// A builder used for creating a [`Mesh`] with a [`Capsule2d`] shape.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct Capsule2dMeshBuilder {
/// The [`Capsule2d`] shape.
pub capsule: Capsule2d,

View File

@ -1,9 +1,11 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages;
use bevy_math::{ops, primitives::Capsule3d, Vec2, Vec3};
use bevy_reflect::prelude::*;
/// Manner in which UV coordinates are distributed vertically.
#[derive(Clone, Copy, Debug, Default)]
#[derive(Clone, Copy, Debug, Default, Reflect)]
#[reflect(Default, Debug)]
pub enum CapsuleUvProfile {
/// UV space is distributed by how much of the capsule consists of the hemispheres.
#[default]
@ -16,7 +18,8 @@ pub enum CapsuleUvProfile {
}
/// A builder used for creating a [`Mesh`] with a [`Capsule3d`] shape.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct Capsule3dMeshBuilder {
/// The [`Capsule3d`] shape.
pub capsule: Capsule3d,

View File

@ -1,9 +1,11 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages;
use bevy_math::{ops, primitives::Cone, Vec3};
use bevy_reflect::prelude::*;
/// Anchoring options for [`ConeMeshBuilder`]
#[derive(Debug, Copy, Clone, Default)]
#[derive(Debug, Copy, Clone, Default, Reflect)]
#[reflect(Default, Debug)]
pub enum ConeAnchor {
#[default]
/// Midpoint between the tip of the cone and the center of its base.
@ -15,7 +17,8 @@ pub enum ConeAnchor {
}
/// A builder used for creating a [`Mesh`] with a [`Cone`] shape.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct ConeMeshBuilder {
/// The [`Cone`] shape.
pub cone: Cone,

View File

@ -1,9 +1,11 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages;
use bevy_math::{ops, primitives::ConicalFrustum, Vec3};
use bevy_reflect::prelude::*;
/// A builder used for creating a [`Mesh`] with a [`ConicalFrustum`] shape.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct ConicalFrustumMeshBuilder {
/// The [`ConicalFrustum`] shape.
pub frustum: ConicalFrustum,

View File

@ -1,12 +1,24 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages;
use bevy_math::{primitives::Cuboid, Vec3};
use bevy_reflect::prelude::*;
/// A builder used for creating a [`Mesh`] with a [`Cuboid`] shape.
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct CuboidMeshBuilder {
half_size: Vec3,
}
impl Default for CuboidMeshBuilder {
/// Returns the default [`CuboidMeshBuilder`] with a width, height, and depth of `1.0`.
fn default() -> Self {
Self {
half_size: Vec3::splat(0.5),
}
}
}
impl MeshBuilder for CuboidMeshBuilder {
fn build(&self) -> Mesh {
let min = -self.half_size;

View File

@ -1,9 +1,11 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages;
use bevy_math::{ops, primitives::Cylinder};
use bevy_reflect::prelude::*;
/// Anchoring options for [`CylinderMeshBuilder`]
#[derive(Debug, Copy, Clone, Default)]
#[derive(Debug, Copy, Clone, Default, Reflect)]
#[reflect(Default, Debug)]
pub enum CylinderAnchor {
#[default]
/// Midpoint between the top and bottom caps of the cylinder
@ -15,7 +17,8 @@ pub enum CylinderAnchor {
}
/// A builder used for creating a [`Mesh`] with a [`Cylinder`] shape.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct CylinderMeshBuilder {
/// The [`Cylinder`] shape.
pub cylinder: Cylinder,

View File

@ -1,9 +1,11 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages;
use bevy_math::{primitives::Plane3d, Dir3, Quat, Vec2, Vec3};
use bevy_reflect::prelude::*;
/// A builder used for creating a [`Mesh`] with a [`Plane3d`] shape.
#[derive(Clone, Copy, Debug, Default)]
#[derive(Clone, Copy, Debug, Default, Reflect)]
#[reflect(Default, Debug)]
pub struct PlaneMeshBuilder {
/// The [`Plane3d`] shape.
pub plane: Plane3d,

View File

@ -1,6 +1,7 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages;
use bevy_math::{ops, primitives::Sphere};
use bevy_reflect::prelude::*;
use core::f32::consts::PI;
use hexasphere::shapes::IcoSphere;
use thiserror::Error;
@ -19,7 +20,8 @@ pub enum IcosphereError {
}
/// A type of sphere mesh.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub enum SphereKind {
/// An icosphere, a spherical mesh that consists of similar sized triangles.
Ico {
@ -46,7 +48,8 @@ impl Default for SphereKind {
}
/// A builder used for creating a [`Mesh`] with an [`Sphere`] shape.
#[derive(Clone, Copy, Debug, Default)]
#[derive(Clone, Copy, Debug, Default, Reflect)]
#[reflect(Default, Debug)]
pub struct SphereMeshBuilder {
/// The [`Sphere`] shape.
pub sphere: Sphere,

View File

@ -2,8 +2,11 @@ use super::triangle3d;
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages;
use bevy_math::primitives::{Tetrahedron, Triangle3d};
use bevy_reflect::prelude::*;
/// A builder used for creating a [`Mesh`] with a [`Tetrahedron`] shape.
#[derive(Clone, Copy, Debug, Default, Reflect)]
#[reflect(Default, Debug)]
pub struct TetrahedronMeshBuilder {
tetrahedron: Tetrahedron,
}

View File

@ -1,10 +1,12 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages;
use bevy_math::{ops, primitives::Torus, Vec3};
use bevy_reflect::prelude::*;
use core::ops::RangeInclusive;
/// A builder used for creating a [`Mesh`] with a [`Torus`] shape.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct TorusMeshBuilder {
/// The [`Torus`] shape.
pub torus: Torus,

View File

@ -1,8 +1,11 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages;
use bevy_math::{primitives::Triangle3d, Vec3};
use bevy_reflect::prelude::*;
/// A builder used for creating a [`Mesh`] with a [`Triangle3d`] shape.
#[derive(Clone, Copy, Debug, Default, Reflect)]
#[reflect(Default, Debug)]
pub struct Triangle3dMeshBuilder {
triangle: Triangle3d,
}

View File

@ -24,6 +24,36 @@ use bevy_ecs::{
pub use components::{mark_3d_meshes_as_changed_if_their_assets_changed, Mesh2d, Mesh3d};
use wgpu::IndexFormat;
/// Registers all [`MeshBuilder`] types.
pub struct MeshBuildersPlugin;
impl Plugin for MeshBuildersPlugin {
fn build(&self, app: &mut App) {
// 2D Mesh builders
app.register_type::<CircleMeshBuilder>()
.register_type::<CircularSectorMeshBuilder>()
.register_type::<CircularSegmentMeshBuilder>()
.register_type::<RegularPolygonMeshBuilder>()
.register_type::<EllipseMeshBuilder>()
.register_type::<AnnulusMeshBuilder>()
.register_type::<RhombusMeshBuilder>()
.register_type::<Triangle2dMeshBuilder>()
.register_type::<RectangleMeshBuilder>()
.register_type::<Capsule2dMeshBuilder>()
// 3D Mesh builders
.register_type::<Capsule3dMeshBuilder>()
.register_type::<ConeMeshBuilder>()
.register_type::<ConicalFrustumMeshBuilder>()
.register_type::<CuboidMeshBuilder>()
.register_type::<CylinderMeshBuilder>()
.register_type::<PlaneMeshBuilder>()
.register_type::<SphereMeshBuilder>()
.register_type::<TetrahedronMeshBuilder>()
.register_type::<TorusMeshBuilder>()
.register_type::<Triangle3dMeshBuilder>();
}
}
/// Adds the [`Mesh`] as an asset and makes sure that they are extracted and prepared for the GPU.
pub struct MeshPlugin;
@ -35,6 +65,7 @@ impl Plugin for MeshPlugin {
.register_type::<Mesh3d>()
.register_type::<skinning::SkinnedMesh>()
.register_type::<Vec<Entity>>()
.add_plugins(MeshBuildersPlugin)
// 'Mesh' must be prepared after 'Image' as meshes rely on the morph target image being ready
.add_plugins(RenderAssetPlugin::<RenderMesh, GpuImage>::default())
.add_plugins(MeshAllocatorPlugin)