gl_utils/mesh/
hemisphere.rs

1use std;
2use crate::{math, vertex};
3use super::*;
4
5/// (vertex count, index count)
6#[inline]
7pub fn lines3d_vertex_index_counts (
8  latitude_divisions : u16, longitude_divisions : u16
9) -> (u32, u32) {
10  let latitude_divisions  = latitude_divisions  as u32;
11  let longitude_divisions = longitude_divisions as u32;
12  (
13    1 + latitude_divisions  * longitude_divisions,  // vertex count
14    4 * longitude_divisions * latitude_divisions    // index count
15  )
16}
17
18impl Lines3d {
19  /// Generates a hemisphere with unit radius in the positive Z half-space
20  /// with a number of parallels equal to `latitude_divisions` and a number of
21  /// half-meridians equal to `longitude_divisions`
22  pub fn hemisphere (
23    index_offset : u32, latitude_divisions : u16, longitude_divisions : u16
24  ) -> Self {
25    use std::f32::consts::PI;
26    assert!(1 <= latitude_divisions);
27    assert!(2 <= longitude_divisions);
28    let (num_vertices, num_indices) =
29      lines3d_vertex_index_counts (latitude_divisions, longitude_divisions);
30    let latitude_divisions  = latitude_divisions  as u32;
31    let longitude_divisions = longitude_divisions as u32;
32    let num_parallels       = latitude_divisions;
33    let num_meridians       = longitude_divisions;
34    let latitude_angle      = 0.5 * (PI / latitude_divisions  as f32);
35    let longitude_angle     = 2.0 * (PI / longitude_divisions as f32);
36    let mut vertices
37      = Vec::<vertex::Vert3dInstanced>::with_capacity (num_vertices as usize);
38
39    // the "north pole"
40    vertices.push (vertex::Vert3dInstanced {
41      inst_position: math::Vector3::unit_z().into_array()
42    });
43
44    // for each parallel, generate a vertex for each meridian
45    for i in 0..num_parallels {
46      let i = i as f32 + 1.0;
47      let v = *math::Rotation3::from_angle_x (math::Rad (i * latitude_angle))
48        * math::Vector3::unit_z();
49      for j in 0..num_meridians {
50        let j = j as f32;
51        let w =
52          *math::Rotation3::from_angle_z (math::Rad (j * longitude_angle)) * v;
53        // each meridian for this parallel
54        vertices.push (vertex::Vert3dInstanced { inst_position: w.into_array() });
55      }
56    }
57    debug_assert_eq!(vertices.len(), num_vertices as usize);
58
59    let mut indices  = Vec::<u32>::with_capacity (num_indices as usize);
60    // connect north pole to first parallel
61    for i in 0..num_meridians {
62      indices.push (index_offset + 0);
63      indices.push (index_offset + 1 + i);
64    }
65    // connect each parallel with itself and the next parallel along the meridians
66    for i in 0..num_parallels {
67      let parallel_base_index = index_offset + 1 + i * num_meridians;
68      for j in 0..num_meridians {
69        indices.push (parallel_base_index + j);
70        indices.push (parallel_base_index + (j + 1) % num_meridians);
71        // only connect to the next parallel if this is not the *last* parallel
72        if i < num_parallels-1 {
73          indices.push (parallel_base_index + j);
74          indices.push (parallel_base_index + j + num_meridians);
75        }
76      }
77    }
78    debug_assert_eq!(indices.len(), num_indices as usize);
79
80    Lines3d { vertices, indices }
81  }
82}