Add subdivisions to PlaneMeshBuilder (#13580)

# Objective

- Plane subdivision was removed without providing an alternative

## Solution

- Add subdivision to the PlaneMeshBuilder

---

## Migration Guide

If you were using `Plane` `subdivisions`, you now need to use
`Plane3d::default().mesh().subdivisions(10)`

fixes https://github.com/bevyengine/bevy/issues/13258
This commit is contained in:
IceSentry 2024-06-03 09:57:07 -04:00 committed by GitHub
parent 52ace67f0e
commit bb51635481
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 68 additions and 13 deletions

View file

@ -11,6 +11,16 @@ use crate::{
pub struct PlaneMeshBuilder {
/// The [`Plane3d`] shape.
pub plane: Plane3d,
/// The number of subdivisions in the mesh.
///
/// 0 - is the original plane geometry, the 4 points in the XZ plane.
///
/// 1 - is split by 1 line in the middle of the plane on both the X axis and the Z axis, resulting in a plane with 4 quads / 8 triangles.
///
/// 2 - is a plane split by 2 lines on both the X and Z axes, subdividing the plane into 3 equal sections along each axis, resulting in a plane with 9 quads / 18 triangles.
///
/// and so on...
pub subdivisions: u32,
}
impl PlaneMeshBuilder {
@ -22,6 +32,7 @@ impl PlaneMeshBuilder {
normal,
half_size: size / 2.0,
},
subdivisions: 0,
}
}
@ -33,6 +44,7 @@ impl PlaneMeshBuilder {
half_size: size / 2.0,
..Default::default()
},
subdivisions: 0,
}
}
@ -45,6 +57,7 @@ impl PlaneMeshBuilder {
half_size: Vec2::splat(length) / 2.0,
..Default::default()
},
subdivisions: 0,
}
}
@ -65,27 +78,66 @@ impl PlaneMeshBuilder {
self.plane.half_size = Vec2::new(width, height) / 2.0;
self
}
/// Sets the subdivisions of the plane mesh.
///
/// 0 - is the original plane geometry, the 4 points in the XZ plane.
///
/// 1 - is split by 1 line in the middle of the plane on both the X axis and the Z axis,
/// resulting in a plane with 4 quads / 8 triangles.
///
/// 2 - is a plane split by 2 lines on both the X and Z axes, subdividing the plane into 3
/// equal sections along each axis, resulting in a plane with 9 quads / 18 triangles.
#[inline]
pub fn subdivisions(mut self, subdivisions: u32) -> Self {
self.subdivisions = subdivisions;
self
}
}
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),
rotation * Vec3::new(-self.plane.half_size.x, 0.0, -self.plane.half_size.y),
rotation * Vec3::new(-self.plane.half_size.x, 0.0, self.plane.half_size.y),
rotation * Vec3::new(self.plane.half_size.x, 0.0, self.plane.half_size.y),
];
let z_vertex_count = self.subdivisions + 2;
let x_vertex_count = self.subdivisions + 2;
let num_vertices = (z_vertex_count * x_vertex_count) as usize;
let num_indices = ((z_vertex_count - 1) * (x_vertex_count - 1) * 6) as usize;
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]);
let mut positions: Vec<Vec3> = Vec::with_capacity(num_vertices);
let mut normals: Vec<[f32; 3]> = Vec::with_capacity(num_vertices);
let mut uvs: Vec<[f32; 2]> = Vec::with_capacity(num_vertices);
let mut indices: Vec<u32> = Vec::with_capacity(num_indices);
let rotation = Quat::from_rotation_arc(Vec3::Y, *self.plane.normal);
let size = self.plane.half_size * 2.0;
for z in 0..z_vertex_count {
for x in 0..x_vertex_count {
let tx = x as f32 / (x_vertex_count - 1) as f32;
let tz = z as f32 / (z_vertex_count - 1) as f32;
let pos = rotation * Vec3::new((-0.5 + tx) * size.x, 0.0, (-0.5 + tz) * size.y);
positions.push(pos);
normals.push(self.plane.normal.to_array());
uvs.push([tx, tz]);
}
}
for z in 0..z_vertex_count - 1 {
for x in 0..x_vertex_count - 1 {
let quad = z * x_vertex_count + x;
indices.push(quad + x_vertex_count + 1);
indices.push(quad + 1);
indices.push(quad + x_vertex_count);
indices.push(quad);
indices.push(quad + x_vertex_count);
indices.push(quad + 1);
}
}
Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::default(),
)
.with_inserted_indices(indices)
.with_inserted_indices(Indices::U32(indices))
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
@ -96,7 +148,10 @@ impl Meshable for Plane3d {
type Output = PlaneMeshBuilder;
fn mesh(&self) -> Self::Output {
PlaneMeshBuilder { plane: *self }
PlaneMeshBuilder {
plane: *self,
subdivisions: 0,
}
}
}

View file

@ -86,7 +86,7 @@ fn setup(
// ground plane
commands.spawn(PbrBundle {
mesh: meshes.add(Plane3d::default().mesh().size(50.0, 50.0)),
mesh: meshes.add(Plane3d::default().mesh().size(50.0, 50.0).subdivisions(10)),
material: materials.add(Color::from(SILVER)),
..default()
});