bevy_mesh/primitives/dim3/
plane.rs

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