mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Common MeshBuilder
trait (#13411)
# Objective - All `ShapeMeshBuilder`s have some methods/implementations in common. These are `fn build(&self) -> Mesh` and this implementation: ```rust impl From<ShapeMeshBuilder> for Mesh { fn from(builder: ShapeMeshBuilder) -> { builder.build() } } ``` - For the sake of consistency, these can be moved into a shared trait ## Solution - Add `trait MeshBuilder` containing a `fn build(&self) -> Mesh` and implementing `MeshBuilder for ShapeMeshBuilder` - Implement `From<T: MeshBuilder> for Mesh` ## Migration Guide - When calling `.build()` you need to import `bevy_render::mesh::primitives::MeshBuilder`
This commit is contained in:
parent
ee6dfd35c9
commit
450a9202d0
9 changed files with 66 additions and 101 deletions
|
@ -43,7 +43,7 @@ pub mod prelude {
|
|||
Camera, ClearColor, ClearColorConfig, OrthographicProjection, PerspectiveProjection,
|
||||
Projection,
|
||||
},
|
||||
mesh::{morph::MorphWeights, primitives::Meshable, Mesh},
|
||||
mesh::{morph::MorphWeights, primitives::MeshBuilder, primitives::Meshable, Mesh},
|
||||
render_resource::Shader,
|
||||
spatial_bundle::SpatialBundle,
|
||||
texture::{image_texture_conversion::IntoDynamicImageError, Image, ImagePlugin},
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
render_asset::RenderAssetUsages,
|
||||
};
|
||||
|
||||
use super::Meshable;
|
||||
use super::{MeshBuilder, Meshable};
|
||||
use bevy_math::primitives::{
|
||||
Annulus, Capsule2d, Circle, Ellipse, Rectangle, RegularPolygon, Triangle2d, Triangle3d,
|
||||
WindingOrder,
|
||||
|
@ -48,9 +48,10 @@ impl CircleMeshBuilder {
|
|||
self.resolution = resolution;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a [`Mesh`] based on the configuration in `self`.
|
||||
pub fn build(&self) -> Mesh {
|
||||
impl MeshBuilder for CircleMeshBuilder {
|
||||
fn build(&self) -> Mesh {
|
||||
RegularPolygon::new(self.circle.radius, self.resolution).mesh()
|
||||
}
|
||||
}
|
||||
|
@ -72,12 +73,6 @@ impl From<Circle> for Mesh {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<CircleMeshBuilder> for Mesh {
|
||||
fn from(circle: CircleMeshBuilder) -> Self {
|
||||
circle.build()
|
||||
}
|
||||
}
|
||||
|
||||
impl Meshable for RegularPolygon {
|
||||
type Output = Mesh;
|
||||
|
||||
|
@ -133,9 +128,10 @@ impl EllipseMeshBuilder {
|
|||
self.resolution = resolution;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a [`Mesh`] based on the configuration in `self`.
|
||||
pub fn build(&self) -> Mesh {
|
||||
impl MeshBuilder for EllipseMeshBuilder {
|
||||
fn build(&self) -> Mesh {
|
||||
let mut indices = Vec::with_capacity((self.resolution - 2) * 3);
|
||||
let mut positions = Vec::with_capacity(self.resolution);
|
||||
let normals = vec![[0.0, 0.0, 1.0]; self.resolution];
|
||||
|
@ -188,12 +184,6 @@ impl From<Ellipse> for Mesh {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<EllipseMeshBuilder> for Mesh {
|
||||
fn from(ellipse: EllipseMeshBuilder) -> Self {
|
||||
ellipse.build()
|
||||
}
|
||||
}
|
||||
|
||||
/// A builder for creating a [`Mesh`] with an [`Annulus`] shape.
|
||||
pub struct AnnulusMeshBuilder {
|
||||
/// The [`Annulus`] shape.
|
||||
|
@ -229,9 +219,10 @@ impl AnnulusMeshBuilder {
|
|||
self.resolution = resolution;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a [`Mesh`] based on the configuration in `self`.
|
||||
pub fn build(&self) -> Mesh {
|
||||
impl MeshBuilder for AnnulusMeshBuilder {
|
||||
fn build(&self) -> Mesh {
|
||||
let inner_radius = self.annulus.inner_circle.radius;
|
||||
let outer_radius = self.annulus.outer_circle.radius;
|
||||
|
||||
|
@ -306,12 +297,6 @@ impl From<Annulus> for Mesh {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<AnnulusMeshBuilder> for Mesh {
|
||||
fn from(builder: AnnulusMeshBuilder) -> Self {
|
||||
builder.build()
|
||||
}
|
||||
}
|
||||
|
||||
impl Meshable for Triangle2d {
|
||||
type Output = Mesh;
|
||||
|
||||
|
@ -423,9 +408,10 @@ impl Capsule2dMeshBuilder {
|
|||
self.resolution = resolution;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a [`Mesh`] based on the configuration in `self`.
|
||||
pub fn build(&self) -> Mesh {
|
||||
impl MeshBuilder for Capsule2dMeshBuilder {
|
||||
fn build(&self) -> Mesh {
|
||||
// The resolution is the number of vertices for one semicircle
|
||||
let resolution = self.resolution as u32;
|
||||
let vertex_count = 2 * self.resolution;
|
||||
|
@ -517,12 +503,6 @@ impl From<Capsule2d> for Mesh {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Capsule2dMeshBuilder> for Mesh {
|
||||
fn from(capsule: Capsule2dMeshBuilder) -> Self {
|
||||
capsule.build()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bevy_math::primitives::RegularPolygon;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
mesh::{Indices, Mesh, Meshable},
|
||||
mesh::{Indices, Mesh, MeshBuilder, Meshable},
|
||||
render_asset::RenderAssetUsages,
|
||||
};
|
||||
use bevy_math::{primitives::Capsule3d, Vec2, Vec3};
|
||||
|
@ -91,9 +91,10 @@ impl Capsule3dMeshBuilder {
|
|||
self.uv_profile = uv_profile;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a [`Mesh`] based on the configuration in `self`.
|
||||
pub fn build(&self) -> Mesh {
|
||||
impl MeshBuilder for Capsule3dMeshBuilder {
|
||||
fn build(&self) -> Mesh {
|
||||
// code adapted from https://behreajj.medium.com/making-a-capsule-mesh-via-script-in-five-3d-environments-c2214abf02db
|
||||
let Capsule3dMeshBuilder {
|
||||
capsule,
|
||||
|
@ -437,9 +438,3 @@ impl From<Capsule3d> for Mesh {
|
|||
capsule.mesh().build()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Capsule3dMeshBuilder> for Mesh {
|
||||
fn from(capsule: Capsule3dMeshBuilder) -> Self {
|
||||
capsule.build()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use bevy_math::{primitives::Cone, Vec3};
|
|||
use wgpu::PrimitiveTopology;
|
||||
|
||||
use crate::{
|
||||
mesh::{Indices, Mesh, Meshable},
|
||||
mesh::{Indices, Mesh, MeshBuilder, Meshable},
|
||||
render_asset::RenderAssetUsages,
|
||||
};
|
||||
|
||||
|
@ -43,9 +43,10 @@ impl ConeMeshBuilder {
|
|||
self.resolution = resolution;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a [`Mesh`] based on the configuration in `self`.
|
||||
pub fn build(&self) -> Mesh {
|
||||
impl MeshBuilder for ConeMeshBuilder {
|
||||
fn build(&self) -> Mesh {
|
||||
let half_height = self.cone.height / 2.0;
|
||||
|
||||
// `resolution` vertices for the base, `resolution` vertices for the bottom of the lateral surface,
|
||||
|
@ -157,17 +158,11 @@ impl From<Cone> for Mesh {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ConeMeshBuilder> for Mesh {
|
||||
fn from(cone: ConeMeshBuilder) -> Self {
|
||||
cone.build()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bevy_math::{primitives::Cone, Vec2};
|
||||
|
||||
use crate::mesh::{Mesh, Meshable, VertexAttributeValues};
|
||||
use crate::mesh::{primitives::MeshBuilder, Mesh, Meshable, VertexAttributeValues};
|
||||
|
||||
/// Rounds floats to handle floating point error in tests.
|
||||
fn round_floats<const N: usize>(points: &mut [[f32; N]]) {
|
||||
|
|
|
@ -2,7 +2,7 @@ use bevy_math::primitives::Cylinder;
|
|||
use wgpu::PrimitiveTopology;
|
||||
|
||||
use crate::{
|
||||
mesh::{Indices, Mesh, Meshable},
|
||||
mesh::{Indices, Mesh, MeshBuilder, Meshable},
|
||||
render_asset::RenderAssetUsages,
|
||||
};
|
||||
|
||||
|
@ -58,9 +58,10 @@ impl CylinderMeshBuilder {
|
|||
self.segments = segments;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a [`Mesh`] based on the configuration in `self`.
|
||||
pub fn build(&self) -> Mesh {
|
||||
impl MeshBuilder for CylinderMeshBuilder {
|
||||
fn build(&self) -> Mesh {
|
||||
let resolution = self.resolution;
|
||||
let segments = self.segments;
|
||||
|
||||
|
@ -176,9 +177,3 @@ impl From<Cylinder> for Mesh {
|
|||
cylinder.mesh().build()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CylinderMeshBuilder> for Mesh {
|
||||
fn from(cylinder: CylinderMeshBuilder) -> Self {
|
||||
cylinder.build()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use bevy_math::{primitives::Plane3d, Dir3, Quat, Vec2, Vec3};
|
|||
use wgpu::PrimitiveTopology;
|
||||
|
||||
use crate::{
|
||||
mesh::{Indices, Mesh, Meshable},
|
||||
mesh::{Indices, Mesh, MeshBuilder, Meshable},
|
||||
render_asset::RenderAssetUsages,
|
||||
};
|
||||
|
||||
|
@ -65,9 +65,10 @@ impl PlaneMeshBuilder {
|
|||
self.plane.half_size = Vec2::new(width, height) / 2.0;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a [`Mesh`] based on the configuration in `self`.
|
||||
pub fn build(&self) -> Mesh {
|
||||
impl MeshBuilder for PlaneMeshBuilder {
|
||||
fn build(&self) -> Mesh {
|
||||
let rotation = Quat::from_rotation_arc(Vec3::Y, *self.plane.normal);
|
||||
let positions = vec![
|
||||
rotation * Vec3::new(self.plane.half_size.x, 0.0, -self.plane.half_size.y),
|
||||
|
@ -104,9 +105,3 @@ impl From<Plane3d> for Mesh {
|
|||
plane.mesh().build()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PlaneMeshBuilder> for Mesh {
|
||||
fn from(plane: PlaneMeshBuilder) -> Self {
|
||||
plane.build()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::f32::consts::PI;
|
||||
|
||||
use crate::{
|
||||
mesh::{Indices, Mesh, Meshable},
|
||||
mesh::{Indices, Mesh, MeshBuilder, Meshable},
|
||||
render_asset::RenderAssetUsages,
|
||||
};
|
||||
use bevy_math::primitives::Sphere;
|
||||
|
@ -75,19 +75,6 @@ impl SphereMeshBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Builds a [`Mesh`] according to the configuration in `self`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the sphere is a [`SphereKind::Ico`] with a subdivision count
|
||||
/// that is greater than or equal to `80` because there will be too many vertices.
|
||||
pub fn build(&self) -> Mesh {
|
||||
match self.kind {
|
||||
SphereKind::Ico { subdivisions } => self.ico(subdivisions).unwrap(),
|
||||
SphereKind::Uv { sectors, stacks } => self.uv(sectors, stacks),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an icosphere mesh with the given number of subdivisions.
|
||||
///
|
||||
/// The number of faces quadruples with each subdivision.
|
||||
|
@ -244,6 +231,21 @@ impl SphereMeshBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
impl MeshBuilder for SphereMeshBuilder {
|
||||
/// Builds a [`Mesh`] according to the configuration in `self`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the sphere is a [`SphereKind::Ico`] with a subdivision count
|
||||
/// that is greater than or equal to `80` because there will be too many vertices.
|
||||
fn build(&self) -> Mesh {
|
||||
match self.kind {
|
||||
SphereKind::Ico { subdivisions } => self.ico(subdivisions).unwrap(),
|
||||
SphereKind::Uv { sectors, stacks } => self.uv(sectors, stacks),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Meshable for Sphere {
|
||||
type Output = SphereMeshBuilder;
|
||||
|
||||
|
@ -260,9 +262,3 @@ impl From<Sphere> for Mesh {
|
|||
sphere.mesh().build()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SphereMeshBuilder> for Mesh {
|
||||
fn from(sphere: SphereMeshBuilder) -> Self {
|
||||
sphere.build()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use bevy_math::{primitives::Torus, Vec3};
|
|||
use wgpu::PrimitiveTopology;
|
||||
|
||||
use crate::{
|
||||
mesh::{Indices, Mesh, Meshable},
|
||||
mesh::{Indices, Mesh, MeshBuilder, Meshable},
|
||||
render_asset::RenderAssetUsages,
|
||||
};
|
||||
|
||||
|
@ -65,9 +65,10 @@ impl TorusMeshBuilder {
|
|||
self.major_resolution = resolution;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a [`Mesh`] according to the configuration in `self`.
|
||||
pub fn build(&self) -> Mesh {
|
||||
impl MeshBuilder for TorusMeshBuilder {
|
||||
fn build(&self) -> Mesh {
|
||||
// code adapted from http://apparat-engine.blogspot.com/2013/04/procedural-meshes-torus.html
|
||||
|
||||
let n_vertices = (self.major_resolution + 1) * (self.minor_resolution + 1);
|
||||
|
@ -158,9 +159,3 @@ impl From<Torus> for Mesh {
|
|||
torus.mesh().build()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TorusMeshBuilder> for Mesh {
|
||||
fn from(torus: TorusMeshBuilder) -> Self {
|
||||
torus.build()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,12 +25,26 @@ pub use dim2::{CircleMeshBuilder, EllipseMeshBuilder};
|
|||
mod dim3;
|
||||
pub use dim3::*;
|
||||
|
||||
use super::Mesh;
|
||||
|
||||
/// A trait for shapes that can be turned into a [`Mesh`](super::Mesh).
|
||||
pub trait Meshable {
|
||||
/// The output of [`Self::mesh`]. This can either be a [`Mesh`](super::Mesh)
|
||||
/// or a builder used for creating a [`Mesh`](super::Mesh).
|
||||
/// or a [`MeshBuilder`] used for creating a [`Mesh`](super::Mesh).
|
||||
type Output;
|
||||
|
||||
/// Creates a [`Mesh`](super::Mesh) for a shape.
|
||||
fn mesh(&self) -> Self::Output;
|
||||
}
|
||||
|
||||
/// A trait used to build [`Mesh`]es from a configuration
|
||||
pub trait MeshBuilder {
|
||||
/// Builds a [`Mesh`] based on the configuration in `self`.
|
||||
fn build(&self) -> Mesh;
|
||||
}
|
||||
|
||||
impl<T: MeshBuilder> From<T> for Mesh {
|
||||
fn from(builder: T) -> Self {
|
||||
builder.build()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue