1pub use glam::{Vec2, Vec3, Vec4, Mat3, Mat4, Quat, Affine3A};
2
3pub fn compute_tangents(
6 positions: &[[f32; 3]],
7 normals: &[[f32; 3]],
8 uvs: &[[f32; 2]],
9 indices: &[u32],
10) -> Vec<[f32; 4]> {
11 let vertex_count = positions.len();
12 let mut tangents = vec![Vec3::ZERO; vertex_count];
13 let mut bitangents = vec![Vec3::ZERO; vertex_count];
14
15 for tri in indices.chunks(3) {
16 if tri.len() < 3 {
17 continue;
18 }
19 let (i0, i1, i2) = (tri[0] as usize, tri[1] as usize, tri[2] as usize);
20
21 let p0 = Vec3::from(positions[i0]);
22 let p1 = Vec3::from(positions[i1]);
23 let p2 = Vec3::from(positions[i2]);
24
25 let uv0 = Vec2::from(uvs[i0]);
26 let uv1 = Vec2::from(uvs[i1]);
27 let uv2 = Vec2::from(uvs[i2]);
28
29 let e1 = p1 - p0;
30 let e2 = p2 - p0;
31 let duv1 = uv1 - uv0;
32 let duv2 = uv2 - uv0;
33
34 let f = 1.0 / (duv1.x * duv2.y - duv2.x * duv1.y + 1e-12);
35 let tangent = Vec3::new(
36 f * (duv2.y * e1.x - duv1.y * e2.x),
37 f * (duv2.y * e1.y - duv1.y * e2.y),
38 f * (duv2.y * e1.z - duv1.y * e2.z),
39 );
40 let bitangent = Vec3::new(
41 f * (-duv2.x * e1.x + duv1.x * e2.x),
42 f * (-duv2.x * e1.y + duv1.x * e2.y),
43 f * (-duv2.x * e1.z + duv1.x * e2.z),
44 );
45
46 for &i in &[i0, i1, i2] {
47 tangents[i] += tangent;
48 bitangents[i] += bitangent;
49 }
50 }
51
52 (0..vertex_count)
53 .map(|i| {
54 let n = Vec3::from(normals[i]);
55 let t = tangents[i];
56 let b = bitangents[i];
57
58 let t_ortho = (t - n * n.dot(t)).normalize_or_zero();
60 let handedness = if n.dot(t_ortho.cross(b)) < 0.0 {
61 -1.0
62 } else {
63 1.0
64 };
65 [t_ortho.x, t_ortho.y, t_ortho.z, handedness]
66 })
67 .collect()
68}