Browse Source

Finally generating correct normals

Have to detect and correct inverted normals during calculation since the winding
order of the generated truncated icosahedrons is inconsistent.
Tyler Hallada 4 years ago
parent
commit
e0fc3c1917

File diff suppressed because it is too large
+ 1 - 1
output/hexsphere_r1_d0.json


File diff suppressed because it is too large
+ 1 - 1
output/hexsphere_r1_d1.json


File diff suppressed because it is too large
+ 1 - 1
output/hexsphere_r1_d2.json


File diff suppressed because it is too large
+ 1 - 1
output/hexsphere_r1_d3.json


File diff suppressed because it is too large
+ 1 - 1
output/hexsphere_r1_d4.json


File diff suppressed because it is too large
+ 1 - 1
output/hexsphere_r1_d5.json


File diff suppressed because it is too large
+ 1 - 1
output/hexsphere_r1_d6.json


File diff suppressed because it is too large
+ 1 - 1
output/icosahedron_r1_d0.json


File diff suppressed because it is too large
+ 1 - 1
output/icosahedron_r1_d1.json


File diff suppressed because it is too large
+ 1 - 1
output/icosahedron_r1_d2.json


File diff suppressed because it is too large
+ 1 - 1
output/icosahedron_r1_d3.json


File diff suppressed because it is too large
+ 1 - 1
output/icosahedron_r1_d4.json


File diff suppressed because it is too large
+ 1 - 1
output/icosahedron_r1_d5.json


File diff suppressed because it is too large
+ 1 - 1
output/icosahedron_r1_d6.json


File diff suppressed because it is too large
+ 1 - 1
output/icosahedron_r1_d7.json


+ 138 - 19
src/main.rs

@@ -3,6 +3,7 @@ extern crate cgmath;
3 3
 use std::collections::HashMap;
4 4
 use std::fs::File;
5 5
 use std::io::Write;
6
+use std::ops::AddAssign;
6 7
 use std::path::Path;
7 8
 
8 9
 use cgmath::prelude::*;
@@ -46,8 +47,10 @@ struct ArraySerializedVector(Vector3<f32>);
46 47
 struct Polyhedron {
47 48
     positions: Vec<ArraySerializedVector>,
48 49
     cells: Vec<Triangle>,
50
+    normals: Vec<ArraySerializedVector>,
49 51
     #[serde(skip)]
50 52
     added_vert_cache: HashMap<(i32, i32, i32), usize>,
53
+    faces: Vec<Vec<usize>>,
51 54
 }
52 55
 
53 56
 impl Serialize for ArraySerializedVector {
@@ -64,12 +67,20 @@ impl Serialize for ArraySerializedVector {
64 67
     }
65 68
 }
66 69
 
70
+impl AddAssign for ArraySerializedVector {
71
+    fn add_assign(&mut self, other: Self) {
72
+        *self = Self(self.0 + other.0);
73
+    }
74
+}
75
+
67 76
 impl Polyhedron {
68 77
     fn new() -> Polyhedron {
69 78
         Polyhedron {
70 79
             positions: vec![],
71 80
             cells: vec![],
81
+            normals: vec![],
72 82
             added_vert_cache: HashMap::new(),
83
+            faces: vec![],
73 84
         }
74 85
     }
75 86
 
@@ -99,7 +110,9 @@ impl Polyhedron {
99 110
                 Triangle::new(8, 6, 7),
100 111
                 Triangle::new(9, 8, 1),
101 112
             ],
113
+            normals: vec![],
102 114
             added_vert_cache: HashMap::new(),
115
+            faces: vec![],
103 116
         };
104 117
         base_isocahedron.add_position(Vector3::new(-1.0, t, 0.0));
105 118
         base_isocahedron.add_position(Vector3::new(1.0, t, 0.0));
@@ -119,11 +132,11 @@ impl Polyhedron {
119 132
         subdivided
120 133
     }
121 134
 
