diff --git a/crates/bevy_render/src/mesh/shape/torus.rs b/crates/bevy_render/src/mesh/shape/torus.rs index ebb1f7531bd05..830e9738a56a4 100644 --- a/crates/bevy_render/src/mesh/shape/torus.rs +++ b/crates/bevy_render/src/mesh/shape/torus.rs @@ -2,13 +2,13 @@ use crate::{ mesh::{Indices, Mesh}, pipeline::PrimitiveTopology, }; -use bevy_math::{Quat, Vec3}; +use bevy_math::Vec3; /// A torus (donut) shape. #[derive(Debug)] pub struct Torus { pub radius: f32, - pub tube_radius: f32, + pub ring_radius: f32, pub subdivisions_segments: usize, pub subdivisions_sides: usize, } @@ -17,7 +17,7 @@ impl Default for Torus { fn default() -> Self { Torus { radius: 1.0, - tube_radius: 0.5, + ring_radius: 0.5, subdivisions_segments: 32, subdivisions_sides: 24, } @@ -26,63 +26,61 @@ impl Default for Torus { impl From for Mesh { fn from(torus: Torus) -> Self { - // code adapted from http://wiki.unity3d.com/index.php/ProceduralPrimitives#C.23_-_Torus + // code adapted from http://apparat-engine.blogspot.com/2013/04/procedural-meshes-torus.html + // (source code at https://github.com/SEilers/Apparat) let n_vertices = (torus.subdivisions_segments + 1) * (torus.subdivisions_sides + 1); let mut positions: Vec<[f32; 3]> = Vec::with_capacity(n_vertices); let mut normals: Vec<[f32; 3]> = Vec::with_capacity(n_vertices); let mut uvs: Vec<[f32; 2]> = Vec::with_capacity(n_vertices); + let segment_stride = 2.0 * std::f32::consts::PI / torus.subdivisions_segments as f32; + let side_stride = 2.0 * std::f32::consts::PI / torus.subdivisions_sides as f32; + for segment in 0..=torus.subdivisions_segments { - let t1 = - segment as f32 / torus.subdivisions_segments as f32 * 2.0 * std::f32::consts::PI; - let r1 = Vec3::new(t1.cos() * torus.radius, 0.0, t1.sin() * torus.radius); + let theta = segment_stride * segment as f32; + let segment_pos = Vec3::new(theta.cos(), 0.0, theta.sin() * torus.radius); for side in 0..=torus.subdivisions_sides { - let t2 = side as f32 / torus.subdivisions_sides as f32 * 2.0 * std::f32::consts::PI; - let r2 = Quat::from_axis_angle(Vec3::unit_y(), -t1) - * Vec3::new( - t2.sin() * torus.tube_radius, - t2.cos() * torus.tube_radius, - 0.0, - ); - - let position = r1 + r2; - let normal = r1.cross(Vec3::unit_y()).normalize(); - let uv = [ - segment as f32 / torus.subdivisions_segments as f32, - side as f32 / torus.subdivisions_sides as f32, - ]; + let phi = side_stride * side as f32; + + let x = theta.cos() * (torus.radius + torus.ring_radius * phi.cos()); + let z = theta.sin() * (torus.radius + torus.ring_radius * phi.cos()); + let y = torus.ring_radius * phi.sin(); - positions.push(position.into()); + let normal = segment_pos.cross(Vec3::unit_y()).normalize(); + + positions.push([x, y, z]); normals.push(normal.into()); - uvs.push(uv); + uvs.push([ + segment as f32 / torus.subdivisions_segments as f32, + side as f32 / torus.subdivisions_sides as f32, + ]); } } - let n_faces = (torus.subdivisions_segments + 1) * (torus.subdivisions_sides); + let n_faces = (torus.subdivisions_segments) * (torus.subdivisions_sides); let n_triangles = n_faces * 2; let n_indices = n_triangles * 3; let mut indices: Vec = Vec::with_capacity(n_indices); - for segment in 0..=torus.subdivisions_segments as u32 { - for side in 0..torus.subdivisions_sides as u32 { - let current = side + segment * (torus.subdivisions_sides as u32 + 1); + let n_vertices_per_row = torus.subdivisions_sides + 1; + for segment in 0..torus.subdivisions_segments { + for side in 0..torus.subdivisions_sides { + let lt = side + segment * n_vertices_per_row; + let rt = (side + 1) + segment * n_vertices_per_row; - let next = if segment < torus.subdivisions_segments as u32 { - (segment + 1) * (torus.subdivisions_sides as u32 + 1) - } else { - 0 - } + side; + let lb = side + (segment + 1) * n_vertices_per_row; + let rb = (side + 1) + (segment + 1) * n_vertices_per_row; - indices.push(current); - indices.push(next); - indices.push(next + 1); + indices.push(lt as u32); + indices.push(rt as u32); + indices.push(lb as u32); - indices.push(current); - indices.push(next + 1); - indices.push(current + 1); + indices.push(rt as u32); + indices.push(rb as u32); + indices.push(lb as u32); } }