diff --git a/crates/bevy_render/src/mesh/primitives/dim3/plane.rs b/crates/bevy_render/src/mesh/primitives/dim3/plane.rs index 2ea9fad1e35d1..5a421069b67fc 100644 --- a/crates/bevy_render/src/mesh/primitives/dim3/plane.rs +++ b/crates/bevy_render/src/mesh/primitives/dim3/plane.rs @@ -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 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 mut positions: Vec = 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 = Vec::with_capacity(num_indices); + 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 size = self.plane.half_size * 2.0; - 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]); + 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, + } } } diff --git a/examples/3d/3d_shapes.rs b/examples/3d/3d_shapes.rs index 5abbba1a05725..4663ac4a99e2c 100644 --- a/examples/3d/3d_shapes.rs +++ b/examples/3d/3d_shapes.rs @@ -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() });