blender_mesh/
y_up.rs

1use crate::BlenderMesh;
2
3static Y: usize = 1;
4static Z: usize = 2;
5
6impl BlenderMesh {
7    /// Blender meshes get exported with a Z up coordinate system.
8    /// Here we flip our coordinate system to be y up
9    ///
10    /// @see https://gamedev.stackexchange.com/a/7932
11    ///
12    /// TODO: When we have bone data we'll need to change them to port change-mat4-coordinate-system
13    /// into here.
14    /// https://github.com/chinedufn/change-mat4-coordinate-system/blob/master/change-mat4-coordinate-system.js
15    pub fn y_up(&mut self) {
16        let vertex_attribs = &mut self.multi_indexed_vertex_attributes;
17
18        let positions = &mut vertex_attribs.positions.attribute.data;
19
20        let mut normals = match &mut vertex_attribs.normals {
21            None => None,
22            Some(normals) => Some(&mut normals.attribute.data),
23        };
24
25        let convert = |vert_num: usize, data: &mut Vec<f32>| {
26            let y_index = vert_num * 3 + 1;
27            let z_index = y_index + 1;
28
29            let new_z = -data[y_index];
30            data[y_index] = data[z_index];
31            data[z_index] = new_z;
32        };
33
34        for vert_num in 0..positions.len() / 3 {
35            convert(vert_num, positions);
36        }
37
38        if let Some(normals) = normals.as_mut() {
39            for vert_num in 0..normals.len() / 3 {
40                convert(vert_num, normals);
41            }
42        }
43
44        let new_z = -self.bounding_box.min_corner[Y];
45        self.bounding_box.min_corner[Y] = self.bounding_box.min_corner[Z];
46        self.bounding_box.min_corner[Z] = new_z;
47
48        let new_z = -self.bounding_box.max_corner[Y];
49        self.bounding_box.max_corner[Y] = self.bounding_box.max_corner[Z];
50        self.bounding_box.max_corner[Z] = new_z;
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57    use crate::bounding_box::BoundingBox;
58    use crate::indexed;
59    use crate::vertex_attributes::MultiIndexedVertexAttributes;
60    use nalgebra::Point3;
61
62    #[test]
63    fn z_up_to_y_up() {
64        let mut start_mesh = BlenderMesh {
65            multi_indexed_vertex_attributes: MultiIndexedVertexAttributes {
66                positions: indexed((vec![0.0, 1.0, 2.0, 0.0, 1.0, 2.0], 3).into()),
67                normals: Some(indexed((vec![0.0, 1.0, 2.0], 3).into())),
68                ..MultiIndexedVertexAttributes::default()
69            },
70            bounding_box: BoundingBox {
71                min_corner: Point3::new(1.0, 2.0, 3.0),
72                max_corner: Point3::new(5.0, 6.0, 7.0),
73            },
74            ..BlenderMesh::default()
75        };
76
77        start_mesh.y_up();
78        let y_up_mesh = start_mesh;
79
80        let expected_mesh = BlenderMesh {
81            multi_indexed_vertex_attributes: MultiIndexedVertexAttributes {
82                positions: indexed((vec![0.0, 2.0, -1.0, 0.0, 2.0, -1.0], 3).into()),
83                normals: Some(indexed((vec![0.0, 2.0, -1.0], 3).into())),
84                ..MultiIndexedVertexAttributes::default()
85            },
86            bounding_box: BoundingBox {
87                min_corner: Point3::new(1.0, 3.0, -2.0),
88                max_corner: Point3::new(5.0, 7.0, -6.0),
89            },
90            ..BlenderMesh::default()
91        };
92
93        assert_eq!(y_up_mesh, expected_mesh);
94    }
95}