bevy_render/mesh/primitives/dim3/
plane.rs1use bevy_math::{primitives::Plane3d, Dir3, Quat, Vec2, Vec3};
2use wgpu::PrimitiveTopology;
3
4use crate::{
5 mesh::{Indices, Mesh, MeshBuilder, Meshable},
6 render_asset::RenderAssetUsages,
7};
8
9#[derive(Clone, Copy, Debug, Default)]
11pub struct PlaneMeshBuilder {
12 pub plane: Plane3d,
14 pub subdivisions: u32,
24}
25
26impl PlaneMeshBuilder {
27 #[inline]
29 pub fn new(normal: Dir3, size: Vec2) -> Self {
30 Self {
31 plane: Plane3d {
32 normal,
33 half_size: size / 2.0,
34 },
35 subdivisions: 0,
36 }
37 }
38
39 #[inline]
41 pub fn from_size(size: Vec2) -> Self {
42 Self {
43 plane: Plane3d {
44 half_size: size / 2.0,
45 ..Default::default()
46 },
47 subdivisions: 0,
48 }
49 }
50
51 #[inline]
54 pub fn from_length(length: f32) -> Self {
55 Self {
56 plane: Plane3d {
57 half_size: Vec2::splat(length) / 2.0,
58 ..Default::default()
59 },
60 subdivisions: 0,
61 }
62 }
63
64 #[inline]
66 #[doc(alias = "facing")]
67 pub fn normal(mut self, normal: Dir3) -> Self {
68 self.plane = Plane3d {
69 normal,
70 ..self.plane
71 };
72 self
73 }
74
75 #[inline]
77 pub fn size(mut self, width: f32, height: f32) -> Self {
78 self.plane.half_size = Vec2::new(width, height) / 2.0;
79 self
80 }
81
82 #[inline]
92 pub fn subdivisions(mut self, subdivisions: u32) -> Self {
93 self.subdivisions = subdivisions;
94 self
95 }
96}
97
98impl MeshBuilder for PlaneMeshBuilder {
99 fn build(&self) -> Mesh {
100 let z_vertex_count = self.subdivisions + 2;
101 let x_vertex_count = self.subdivisions + 2;
102 let num_vertices = (z_vertex_count * x_vertex_count) as usize;
103 let num_indices = ((z_vertex_count - 1) * (x_vertex_count - 1) * 6) as usize;
104
105 let mut positions: Vec<Vec3> = Vec::with_capacity(num_vertices);
106 let mut normals: Vec<[f32; 3]> = Vec::with_capacity(num_vertices);
107 let mut uvs: Vec<[f32; 2]> = Vec::with_capacity(num_vertices);
108 let mut indices: Vec<u32> = Vec::with_capacity(num_indices);
109
110 let rotation = Quat::from_rotation_arc(Vec3::Y, *self.plane.normal);
111 let size = self.plane.half_size * 2.0;
112
113 for z in 0..z_vertex_count {
114 for x in 0..x_vertex_count {
115 let tx = x as f32 / (x_vertex_count - 1) as f32;
116 let tz = z as f32 / (z_vertex_count - 1) as f32;
117 let pos = rotation * Vec3::new((-0.5 + tx) * size.x, 0.0, (-0.5 + tz) * size.y);
118 positions.push(pos);
119 normals.push(self.plane.normal.to_array());
120 uvs.push([tx, tz]);
121 }
122 }
123
124 for z in 0..z_vertex_count - 1 {
125 for x in 0..x_vertex_count - 1 {
126 let quad = z * x_vertex_count + x;
127 indices.push(quad + x_vertex_count + 1);
128 indices.push(quad + 1);
129 indices.push(quad + x_vertex_count);
130 indices.push(quad);
131 indices.push(quad + x_vertex_count);
132 indices.push(quad + 1);
133 }
134 }
135
136 Mesh::new(
137 PrimitiveTopology::TriangleList,
138 RenderAssetUsages::default(),
139 )
140 .with_inserted_indices(Indices::U32(indices))
141 .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
142 .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
143 .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
144 }
145}
146
147impl Meshable for Plane3d {
148 type Output = PlaneMeshBuilder;
149
150 fn mesh(&self) -> Self::Output {
151 PlaneMeshBuilder {
152 plane: *self,
153 subdivisions: 0,
154 }
155 }
156}
157
158impl From<Plane3d> for Mesh {
159 fn from(plane: Plane3d) -> Self {
160 plane.mesh().build()
161 }
162}