bevy_mesh/primitives/dim3/
torus.rs1use crate::{Indices, Mesh, MeshBuilder, Meshable};
2use bevy_asset::RenderAssetUsages;
3use bevy_math::{ops, primitives::Torus, Vec3};
4use core::ops::RangeInclusive;
5use wgpu::PrimitiveTopology;
6
7#[derive(Clone, Debug)]
9pub struct TorusMeshBuilder {
10 pub torus: Torus,
12 pub minor_resolution: usize,
17 pub major_resolution: usize,
24 pub angle_range: RangeInclusive<f32>,
26}
27
28impl Default for TorusMeshBuilder {
29 fn default() -> Self {
30 Self {
31 torus: Torus::default(),
32 minor_resolution: 24,
33 major_resolution: 32,
34 angle_range: (0.0..=2.0 * core::f32::consts::PI),
35 }
36 }
37}
38
39impl TorusMeshBuilder {
40 #[inline]
45 pub fn new(inner_radius: f32, outer_radius: f32) -> Self {
46 Self {
47 torus: Torus::new(inner_radius, outer_radius),
48 ..Default::default()
49 }
50 }
51
52 #[inline]
55 pub const fn minor_resolution(mut self, resolution: usize) -> Self {
56 self.minor_resolution = resolution;
57 self
58 }
59
60 #[inline]
65 pub const fn major_resolution(mut self, resolution: usize) -> Self {
66 self.major_resolution = resolution;
67 self
68 }
69
70 #[inline]
72 pub const fn angle_range(mut self, range: RangeInclusive<f32>) -> Self {
73 self.angle_range = range;
74 self
75 }
76}
77
78impl MeshBuilder for TorusMeshBuilder {
79 fn build(&self) -> Mesh {
80 let n_vertices = (self.major_resolution + 1) * (self.minor_resolution + 1);
83 let mut positions: Vec<[f32; 3]> = Vec::with_capacity(n_vertices);
84 let mut normals: Vec<[f32; 3]> = Vec::with_capacity(n_vertices);
85 let mut uvs: Vec<[f32; 2]> = Vec::with_capacity(n_vertices);
86
87 let start_angle = self.angle_range.start();
88 let end_angle = self.angle_range.end();
89
90 let segment_stride = (end_angle - start_angle) / self.major_resolution as f32;
91 let side_stride = 2.0 * core::f32::consts::PI / self.minor_resolution as f32;
92
93 for segment in 0..=self.major_resolution {
94 let theta = start_angle + segment_stride * segment as f32;
95
96 for side in 0..=self.minor_resolution {
97 let phi = side_stride * side as f32;
98 let (sin_theta, cos_theta) = ops::sin_cos(theta);
99 let (sin_phi, cos_phi) = ops::sin_cos(phi);
100 let radius = self.torus.major_radius + self.torus.minor_radius * cos_phi;
101
102 let position = Vec3::new(
103 cos_theta * radius,
104 self.torus.minor_radius * sin_phi,
105 sin_theta * radius,
106 );
107
108 let center = Vec3::new(
109 self.torus.major_radius * cos_theta,
110 0.,
111 self.torus.major_radius * sin_theta,
112 );
113 let normal = (position - center).normalize();
114
115 positions.push(position.into());
116 normals.push(normal.into());
117 uvs.push([
118 segment as f32 / self.major_resolution as f32,
119 side as f32 / self.minor_resolution as f32,
120 ]);
121 }
122 }
123
124 let n_faces = (self.major_resolution) * (self.minor_resolution);
125 let n_triangles = n_faces * 2;
126 let n_indices = n_triangles * 3;
127
128 let mut indices: Vec<u32> = Vec::with_capacity(n_indices);
129
130 let n_vertices_per_row = self.minor_resolution + 1;
131 for segment in 0..self.major_resolution {
132 for side in 0..self.minor_resolution {
133 let lt = side + segment * n_vertices_per_row;
134 let rt = (side + 1) + segment * n_vertices_per_row;
135
136 let lb = side + (segment + 1) * n_vertices_per_row;
137 let rb = (side + 1) + (segment + 1) * n_vertices_per_row;
138
139 indices.push(lt as u32);
140 indices.push(rt as u32);
141 indices.push(lb as u32);
142
143 indices.push(rt as u32);
144 indices.push(rb as u32);
145 indices.push(lb as u32);
146 }
147 }
148
149 Mesh::new(
150 PrimitiveTopology::TriangleList,
151 RenderAssetUsages::default(),
152 )
153 .with_inserted_indices(Indices::U32(indices))
154 .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
155 .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
156 .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
157 }
158}
159
160impl Meshable for Torus {
161 type Output = TorusMeshBuilder;
162
163 fn mesh(&self) -> Self::Output {
164 TorusMeshBuilder {
165 torus: *self,
166 ..Default::default()
167 }
168 }
169}
170
171impl From<Torus> for Mesh {
172 fn from(torus: Torus) -> Self {
173 torus.mesh().build()
174 }
175}