Skip to main content

bevy_mesh/primitives/dim3/
plane.rs

1use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
2use bevy_asset::RenderAssetUsages;
3use bevy_math::{Dir3, Quat, Vec2, Vec3};
4use bevy_reflect::prelude::*;
5use bevy_shape::Plane3d;
6
7/// A builder used for creating a [`Mesh`] with a [`Plane3d`] shape.
8#[derive(Clone, Copy, Debug, Default, Reflect)]
9#[reflect(Default, Debug, Clone)]
10pub struct PlaneMeshBuilder {
11    /// The [`Plane3d`] shape.
12    pub plane: Plane3d,
13    /// The number of subdivisions along the X axis.
14    ///
15    /// 0 - is the original plane geometry, the 4 points in the XZ plane.
16    ///
17    /// 1 - adds a vertex in the middle of the X axis, resulting in a plane with 2 quads / 4 triangles, and a new edge along the Z axis.
18    ///
19    /// 2 - adds 2 vertices along the X axis, resulting in a plane with 3 quads / 6 triangles.
20    ///
21    /// and so on...
22    pub subdivisions_x: u32,
23
24    /// The number of subdivisions along the Z axis.
25    ///
26    /// 0 - is the original plane geometry, the 4 points in the XZ plane.
27    ///
28    /// 1 - adds a vertex in the middle of the Z axis, resulting in a plane with 2 quads / 4 triangles, and a new edge along the X axis.
29    ///
30    /// 2 - adds 2 vertices along the Z axis, resulting in a plane with 3 quads / 6 triangles.
31    ///
32    /// and so on...
33    pub subdivisions_z: u32,
34}
35
36impl PlaneMeshBuilder {
37    /// Creates a new [`PlaneMeshBuilder`] from a given normal and size.
38    #[inline]
39    pub fn new(normal: Dir3, size: Vec2) -> Self {
40        Self {
41            plane: Plane3d {
42                normal,
43                half_size: size / 2.0,
44            },
45            subdivisions_x: 0,
46            subdivisions_z: 0,
47        }
48    }
49
50    /// Creates a new [`PlaneMeshBuilder`] from the given size, with the normal pointing upwards.
51    #[inline]
52    pub fn from_size(size: Vec2) -> Self {
53        Self {
54            plane: Plane3d {
55                half_size: size / 2.0,
56                ..Default::default()
57            },
58            subdivisions_x: 0,
59            subdivisions_z: 0,
60        }
61    }
62
63    /// Creates a new [`PlaneMeshBuilder`] from the given length, with the normal pointing upwards,
64    /// and the resulting [`PlaneMeshBuilder`] being a square.
65    #[inline]
66    pub fn from_length(length: f32) -> Self {
67        Self {
68            plane: Plane3d {
69                half_size: Vec2::splat(length) / 2.0,
70                ..Default::default()
71            },
72            subdivisions_x: 0,
73            subdivisions_z: 0,
74        }
75    }
76
77    /// Sets the normal of the plane, aka the direction the plane is facing.
78    #[inline]
79    #[doc(alias = "facing")]
80    pub fn normal(mut self, normal: Dir3) -> Self {
81        self.plane = Plane3d {
82            normal,
83            ..self.plane
84        };
85        self
86    }
87
88    /// Sets the size of the plane mesh.
89    #[inline]
90    pub fn size(mut self, width: f32, height: f32) -> Self {
91        self.plane.half_size = Vec2::new(width, height) / 2.0;
92        self
93    }
94
95    /// Sets the subdivisions of the plane mesh.
96    ///
97    /// 0 - is the original plane geometry, the 4 points in the XZ plane.
98    ///
99    /// 1 - is split by 1 line in the middle of the plane on both the X axis and the Z axis,
100    ///     resulting in a plane with 4 quads / 8 triangles.
101    ///
102    /// 2 - is a plane split by 2 lines on both the X and Z axes, subdividing the plane into 3
103    ///     equal sections along each axis, resulting in a plane with 9 quads / 18 triangles.
104    #[inline]
105    pub fn subdivisions(mut self, subdivisions: u32) -> Self {
106        self.subdivisions_x = subdivisions;
107        self.subdivisions_z = subdivisions;
108        self
109    }
110
111    #[inline]
112    /// The number of subdivisions along the X axis.
113    ///
114    /// 0 - is the original plane geometry, the 4 points in the XZ plane.
115    ///
116    /// 1 - adds a vertex in the middle of the X axis, resulting in a plane with 2 quads / 4 triangles, and a new edge along the Z axis.
117    ///
118    /// 2 - adds 2 vertices along the X axis, resulting in a plane with 3 quads / 6 triangles.
119    ///
120    /// and so on...
121    pub fn subdivisions_x(mut self, subdivisions: u32) -> Self {
122        self.subdivisions_x = subdivisions;
123        self
124    }
125
126    #[inline]
127    /// The number of subdivisions along the Z axis.
128    ///
129    /// 0 - is the original plane geometry, the 4 points in the XZ plane.
130    ///
131    /// 1 - adds a vertex in the middle of the Z axis, resulting in a plane with 2 quads / 4 triangles, and a new edge along the X axis.
132    ///
133    /// 2 - adds 2 vertices along the Z axis, resulting in a plane with 3 quads / 6 triangles.
134    ///
135    /// and so on...
136    pub fn subdivisions_z(mut self, subdivisions: u32) -> Self {
137        self.subdivisions_z = subdivisions;
138        self
139    }
140}
141
142impl MeshBuilder for PlaneMeshBuilder {
143    fn build(&self) -> Mesh {
144        let z_vertex_count = self.subdivisions_z + 2;
145        let x_vertex_count = self.subdivisions_x + 2;
146        let num_vertices = (z_vertex_count * x_vertex_count) as usize;
147        let num_indices = ((z_vertex_count - 1) * (x_vertex_count - 1) * 6) as usize;
148
149        let mut positions: Vec<Vec3> = Vec::with_capacity(num_vertices);
150        let mut normals: Vec<[f32; 3]> = Vec::with_capacity(num_vertices);
151        let mut uvs: Vec<[f32; 2]> = Vec::with_capacity(num_vertices);
152        let mut indices: Vec<u32> = Vec::with_capacity(num_indices);
153
154        let rotation = Quat::from_rotation_arc(Vec3::Y, *self.plane.normal);
155        let size = self.plane.half_size * 2.0;
156
157        for z in 0..z_vertex_count {
158            for x in 0..x_vertex_count {
159                let tx = x as f32 / (x_vertex_count - 1) as f32;
160                let tz = z as f32 / (z_vertex_count - 1) as f32;
161                let pos = rotation * Vec3::new((-0.5 + tx) * size.x, 0.0, (-0.5 + tz) * size.y);
162                positions.push(pos);
163                normals.push(self.plane.normal.to_array());
164                uvs.push([tx, tz]);
165            }
166        }
167
168        for z in 0..z_vertex_count - 1 {
169            for x in 0..x_vertex_count - 1 {
170                let quad = z * x_vertex_count + x;
171                indices.push(quad + x_vertex_count + 1);
172                indices.push(quad + 1);
173                indices.push(quad + x_vertex_count);
174                indices.push(quad);
175                indices.push(quad + x_vertex_count);
176                indices.push(quad + 1);
177            }
178        }
179
180        Mesh::new(
181            PrimitiveTopology::TriangleList,
182            RenderAssetUsages::default(),
183        )
184        .with_inserted_indices(Indices::U32(indices))
185        .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
186        .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
187        .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
188    }
189}
190
191impl Meshable for Plane3d {
192    type Output = PlaneMeshBuilder;
193
194    fn mesh(&self) -> Self::Output {
195        PlaneMeshBuilder {
196            plane: *self,
197            subdivisions_x: 0,
198            subdivisions_z: 0,
199        }
200    }
201}
202
203impl From<Plane3d> for Mesh {
204    fn from(plane: Plane3d) -> Self {
205        plane.mesh().build()
206    }
207}