solstice_2d/d3/shapes/
sphere_geometry.rs1use crate::{Geometry, Rad, Vertex3D};
2
3#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
4pub struct Sphere {
5 pub radius: f32,
6 pub width_segments: u32,
7 pub height_segments: u32,
8 pub phi_start: Rad,
9 pub phi_length: Rad,
10 pub theta_start: Rad,
11 pub theta_length: Rad,
12}
13
14impl Default for Sphere {
15 fn default() -> Self {
16 Self {
17 radius: 1.,
18 width_segments: 8,
19 height_segments: 6,
20 phi_start: Rad(0.0),
21 phi_length: Rad(std::f32::consts::PI * 2.),
22 theta_start: Rad(0.0),
23 theta_length: Rad(std::f32::consts::PI),
24 }
25 }
26}
27
28impl Sphere {
29 fn vertices(&self) -> Vec<Vertex3D> {
30 let mut vertices = vec![];
31 let theta_end = std::f32::consts::PI.min(self.theta_start.0 + self.theta_length.0);
32
33 for y in 0..=self.height_segments {
34 let v = y as f32 / self.height_segments as f32;
35
36 let u_offset = if y == 0 && self.theta_start.0 == 0. {
38 0.5 / self.width_segments as f32
39 } else if y == self.height_segments && theta_end == std::f32::consts::PI {
40 -0.5 / self.width_segments as f32
41 } else {
42 0.
43 };
44
45 for x in 0..=self.width_segments {
46 let u = x as f32 / self.width_segments as f32;
47
48 let position = nalgebra::Vector3::new(
49 -self.radius
50 * (self.phi_start.0 + u * self.phi_length.0).cos()
51 * (self.theta_start.0 + v * self.theta_length.0).sin(),
52 self.radius * (self.theta_start.0 + v * self.theta_length.0).cos(),
53 self.radius
54 * (self.phi_start.0 + u * self.phi_length.0).sin()
55 * (self.theta_start.0 + v * self.theta_length.0).sin(),
56 );
57 vertices.push(Vertex3D {
58 normal: position.normalize().into(),
59 position: position.into(),
60 uv: [u + u_offset, v],
61 color: [1., 1., 1., 1.],
62 });
63 }
64 }
65
66 vertices
67 }
68
69 fn indices(&self) -> Vec<u32> {
70 let mut indices = vec![];
71 let theta_end = std::f32::consts::PI.min(self.theta_start.0 + self.theta_length.0);
72
73 let mut index = 0;
74 let mut grid = vec![];
75 for _y in 0..=self.height_segments {
76 let mut vertices_row = vec![];
77 for _x in 0..=self.width_segments {
78 vertices_row.push(index);
79 index += 1;
80 }
81 grid.push(vertices_row);
82 }
83
84 for iy in 0..self.height_segments as usize {
85 for ix in 0..self.width_segments as usize {
86 let a = grid[iy][ix + 1];
87 let b = grid[iy][ix];
88 let c = grid[iy + 1][ix];
89 let d = grid[iy + 1][ix + 1];
90
91 if iy as u32 != 0 || self.theta_start.0 > 0. {
92 indices.extend_from_slice(&[a, b, d]);
93 }
94 if iy as u32 != self.height_segments - 1 || theta_end < std::f32::consts::PI {
95 indices.extend_from_slice(&[b, c, d]);
96 }
97 }
98 }
99
100 indices
101 }
102}
103
104impl From<&Sphere> for Geometry<'_, Vertex3D> {
105 fn from(s: &Sphere) -> Self {
106 Self::new(s.vertices(), Some(s.indices()))
107 }
108}
109
110impl From<Sphere> for Geometry<'_, Vertex3D> {
111 fn from(s: Sphere) -> Self {
112 (&s).into()
113 }
114}