122
-    fn new_dual_isocahedron(radius: f32, detail: usize) -> Polyhedron {
135
+    fn new_truncated_isocahedron(radius: f32, detail: usize) -> Polyhedron {
123 136
         let isocahedron = Polyhedron::new_isocahedron(radius, detail);
124
-        let mut dual_isocahedron = Polyhedron::new();
125
-        dual_isocahedron.dual(isocahedron);
126
-        dual_isocahedron
137
+        let mut truncated_isocahedron = Polyhedron::new();
138
+        truncated_isocahedron.truncated(isocahedron);
139
+        truncated_isocahedron
127 140
     }
128 141
 
129 142
     fn subdivide(&mut self, other: Polyhedron, radius: f32, detail: usize) {
@@ -192,19 +205,22 @@ impl Polyhedron {
192 205
             return *added_vert_index;
193 206
         } else {
194 207
             self.positions.push(ArraySerializedVector(vertex));
208
+            self.normals
209
+                .push(ArraySerializedVector(Vector3::new(0.0, 0.0, 0.0)));
195 210
             let added_index = self.positions.len() - 1;
196 211
             self.added_vert_cache.insert(vertex_key, added_index);
197 212
             return added_index;
198 213
         }
199 214
     }
200 215
 
201
-    fn dual(&mut self, other: Polyhedron) {
216
+    fn truncated(&mut self, other: Polyhedron) {
202 217
         let vert_to_faces = other.vert_to_faces();
203 218
         let original_vert_count = other.positions.len();
204 219
         let triangle_centroids = other.triangle_centroids();
205
-        let mut mid_centroid_cache: HashMap<(usize, usize), Vector3<f32>> = HashMap::new();
220
+        let mut mid_centroid_cache: HashMap<(usize, usize, usize), Vector3<f32>> = HashMap::new();
206 221
         let mut hex_count = 0;
207 222
         let mut pent_count = 0;
223
+        let mut count = 0;
208 224
         for i in 0..original_vert_count {
209 225
             let faces = &vert_to_faces[&i];
210 226
             if faces.len() == 6 {
@@ -215,7 +231,9 @@ impl Polyhedron {
215 231
 
216 232
             let center_point = find_center_of_triangles(faces, &triangle_centroids);
217 233
 
218
-            for face_index in faces {
234
+            let mut new_face = Vec::new();
235
+
236
+            for face_index in faces.iter().rev() {
219 237
                 let triangle = &other.cells[*face_index];
220 238
                 let other_verts: Vec<usize> = vec![triangle.a, triangle.b, triangle.c]
221 239
                     .drain(..)
@@ -225,15 +243,19 @@ impl Polyhedron {
225 243
 
226 244
                 let centroid = triangle_centroids[face_index];
227 245
                 let mid_b_centroid = other.calculate_mid_centroid(
246
+                    sorted_triangle.a,
228 247
                     sorted_triangle.b,
229 248
                     faces,
249
+                    *face_index,
230 250
                     centroid,
231 251
                     &triangle_centroids,
232 252
                     &mut mid_centroid_cache,
233 253
                 );
234 254
                 let mid_c_centroid = other.calculate_mid_centroid(
255
+                    sorted_triangle.a,
235 256
                     sorted_triangle.c,
236 257
                     faces,
258
+                    *face_index,
237 259
                     centroid,
238 260
                     &triangle_centroids,
239 261
                     &mut mid_centroid_cache,
@@ -246,15 +268,18 @@ impl Polyhedron {
246 268
 
247 269
                 self.cells.push(Triangle::new(
248 270
                     center_point_index,
271
+                    mid_c_centroid_index,
249 272
                     centroid_index,
250
-                    mid_b_centroid_index,
251 273
                 ));
274
+                new_face.push(self.cells.len() - 1);
252 275
                 self.cells.push(Triangle::new(
253 276
                     center_point_index,
254 277
                     centroid_index,
255
-                    mid_c_centroid_index,
278
+                    mid_b_centroid_index,
256 279
                 ));
280
+                new_face.push(self.cells.len() - 1);
257 281
             }
282
+            self.faces.push(new_face);
258 283
         }
259 284
         println!("hexagons: {}", hex_count);
260 285
         println!("pentagons: {}", pent_count);
@@ -299,35 +324,124 @@ impl Polyhedron {
299 324
 
300 325
     fn calculate_mid_centroid(
301 326
         &self,
327
+        spoke_vertex_index: usize,
302 328
         vertex_index: usize,
303 329
         faces: &Vec<usize>,
330
+        current_face_index: usize,
304 331
         centroid: Vector3<f32>,
305 332
         triangle_centroids: &HashMap<usize, Vector3<f32>>,
306
-        mid_centroid_cache: &mut HashMap<(usize, usize), Vector3<f32>>,
333
+        mid_centroid_cache: &mut HashMap<(usize, usize, usize), Vector3<f32>>,
307 334
     ) -> Vector3<f32> {
308
-        let adj_face_index = self.find_adjacent_face(vertex_index, faces).unwrap();
335
+        let adj_face_index = self
336
+            .find_adjacent_face(spoke_vertex_index, vertex_index, faces, current_face_index)
337
+            .unwrap();
309 338
         let adj_centroid = triangle_centroids[&adj_face_index];
310
-        if let Some(mid_centroid) = mid_centroid_cache.get(&(vertex_index, adj_face_index)) {
339
+        if let Some(mid_centroid) =
340
+            mid_centroid_cache.get(&(spoke_vertex_index, vertex_index, adj_face_index))
341
+        {
311 342
             return *mid_centroid;
312 343
         } else {
313 344
             let mid_centroid = centroid.clone().lerp(adj_centroid, 0.5);
314
-            mid_centroid_cache.insert((vertex_index, adj_face_index), mid_centroid);
345
+            mid_centroid_cache.insert(
346
+                (spoke_vertex_index, vertex_index, adj_face_index),
347
+                mid_centroid,
348
+            );
315 349
             return mid_centroid;
316 350
         }
317 351
     }
318 352
 
319
-    fn find_adjacent_face(&self, vertex_index: usize, faces: &Vec<usize>) -> Option<usize> {
353
+    fn find_adjacent_face(
354
+        &self,
355
+        spoke_vertex_index: usize,
356
+        vertex_index: usize,
357
+        faces: &Vec<usize>,
358
+        current_face_index: usize,
359
+    ) -> Option<usize> {
320 360
         for face_index in faces {
361
+            if *face_index == current_face_index {
362
+                continue;
363
+            }
321 364
             let triangle = &self.cells[*face_index];
322
-            if triangle.a == vertex_index
323
-                || triangle.b == vertex_index
324
-                || triangle.c == vertex_index
365
+            if (triangle.a == spoke_vertex_index
366
+                || triangle.b == spoke_vertex_index
367
+                || triangle.c == spoke_vertex_index)
368
+                && (triangle.a == vertex_index
369
+                    || triangle.b == vertex_index
370
+                    || triangle.c == vertex_index)
325 371
             {
326 372
                 return Some(*face_index);
327 373
             }
328 374
         }
329 375
         None
330 376
     }
377
+
378
+    fn compute_triangle_normals(&mut self) {
379
+        let origin = Vector3::new(0.0, 0.0, 0.0);
380
+        for i in 0..self.cells.len() {
381
+            let vertex_a = &self.positions[self.cells[i].a].0;
382
+            let vertex_b = &self.positions[self.cells[i].b].0;
383
+            let vertex_c = &self.positions[self.cells[i].c].0;
384
+
385
+            let e1 = vertex_a - vertex_b;
386
+            let e2 = vertex_c - vertex_b;
387
+            let mut no = e1.cross(e2);
388
+
389
+            // detect and correct inverted normal
390
+            let dist = vertex_b - origin;
391
+            if no.dot(dist) < 0.0 {
392
+                no *= -1.0;
393
+            }
394
+
395
+            let normal_a = self.normals[self.cells[i].a].0 + no;
396
+            let normal_b = self.normals[self.cells[i].b].0 + no;
397
+            let normal_c = self.normals[self.cells[i].c].0 + no;
398
+
399
+            self.normals[self.cells[i].a] = ArraySerializedVector(normal_a);
400
+            self.normals[self.cells[i].b] = ArraySerializedVector(normal_b);
401
+            self.normals[self.cells[i].c] = ArraySerializedVector(normal_c);
402
+        }
403
+
404
+        for normal in self.normals.iter_mut() {
405
+            *normal = ArraySerializedVector(normal.0.normalize());
406
+        }
407
+    }
408
+
409
+    fn compute_face_normals(&mut self) {
410
+        let origin = Vector3::new(0.0, 0.0, 0.0);
411
+        for i in 0..self.faces.len() {
412
+            let first_cell = &self.cells[self.faces[i][0]];
413
+
414
+            let vertex_a = &self.positions[first_cell.a].0;
415
+            let vertex_b = &self.positions[first_cell.b].0;
416
+            let vertex_c = &self.positions[first_cell.c].0;
417
+
418
+            let e1 = vertex_a - vertex_b;
419
+            let e2 = vertex_c - vertex_b;
420
+            let mut normal = e1.cross(e2);
421
+
422
+            // detect and correct inverted normal
423
+            let dist = vertex_b - origin;
424
+            if normal.dot(dist) < 0.0 {
425
+                normal *= -1.0;
426
+            }
427
+
428
+            for c in 0..self.faces[i].len() {
429
+                let face_cell = &self.cells[self.faces[i][c]];
430
+
431
+                let normal_a = self.normals[face_cell.a].0 + normal;
432
+                let normal_b = self.normals[face_cell.b].0 + normal;
433
+                let normal_c = self.normals[face_cell.c].0 + normal;
434
+
435
+                self.normals[face_cell.a] = ArraySerializedVector(normal_a);
436
+                self.normals[face_cell.b] = ArraySerializedVector(normal_b);
437
+                self.normals[face_cell.c] = ArraySerializedVector(normal_c);
438
+            }
439
+        }
440
+
441
+        for normal in self.normals.iter_mut() {
442
+            *normal = ArraySerializedVector(normal.0.normalize());
443
+        }
444
+    }
331 445
 }
332 446
 
333 447
 fn calculate_centroid(pa: Vector3<f32>, pb: Vector3<f32>, pc: Vector3<f32>) -> Vector3<f32> {
@@ -356,7 +470,8 @@ fn generate_icosahedron_files(dir: &str, param_list: Vec<(f32, usize)>) {
356 470
         );
357 471
         let filename = Path::new(dir).join(format!("icosahedron_r{}_d{}.json", param.0, param.1));
358 472
         let mut file = File::create(filename).expect("Can't create file");
359
-        let icosahedron = Polyhedron::new_isocahedron(param.0, param.1);
473
+        let mut icosahedron = Polyhedron::new_isocahedron(param.0, param.1);
474
+        icosahedron.compute_triangle_normals();
360 475
         println!("triangles: {}", icosahedron.cells.len());
361 476
         println!("vertices: {}", icosahedron.positions.len());
362 477
         let icosahedron_json = serde_json::to_string(&icosahedron).expect("Problem serializing");
@@ -373,7 +488,9 @@ fn generate_hexsphere_files(dir: &str, param_list: Vec<(f32, usize)>) {
373 488
         );
374 489
         let filename = Path::new(dir).join(format!("hexsphere_r{}_d{}.json", param.0, param.1));
375 490
         let mut file = File::create(filename).expect("Can't create file");
376
-        let hexsphere = Polyhedron::new_dual_isocahedron(param.0, param.1);
491
+        let mut hexsphere = Polyhedron::new_truncated_isocahedron(param.0, param.1);
492
+        hexsphere.compute_triangle_normals();
493
+        // hexsphere.compute_face_normals();
377 494
         println!("triangles: {}", hexsphere.cells.len());
378 495
         println!("vertices: {}", hexsphere.positions.len());
379 496
         let hexsphere_json = serde_json::to_string(&hexsphere).expect("Problem serializing");
@@ -394,6 +511,8 @@ fn main() {
394 511
             (1.0, 5),
395 512
             (1.0, 6),
396 513
             (1.0, 7),
514
+            // (1.0, 8),
515
+            // (1.0, 9),
397 516
         ],
398 517
     );
399 518
     generate_icosahedron_files(