ncollide3d/procedural/
sphere.rs
1use super::utils;
2#[cfg(feature = "dim2")]
3use super::Polyline;
4#[cfg(feature = "dim3")]
5use super::{IndexBuffer, TriMesh};
6use na;
7#[cfg(feature = "dim3")]
8use na::{Point2, Point3, Vector3};
9use simba::scalar::RealField;
10
11#[cfg(feature = "dim3")]
13pub fn sphere<N>(
14 diameter: N,
15 ntheta_subdiv: u32,
16 nphi_subdiv: u32,
17 generate_uvs: bool,
18) -> TriMesh<N>
19where
20 N: RealField + Copy,
21{
22 let mut sphere = unit_sphere(ntheta_subdiv, nphi_subdiv, generate_uvs);
23
24 sphere.scale_by_scalar(diameter);
25
26 sphere
27}
28
29#[cfg(feature = "dim3")]
31pub fn unit_sphere<N>(ntheta_subdiv: u32, nphi_subdiv: u32, generate_uvs: bool) -> TriMesh<N>
32where
33 N: RealField + Copy,
34{
35 if generate_uvs {
36 unit_sphere_with_uvs(ntheta_subdiv, nphi_subdiv)
37 } else {
38 unit_sphere_without_uvs(ntheta_subdiv, nphi_subdiv)
39 }
40}
41
42#[cfg(feature = "dim3")]
44fn unit_sphere_without_uvs<N>(ntheta_subdiv: u32, nphi_subdiv: u32) -> TriMesh<N>
45where
46 N: RealField + Copy,
47{
48 let pi = N::pi();
49 let two_pi = N::two_pi();
50 let pi_two = N::frac_pi_2();
51 let dtheta = two_pi / na::convert(ntheta_subdiv as f64);
52 let dphi = pi / na::convert(nphi_subdiv as f64);
53
54 let mut coords = Vec::new();
55 let mut curr_phi = -pi_two + dphi;
56
57 coords.push(Point3::new(na::zero(), -na::one::<N>(), na::zero()));
59
60 for _ in 0..nphi_subdiv - 1 {
61 utils::push_circle(
62 curr_phi.cos(),
63 ntheta_subdiv,
64 dtheta,
65 curr_phi.sin(),
66 &mut coords,
67 );
68 curr_phi = curr_phi + dphi;
69 }
70
71 coords.push(Point3::new(na::zero(), na::one(), na::zero()));
72
73 let normals: Vec<Vector3<N>> = coords.iter().map(|p| p.coords).collect();
75
76 let mut idx = Vec::new();
78
79 utils::push_degenerate_top_ring_indices(1, 0, ntheta_subdiv, &mut idx);
80
81 utils::reverse_clockwising(&mut idx[..]);
82
83 for i in 0..nphi_subdiv - 2 {
84 let bottom = 1 + i * ntheta_subdiv;
85 let up = bottom + ntheta_subdiv;
86 utils::push_ring_indices(bottom, up, ntheta_subdiv, &mut idx);
87 }
88
89 utils::push_degenerate_top_ring_indices(
90 1 + (nphi_subdiv - 2) * ntheta_subdiv,
91 coords.len() as u32 - 1,
92 ntheta_subdiv,
93 &mut idx,
94 );
95
96 let mut res = TriMesh::new(coords, Some(normals), None, Some(IndexBuffer::Unified(idx)));
97
98 let _0_5: N = na::convert(0.5);
99
100 res.scale_by_scalar(_0_5);
101
102 res
103}
104
105#[cfg(feature = "dim3")]
106fn unit_sphere_with_uvs<N: RealField + Copy>(ntheta_subdiv: u32, nphi_subdiv: u32) -> TriMesh<N> {
107 let pi = N::pi();
108 let two_pi = N::two_pi();
109 let pi_two = N::frac_pi_2();
110 let duvtheta = N::one() / na::convert(ntheta_subdiv as f64); let duvphi = N::one() / na::convert(nphi_subdiv as f64); let dtheta = two_pi * duvtheta;
113 let dphi = pi * duvphi;
114
115 let mut coords = Vec::new();
116 let mut curr_phi = -pi_two;
117
118 for _ in 0..nphi_subdiv + 1 {
119 utils::push_circle(
120 curr_phi.cos(),
121 ntheta_subdiv + 1,
122 dtheta,
123 curr_phi.sin(),
124 &mut coords,
125 );
126 curr_phi = curr_phi + dphi;
127 }
128
129 let normals: Vec<Vector3<N>> = coords.iter().map(|p| p.coords).collect();
131
132 let mut idx = Vec::new();
134
135 for i in 0..nphi_subdiv {
136 let bottom = i * (ntheta_subdiv + 1);
137 let up = bottom + (ntheta_subdiv + 1);
138 utils::push_open_ring_indices(bottom, up, ntheta_subdiv + 1, &mut idx);
139 }
140
141 let mut uvs = Vec::new();
142 let mut curr_uvphi = na::zero::<N>();
143
144 for _ in 0..nphi_subdiv + 1 {
145 let mut curr_uvtheta = na::zero::<N>();
146
147 for _ in 0..ntheta_subdiv + 1 {
148 uvs.push(Point2::new(curr_uvtheta, curr_uvphi));
149 curr_uvtheta = curr_uvtheta + duvtheta;
150 }
151
152 curr_uvphi = curr_uvphi + duvphi;
153 }
154
155 let mut res = TriMesh::new(
156 coords,
157 Some(normals),
158 Some(uvs),
159 Some(IndexBuffer::Unified(idx)),
160 );
161
162 let _0_5: N = na::convert(0.5);
163 res.scale_by_scalar(_0_5);
164
165 res
166}
167
168#[cfg(feature = "dim3")]
170pub fn unit_hemisphere<N: RealField + Copy>(ntheta_subdiv: u32, nphi_subdiv: u32) -> TriMesh<N> {
171 let two_pi = N::two_pi();
172 let pi_two = N::frac_pi_2();
173 let dtheta = two_pi / na::convert(ntheta_subdiv as f64);
174 let dphi = pi_two / na::convert(nphi_subdiv as f64);
175
176 let mut coords = Vec::new();
177 let mut curr_phi = na::zero::<N>();
178
179 for _ in 0..nphi_subdiv - 1 {
180 utils::push_circle(
181 curr_phi.cos(),
182 ntheta_subdiv,
183 dtheta,
184 curr_phi.sin(),
185 &mut coords,
186 );
187 curr_phi = curr_phi + dphi;
188 }
189
190 coords.push(Point3::new(na::zero(), na::one(), na::zero()));
191
192 let mut idx = Vec::new();
193
194 for i in 0..nphi_subdiv - 2 {
195 utils::push_ring_indices(
196 i * ntheta_subdiv,
197 (i + 1) * ntheta_subdiv,
198 ntheta_subdiv,
199 &mut idx,
200 );
201 }
202
203 utils::push_degenerate_top_ring_indices(
204 (nphi_subdiv - 2) * ntheta_subdiv,
205 coords.len() as u32 - 1,
206 ntheta_subdiv,
207 &mut idx,
208 );
209
210 let normals: Vec<Vector3<N>> = coords.iter().map(|p| p.coords).collect();
212 let mut out = TriMesh::new(coords, Some(normals), None, Some(IndexBuffer::Unified(idx)));
214
215 let _0_5: N = na::convert(0.5);
217 out.scale_by_scalar(_0_5);
218
219 out
220}
221
222#[cfg(feature = "dim2")]
224pub fn circle<N: RealField + Copy>(diameter: &N, nsubdivs: u32) -> Polyline<N> {
225 let two_pi = N::two_pi();
226 let dtheta = two_pi / na::convert(nsubdivs as f64);
227
228 let mut pts = Vec::with_capacity(nsubdivs as usize);
229
230 utils::push_xy_arc(*diameter / na::convert(2.0), nsubdivs, dtheta, &mut pts);
231
232 Polyline::new(pts, None)
235}
236
237#[cfg(feature = "dim2")]
239pub fn unit_circle<N: RealField + Copy>(nsubdivs: u32) -> Polyline<N> {
240 circle(&na::convert(1.0), nsubdivs)
242}