/// Test taken & slightly modified from mikktspace crate use mikktspace_sys::*; pub type Face = [u32; 3]; #[derive(Debug)] struct Vertex { position: [f32; 3], normal: [f32; 3], tex_coord: [f32; 2], } #[derive(Debug, PartialEq)] struct Result { tangent: [f32; 3], bi_tangent: [f32; 3], mag_s: f32, mag_t: f32, bi_tangent_preserves_orientation: bool, face: usize, vert: usize, } impl Result { fn new( tangent: [f32; 3], bi_tangent: [f32; 3], mag_s: f32, mag_t: f32, bi_tangent_preserves_orientation: bool, face: usize, vert: usize, ) -> Self { Self { tangent, bi_tangent, mag_s, mag_t, bi_tangent_preserves_orientation, face, vert, } } } struct Mesh { faces: Vec, vertices: Vec, } struct Context { mesh: Mesh, results: Vec, } fn vertex(mesh: &Mesh, face: usize, vert: usize) -> &Vertex { let vs: &[u32; 3] = &mesh.faces[face]; &mesh.vertices[vs[vert] as usize] } impl MikkTSpaceInterface for Context { fn get_num_faces(&self) -> usize { self.mesh.faces.len() } fn get_num_vertices_of_face(&self, _face: usize) -> usize { 3 } fn get_position(&self, face: usize, vert: usize) -> [f32; 3] { vertex(&self.mesh, face, vert).position } fn get_normal(&self, face: usize, vert: usize) -> [f32; 3] { vertex(&self.mesh, face, vert).normal } fn get_tex_coord(&self, face: usize, vert: usize) -> [f32; 2] { vertex(&self.mesh, face, vert).tex_coord } fn set_tspace( &mut self, tangent: [f32; 3], bi_tangent: [f32; 3], mag_s: f32, mag_t: f32, bi_tangent_preserves_orientation: bool, face: usize, vert: usize, ) { self.results.push(Result { tangent, bi_tangent, mag_s, mag_t, bi_tangent_preserves_orientation, face, vert, }) } } struct ControlPoint { uv: [f32; 2], dir: [f32; 3], } impl ControlPoint { fn new(uv: [f32; 2], dir: [f32; 3]) -> Self { Self { uv, dir } } } fn make_cube() -> Mesh { let mut faces = Vec::new(); let mut ctl_pts = Vec::new(); let mut vertices = Vec::new(); // +x plane { let base = ctl_pts.len() as u32; faces.push([base, base + 1, base + 4]); faces.push([base + 1, base + 2, base + 4]); faces.push([base + 2, base + 3, base + 4]); faces.push([base + 3, base, base + 4]); ctl_pts.push(ControlPoint::new([0.0, 0.0], [1.0, -1.0, 1.0])); ctl_pts.push(ControlPoint::new([0.0, 1.0], [1.0, -1.0, -1.0])); ctl_pts.push(ControlPoint::new([1.0, 1.0], [1.0, 1.0, -1.0])); ctl_pts.push(ControlPoint::new([1.0, 0.0], [1.0, 1.0, 1.0])); ctl_pts.push(ControlPoint::new([0.5, 0.5], [1.0, 0.0, 0.0])); } // -x plane { let base = ctl_pts.len() as u32; faces.push([base, base + 1, base + 4]); faces.push([base + 1, base + 2, base + 4]); faces.push([base + 2, base + 3, base + 4]); faces.push([base + 3, base, base + 4]); ctl_pts.push(ControlPoint::new([1.0, 0.0], [-1.0, 1.0, 1.0])); ctl_pts.push(ControlPoint::new([1.0, 1.0], [-1.0, 1.0, -1.0])); ctl_pts.push(ControlPoint::new([0.0, 1.0], [-1.0, -1.0, -1.0])); ctl_pts.push(ControlPoint::new([0.0, 0.0], [-1.0, -1.0, 1.0])); ctl_pts.push(ControlPoint::new([0.5, 0.5], [-1.0, 0.0, 0.0])); } // +y plane { let base = ctl_pts.len() as u32; faces.push([base, base + 1, base + 4]); faces.push([base + 1, base + 2, base + 4]); faces.push([base + 2, base + 3, base + 4]); faces.push([base + 3, base, base + 4]); ctl_pts.push(ControlPoint::new([0.0, 0.0], [1.0, 1.0, 1.0])); ctl_pts.push(ControlPoint::new([0.0, 1.0], [1.0, 1.0, -1.0])); ctl_pts.push(ControlPoint::new([0.0, 1.0], [-1.0, 1.0, -1.0])); ctl_pts.push(ControlPoint::new([0.0, 0.0], [-1.0, 1.0, 1.0])); ctl_pts.push(ControlPoint::new([0.0, 0.5], [0.0, 1.0, 0.0])); } // -y plane { let base = ctl_pts.len() as u32; faces.push([base, base + 1, base + 4]); faces.push([base + 1, base + 2, base + 4]); faces.push([base + 2, base + 3, base + 4]); faces.push([base + 3, base, base + 4]); ctl_pts.push(ControlPoint::new([0.0, 0.0], [-1.0, -1.0, 1.0])); ctl_pts.push(ControlPoint::new([0.0, 1.0], [-1.0, -1.0, -1.0])); ctl_pts.push(ControlPoint::new([0.0, 1.0], [1.0, -1.0, -1.0])); ctl_pts.push(ControlPoint::new([0.0, 0.0], [1.0, -1.0, 1.0])); ctl_pts.push(ControlPoint::new([0.0, 0.5], [0.0, -1.0, 0.0])); } // +z plane { let base = ctl_pts.len() as u32; faces.push([base, base + 1, base + 4]); faces.push([base + 1, base + 2, base + 4]); faces.push([base + 2, base + 3, base + 4]); faces.push([base + 3, base, base + 4]); ctl_pts.push(ControlPoint::new([0.0, 0.0], [-1.0, 1.0, 1.0])); ctl_pts.push(ControlPoint::new([0.0, 1.0], [-1.0, -1.0, 1.0])); ctl_pts.push(ControlPoint::new([1.0, 1.0], [1.0, -1.0, 1.0])); ctl_pts.push(ControlPoint::new([1.0, 0.0], [1.0, 1.0, 1.0])); ctl_pts.push(ControlPoint::new([0.5, 0.5], [0.0, 0.0, 1.0])); } // -z plane { let base = ctl_pts.len() as u32; faces.push([base, base + 1, base + 4]); faces.push([base + 1, base + 2, base + 4]); faces.push([base + 2, base + 3, base + 4]); faces.push([base + 3, base, base + 4]); ctl_pts.push(ControlPoint::new([1.0, 0.0], [1.0, 1.0, -1.0])); ctl_pts.push(ControlPoint::new([1.0, 1.0], [1.0, -1.0, -1.0])); ctl_pts.push(ControlPoint::new([0.0, 1.0], [-1.0, -1.0, -1.0])); ctl_pts.push(ControlPoint::new([0.0, 0.0], [-1.0, 1.0, -1.0])); ctl_pts.push(ControlPoint::new([0.5, 0.5], [0.0, 0.0, -1.0])); } for pt in ctl_pts { let normal_len = f32::sqrt((pt.dir[0] * pt.dir[0]) + (pt.dir[1] * pt.dir[1]) + (pt.dir[2] * pt.dir[2])); let normal = [ pt.dir[0] / normal_len, pt.dir[1] / normal_len, pt.dir[2] / normal_len, ]; vertices.push(Vertex { position: [pt.dir[0] / 2.0, pt.dir[1] / 2.0, pt.dir[2] / 2.0], normal, tex_coord: pt.uv, }); } Mesh { faces, vertices } } #[test] fn cube_tangents_should_equal_reference_values() { let mut context = Context { mesh: make_cube(), results: Vec::new(), }; let ret = gen_tang_space_default(&mut context); assert!(ret); let expected_results: Vec = vec![ Result::new( [0.40824825, 0.81649655, 0.40824825], [0.40824825, -0.40824825, -0.81649655], 1.00000000, 1.00000000, false, 0, 0, ), Result::new( [0.40824825, 0.81649655, -0.40824825], [-0.40824825, 0.40824825, -0.81649655], 1.00000000, 1.00000000, false, 0, 1, ), Result::new( [0.00000000, 1.00000000, 0.00000000], [0.00000000, 0.00000000, -1.00000000], 1.00000000, 1.00000000, false, 0, 2, ), Result::new( [0.40824825, 0.81649655, -0.40824825], [-0.40824825, 0.40824825, -0.81649655], 1.00000000, 1.00000000, false, 1, 0, ), Result::new( [-0.40824825, 0.81649655, 0.40824825], [-0.40824825, -0.40824825, -0.81649655], 1.00000000, 1.00000000, false, 1, 1, ), Result::new( [0.00000000, 1.00000000, 0.00000000], [0.00000000, 0.00000000, -1.00000000], 1.00000000, 1.00000000, false, 1, 2, ), Result::new( [-0.40824825, 0.81649655, 0.40824825], [-0.40824825, -0.40824825, -0.81649655], 1.00000000, 1.00000000, false, 2, 0, ), Result::new( [-0.40824825, 0.81649655, -0.40824825], [0.40824825, 0.40824825, -0.81649655], 1.00000000, 1.00000000, false, 2, 1, ), Result::new( [0.00000000, 1.00000000, 0.00000000], [0.00000000, 0.00000000, -1.00000000], 1.00000000, 1.00000000, false, 2, 2, ), Result::new( [-0.40824825, 0.81649655, -0.40824825], [0.40824825, 0.40824825, -0.81649655], 1.00000000, 1.00000000, false, 3, 0, ), Result::new( [0.40824825, 0.81649655, 0.40824825], [0.40824825, -0.40824825, -0.81649655], 1.00000000, 1.00000000, false, 3, 1, ), Result::new( [0.00000000, 1.00000000, 0.00000000], [0.00000000, 0.00000000, -1.00000000], 1.00000000, 1.00000000, false, 3, 2, ), Result::new( [0.40824825, 0.81649655, -0.40824825], [-0.40824825, 0.40824825, -0.81649655], 1.00000000, 1.00000000, true, 4, 0, ), Result::new( [0.40824825, 0.81649655, 0.40824825], [0.40824825, -0.40824825, -0.81649655], 1.00000000, 1.00000000, true, 4, 1, ), Result::new( [0.00000000, 1.00000000, 0.00000000], [0.00000000, 0.00000000, -1.00000000], 1.00000000, 1.00000000, true, 4, 2, ), Result::new( [0.40824825, 0.81649655, 0.40824825], [0.40824825, -0.40824825, -0.81649655], 1.00000000, 1.00000000, true, 5, 0, ), Result::new( [-0.40824825, 0.81649655, -0.40824825], [0.40824825, 0.40824825, -0.81649655], 1.00000000, 1.00000000, true, 5, 1, ), Result::new( [0.00000000, 1.00000000, 0.00000000], [0.00000000, 0.00000000, -1.00000000], 1.00000000, 1.00000000, true, 5, 2, ), Result::new( [-0.40824825, 0.81649655, -0.40824825], [0.40824825, 0.40824825, -0.81649655], 1.00000000, 1.00000000, true, 6, 0, ), Result::new( [-0.40824825, 0.81649655, 0.40824825], [-0.40824825, -0.40824825, -0.81649655], 1.00000000, 1.00000000, true, 6, 1, ), Result::new( [0.00000000, 1.00000000, 0.00000000], [0.00000000, 0.00000000, -1.00000000], 1.00000000, 1.00000000, true, 6, 2, ), Result::new( [-0.40824825, 0.81649655, 0.40824825], [-0.40824825, -0.40824825, -0.81649655], 1.00000000, 1.00000000, true, 7, 0, ), Result::new( [0.40824825, 0.81649655, -0.40824825], [-0.40824825, 0.40824825, -0.81649655], 1.00000000, 1.00000000, true, 7, 1, ), Result::new( [0.00000000, 1.00000000, 0.00000000], [0.00000000, 0.00000000, -1.00000000], 1.00000000, 1.00000000, true, 7, 2, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 8, 0, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 8, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 8, 2, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 9, 0, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 9, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 9, 2, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 10, 0, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 10, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 10, 2, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 11, 0, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 11, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 11, 2, ), Result::new( [-0.40824825, 0.81649655, 0.40824825], [-0.40824825, -0.40824825, -0.81649655], 1.00000000, 1.00000000, true, 12, 0, ), Result::new( [-0.40824825, 0.81649655, -0.40824825], [0.40824825, 0.40824825, -0.81649655], 1.00000000, 1.00000000, true, 12, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 12, 2, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 13, 0, ), Result::new( [0.40824825, 0.81649655, -0.40824825], [-0.40824825, 0.40824825, -0.81649655], 1.00000000, 1.00000000, false, 13, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 13, 2, ), Result::new( [0.40824825, 0.81649655, -0.40824825], [-0.40824825, 0.40824825, -0.81649655], 1.00000000, 1.00000000, false, 14, 0, ), Result::new( [0.40824825, 0.81649655, 0.40824825], [0.40824825, -0.40824825, -0.81649655], 1.00000000, 1.00000000, false, 14, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 14, 2, ), Result::new( [0.40824825, 0.81649655, 0.40824825], [0.40824825, -0.40824825, -0.81649655], 1.00000000, 1.00000000, false, 15, 0, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 15, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, 1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 15, 2, ), Result::new( [0.81649655, 0.40824825, 0.40824825], [-0.40824825, -0.81649655, 0.40824825], 1.00000000, 1.00000000, false, 16, 0, ), Result::new( [0.81649655, -0.40824825, 0.40824825], [0.40824825, -0.81649655, -0.40824825], 1.00000000, 1.00000000, false, 16, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, -1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 16, 2, ), Result::new( [0.81649655, -0.40824825, 0.40824825], [0.40824825, -0.81649655, -0.40824825], 1.00000000, 1.00000000, false, 17, 0, ), Result::new( [0.81649655, 0.40824825, -0.40824825], [-0.40824825, -0.81649655, -0.40824825], 1.00000000, 1.00000000, false, 17, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, -1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 17, 2, ), Result::new( [0.81649655, 0.40824825, -0.40824825], [-0.40824825, -0.81649655, -0.40824825], 1.00000000, 1.00000000, false, 18, 0, ), Result::new( [0.81649655, -0.40824825, -0.40824825], [0.40824825, -0.81649655, 0.40824825], 1.00000000, 1.00000000, false, 18, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, -1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 18, 2, ), Result::new( [0.81649655, -0.40824825, -0.40824825], [0.40824825, -0.81649655, 0.40824825], 1.00000000, 1.00000000, false, 19, 0, ), Result::new( [0.81649655, 0.40824825, 0.40824825], [-0.40824825, -0.81649655, 0.40824825], 1.00000000, 1.00000000, false, 19, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, -1.00000000, 0.00000000], 1.00000000, 1.00000000, false, 19, 2, ), Result::new( [0.81649655, -0.40824825, 0.40824825], [0.40824825, -0.81649655, -0.40824825], 1.00000000, 1.00000000, true, 20, 0, ), Result::new( [0.81649655, 0.40824825, 0.40824825], [-0.40824825, -0.81649655, 0.40824825], 1.00000000, 1.00000000, true, 20, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, -1.00000000, 0.00000000], 1.00000000, 1.00000000, true, 20, 2, ), Result::new( [0.81649655, 0.40824825, 0.40824825], [-0.40824825, -0.81649655, 0.40824825], 1.00000000, 1.00000000, true, 21, 0, ), Result::new( [0.81649655, -0.40824825, -0.40824825], [0.40824825, -0.81649655, 0.40824825], 1.00000000, 1.00000000, true, 21, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, -1.00000000, 0.00000000], 1.00000000, 1.00000000, true, 21, 2, ), Result::new( [0.81649655, -0.40824825, -0.40824825], [0.40824825, -0.81649655, 0.40824825], 1.00000000, 1.00000000, true, 22, 0, ), Result::new( [0.81649655, 0.40824825, -0.40824825], [-0.40824825, -0.81649655, -0.40824825], 1.00000000, 1.00000000, true, 22, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, -1.00000000, 0.00000000], 1.00000000, 1.00000000, true, 22, 2, ), Result::new( [0.81649655, 0.40824825, -0.40824825], [-0.40824825, -0.81649655, -0.40824825], 1.00000000, 1.00000000, true, 23, 0, ), Result::new( [0.81649655, -0.40824825, 0.40824825], [0.40824825, -0.81649655, -0.40824825], 1.00000000, 1.00000000, true, 23, 1, ), Result::new( [1.00000000, 0.00000000, 0.00000000], [0.00000000, -1.00000000, 0.00000000], 1.00000000, 1.00000000, true, 23, 2, ), ]; assert_eq!(expected_results, context.results); }