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