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