rendersloth/rasterizer/
geom.rs

1#![allow(dead_code)]
2use glam::{Mat4, Vec4};
3use std::clone::Clone;
4use tobj::{Material, Mesh};
5use stl_io::IndexedMesh;
6
7#[derive(PartialEq, Debug)]
8pub struct AABB {
9    pub min: Vec4,
10    pub max: Vec4,
11}
12
13impl AABB {
14    pub fn new(min: Vec4, max: Vec4) -> AABB {
15        AABB { min, max }
16    }
17}
18
19#[derive(PartialEq, Debug)]
20pub struct Triangle {
21    pub color: (u8, u8, u8),
22    pub v1: Vec4,
23    pub v2: Vec4,
24    pub v3: Vec4,
25}
26
27impl Default for Triangle {
28    fn default() -> Self {
29        Self {
30            color: (1, 0, 0),
31            v1: Vec4::new(1.0, -1.0, -1.0, 1.0),
32            v2: Vec4::new(-1.0, -1.0, 1.0, 1.0),
33            v3: Vec4::new(1.0, 1.0, -1.0, 1.0),
34        }
35    }
36}
37
38impl Triangle {
39    pub fn aabb(&self) -> AABB {
40        AABB::new(
41            Vec4::new(
42                self.v1[0].min(self.v2[0].min(self.v3[0])),
43                self.v1[1].min(self.v2[1].min(self.v3[1])),
44                self.v1[2].min(self.v2[2].min(self.v3[2])),
45                1.0,
46            ),
47            Vec4::new(
48                self.v1[0].max(self.v2[0].max(self.v3[0])),
49                self.v1[1].max(self.v2[1].max(self.v3[1])),
50                self.v1[2].max(self.v2[2].max(self.v3[2])),
51                1.0,
52            ),
53        )
54    }
55    pub fn mul(&mut self, transform: Mat4) -> &mut Triangle {
56        self.v1 = transform * self.v1;
57        self.v2 = transform * self.v2;
58        self.v3 = transform * self.v3;
59        self
60    }
61    pub fn normal(&self) -> Vec4 {
62        let v1 = self.v2 - self.v1;
63        let v2 = self.v3 - self.v1;
64        let x = (v1[1] * v2[2]) - (v1[2] * v2[1]);
65        let y = (v1[2] * v2[0]) - (v1[0] * v2[2]);
66        let z = (v1[0] * v2[1]) - (v1[1] * v2[0]);
67        Vec4::new(x, y, z, 0.0).normalize()
68    }
69}
70
71impl Clone for Triangle {
72    fn clone(&self) -> Triangle {
73        Triangle {
74            color: self.color,
75            v1: self.v1,
76            v2: self.v2,
77            v3: self.v3,
78        }
79    }
80}
81
82pub trait ToSimpleMesh {
83    fn to_simple_mesh(&self) -> SimpleMesh;
84}
85
86pub trait ToSimpleMeshWithMaterial {
87    fn to_simple_mesh_with_materials(&self, materials: &[Material]) -> SimpleMesh;
88}
89
90pub struct SimpleMesh {
91    pub bounding_box: AABB,
92    pub triangles: Vec<Triangle>,
93}
94
95impl ToSimpleMeshWithMaterial for Mesh {
96    fn to_simple_mesh_with_materials(&self, materials: &[Material]) -> SimpleMesh {
97        let mut bounding_box = AABB {
98            min: Vec4::new(0.0, 0.0, 0.0, 1.0),
99            max: Vec4::new(0.0, 0.0, 0.0, 1.0),
100        };
101        let mut triangles = vec![
102            Triangle {
103                color: (1, 1, 1),
104                v1: Vec4::new(0.0, 0.0, 0.0, 1.0),
105                v2: Vec4::new(0.0, 0.0, 0.0, 1.0),
106                v3: Vec4::new(0.0, 0.0, 0.0, 1.0)
107            };
108            self.indices.len() / 3
109        ];
110        for (x, tri) in triangles.iter_mut().enumerate() {
111            tri.v1.x = self.positions[(self.indices[x * 3] * 3) as usize];
112            tri.v1.y = self.positions[(self.indices[x * 3] * 3 + 1) as usize];
113            tri.v1.z = self.positions[(self.indices[x * 3] * 3 + 2) as usize];
114            tri.v2.x = self.positions[(self.indices[x * 3 + 1] * 3) as usize];
115            tri.v2.y = self.positions[(self.indices[x * 3 + 1] * 3 + 1) as usize];
116            tri.v2.z = self.positions[(self.indices[x * 3 + 1] * 3 + 2) as usize];
117            tri.v3.x = self.positions[(self.indices[x * 3 + 2] * 3) as usize];
118            tri.v3.y = self.positions[(self.indices[x * 3 + 2] * 3 + 1) as usize];
119            tri.v3.z = self.positions[(self.indices[x * 3 + 2] * 3 + 2) as usize];
120
121            if !materials.is_empty() {
122                let material = &materials[self.material_id.unwrap()];
123                tri.color = (
124                    (material.diffuse[0] * 255.0) as u8,
125                    (material.diffuse[1] * 255.0) as u8,
126                    (material.diffuse[2] * 255.0) as u8,
127                );
128
129                // Check if the model contains vertex colors.
130                if !self.vertex_color.is_empty() {
131                    // Get the vertex_color from the first indice in the tri.
132                    let color = (
133                        (self.vertex_color[(self.indices[x * 3] * 3) as usize] * 255.0) as u8,
134                        (self.vertex_color[(self.indices[x * 3] * 3 + 1) as usize] * 255.0) as u8,
135                        (self.vertex_color[(self.indices[x * 3] * 3 + 2) as usize] * 255.0) as u8,
136                    );
137                    tri.color = color;
138                }
139            }
140
141            let aabb = tri.aabb();
142            bounding_box.min.x = aabb.min.x.min(bounding_box.min.x);
143            bounding_box.min.y = aabb.min.y.min(bounding_box.min.y);
144            bounding_box.min.z = aabb.min.z.min(bounding_box.min.z);
145            bounding_box.max.x = aabb.max.x.max(bounding_box.max.x);
146            bounding_box.max.y = aabb.max.y.max(bounding_box.max.y);
147            bounding_box.max.z = aabb.max.z.max(bounding_box.max.z);
148        }
149        SimpleMesh {
150            triangles,
151            bounding_box,
152        }
153    }
154}
155
156impl ToSimpleMesh for Mesh {
157    fn to_simple_mesh(&self) -> SimpleMesh {
158        self.to_simple_mesh_with_materials(&[])
159    }
160}
161
162impl ToSimpleMesh for IndexedMesh {
163    fn to_simple_mesh(&self) -> SimpleMesh {
164        let mut bounding_box = AABB {
165            min: Vec4::new(std::f32::MAX, std::f32::MAX, std::f32::MAX, 1.0),
166            max: Vec4::new(std::f32::MIN, std::f32::MIN, std::f32::MIN, 1.0),
167        };
168        fn stlv2v4(stlio_vec: [f32; 3]) -> Vec4 {
169            Vec4::new(stlio_vec[0], stlio_vec[1], stlio_vec[2], 1.0)
170        }
171        let mut triangles = vec![
172            Triangle {
173                // at time of writing, stl_io lacked color
174                color: (0xFF, 0xFF, 0x00),
175                v1: Vec4::new(0.0, 0.0, 0.0, 1.0),
176                v2: Vec4::new(0.0, 0.0, 0.0, 1.0),
177                v3: Vec4::new(0.0, 0.0, 0.0, 1.0)
178            };
179            self.faces.len()
180        ];
181        #[allow(clippy::needless_range_loop)]
182        // We need an index number, to get the triangle's index too
183        for t_index in 0..self.faces.len() {
184            triangles[t_index].v1 = stlv2v4(self.vertices[self.faces[t_index].vertices[0]].into());
185            triangles[t_index].v2 = stlv2v4(self.vertices[self.faces[t_index].vertices[1]].into());
186            triangles[t_index].v3 = stlv2v4(self.vertices[self.faces[t_index].vertices[2]].into());
187            let aabb = triangles[t_index].aabb();
188            bounding_box.min.x = aabb.min.x.min(bounding_box.min.x);
189            bounding_box.min.y = aabb.min.y.min(bounding_box.min.y);
190            bounding_box.min.z = aabb.min.z.min(bounding_box.min.z);
191            bounding_box.max.x = aabb.max.x.max(bounding_box.max.x);
192            bounding_box.max.y = aabb.max.y.max(bounding_box.max.y);
193            bounding_box.max.z = aabb.max.z.max(bounding_box.max.z);
194        }
195        SimpleMesh {
196            triangles,
197            bounding_box,
198        }
199    }
200}
201
202#[cfg(test)]
203mod tests {
204    use super::*;
205    use glam::{Mat4, Vec3, Vec4};
206
207    #[test]
208    fn test_aabb() {
209        let triangle = Triangle::default();
210        assert_eq!(
211            triangle.aabb(),
212            AABB::new(
213                Vec4::new(-1.0, -1.0, -1.0, 1.0),
214                Vec4::new(1.0, 1.0, 1.0, 1.0)
215            )
216        );
217    }
218
219    #[test]
220    fn test_transform() {
221        let transform = Mat4::from_translation(Vec3::new(1.0, 1.0, 1.0));
222        let mut triangle = Triangle::default();
223        triangle.mul(transform);
224        assert_eq!(
225            triangle.aabb(),
226            AABB::new(Vec4::new(0.0, 0.0, 0.0, 1.0), Vec4::new(2.0, 2.0, 2.0, 1.0))
227        );
228    }
229
230    #[test]
231    fn test_normal() {
232        let triangle = Triangle {
233            color: (1, 0, 0),
234            v1: Vec4::new(-1.0, 1.0, 0.0, 1.0),
235            v2: Vec4::new(0.0, 1.0, 1.0, 1.0),
236            v3: Vec4::new(1.0, 1.0, 0.0, 1.0),
237        };
238        assert_eq!(triangle.normal(), Vec4::new(0.0, 1.0, 0.0, 0.0));
239    }
240}