# Objective
- I hated having to do `Cuboid::new(1.0, 1.0, 1.0)` or
`Cuboid::from_size(Vec3::splat(1.0))` when there should be a much easier
way to do this.
## Solution
- Implemented a `from_length()` method that only takes in a single
float, and constructs a primitive of equal size in all directions.
- Ex:
```rs
// These:
Cuboid::new(1.0, 1.0, 1.0);
Cuboid::from_size(Vec3::splat(1.0));
// Are equivalent to this:
Cuboid::from_length(1.0);
```
- For the rest of the changed primitives:
```rs
Rectangle::from_length(1.0);
Plane3d::default().mesh().from_length(1.0);
```
121 lines
3.4 KiB
Rust
121 lines
3.4 KiB
Rust
use bevy_math::{
|
|
primitives::{Direction3d, Plane3d},
|
|
Quat, Vec2, Vec3,
|
|
};
|
|
use wgpu::PrimitiveTopology;
|
|
|
|
use crate::{
|
|
mesh::{Indices, Mesh, Meshable},
|
|
render_asset::RenderAssetUsages,
|
|
};
|
|
|
|
/// A builder used for creating a [`Mesh`] with a [`Plane3d`] shape.
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct PlaneMeshBuilder {
|
|
/// The [`Plane3d`] shape.
|
|
pub plane: Plane3d,
|
|
/// Half the size of the plane mesh.
|
|
pub half_size: Vec2,
|
|
}
|
|
|
|
impl Default for PlaneMeshBuilder {
|
|
fn default() -> Self {
|
|
Self {
|
|
plane: Plane3d::default(),
|
|
half_size: Vec2::ONE,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PlaneMeshBuilder {
|
|
/// Creates a new [`PlaneMeshBuilder`] from a given normal and size.
|
|
#[inline]
|
|
pub fn new(normal: Direction3d, size: Vec2) -> Self {
|
|
Self {
|
|
plane: Plane3d { normal },
|
|
half_size: size / 2.0,
|
|
}
|
|
}
|
|
|
|
/// Creates a new [`PlaneMeshBuilder`] from the given size, with the normal pointing upwards.
|
|
#[inline]
|
|
pub fn from_size(size: Vec2) -> Self {
|
|
Self {
|
|
half_size: size / 2.0,
|
|
..Default::default()
|
|
}
|
|
}
|
|
|
|
/// Creates a new [`PlaneMeshBuilder`] from the given length, with the normal pointing upwards,
|
|
/// and the resulting [`PlaneMeshBuilder`] being a square.
|
|
#[inline]
|
|
pub fn from_length(length: f32) -> Self {
|
|
Self {
|
|
half_size: Vec2::splat(length) / 2.0,
|
|
..Default::default()
|
|
}
|
|
}
|
|
|
|
/// Sets the normal of the plane, aka the direction the plane is facing.
|
|
#[inline]
|
|
#[doc(alias = "facing")]
|
|
pub fn normal(mut self, normal: Direction3d) -> Self {
|
|
self.plane = Plane3d { normal };
|
|
self
|
|
}
|
|
|
|
/// Sets the size of the plane mesh.
|
|
#[inline]
|
|
pub fn size(mut self, width: f32, height: f32) -> Self {
|
|
self.half_size = Vec2::new(width, height) / 2.0;
|
|
self
|
|
}
|
|
|
|
/// Builds a [`Mesh`] based on the configuration in `self`.
|
|
pub fn build(&self) -> Mesh {
|
|
let rotation = Quat::from_rotation_arc(Vec3::Y, *self.plane.normal);
|
|
let positions = vec![
|
|
rotation * Vec3::new(self.half_size.x, 0.0, -self.half_size.y),
|
|
rotation * Vec3::new(-self.half_size.x, 0.0, -self.half_size.y),
|
|
rotation * Vec3::new(-self.half_size.x, 0.0, self.half_size.y),
|
|
rotation * Vec3::new(self.half_size.x, 0.0, self.half_size.y),
|
|
];
|
|
|
|
let normals = vec![self.plane.normal.to_array(); 4];
|
|
let uvs = vec![[1.0, 0.0], [0.0, 0.0], [0.0, 1.0], [1.0, 1.0]];
|
|
let indices = Indices::U32(vec![0, 1, 2, 0, 2, 3]);
|
|
|
|
Mesh::new(
|
|
PrimitiveTopology::TriangleList,
|
|
RenderAssetUsages::default(),
|
|
)
|
|
.with_inserted_indices(indices)
|
|
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
|
|
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
|
|
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
|
|
}
|
|
}
|
|
|
|
impl Meshable for Plane3d {
|
|
type Output = PlaneMeshBuilder;
|
|
|
|
fn mesh(&self) -> Self::Output {
|
|
PlaneMeshBuilder {
|
|
plane: *self,
|
|
..Default::default()
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Plane3d> for Mesh {
|
|
fn from(plane: Plane3d) -> Self {
|
|
plane.mesh().build()
|
|
}
|
|
}
|
|
|
|
impl From<PlaneMeshBuilder> for Mesh {
|
|
fn from(plane: PlaneMeshBuilder) -> Self {
|
|
plane.build()
|
|
}
|
|
}
|