Compute tangents, bitangents, normals. Args: vertex_pos: [N,3] vertex coordinates vertex_uv: [N,2] texture coordinates faces: [M,3] texture coordinates Returns: tangents, bitangents, normals
(vertex_pos, vertex_uv, faces, eps=1e-5)
| 49 | |
| 50 | |
| 51 | def compute_vertex_tbn(vertex_pos, vertex_uv, faces, eps=1e-5): |
| 52 | """Compute tangents, bitangents, normals. |
| 53 | Args: |
| 54 | vertex_pos: [N,3] vertex coordinates |
| 55 | vertex_uv: [N,2] texture coordinates |
| 56 | faces: [M,3] texture coordinates |
| 57 | Returns: |
| 58 | tangents, bitangents, normals |
| 59 | """ |
| 60 | |
| 61 | |
| 62 | #sample the positions and uv for every face vertex |
| 63 | #as a results the triangled vertices are (B,N,3,3) and triangled_vertices_uv is (N,3,2) |
| 64 | triangled_vertices = torch.tensor(vertex_pos[faces, :]) |
| 65 | triangled_vertices_uv = torch.tensor(vertex_uv[faces, :]) |
| 66 | |
| 67 | v01 = triangled_vertices[:, 1] - triangled_vertices[:, 0] |
| 68 | v02 = triangled_vertices[:, 2] - triangled_vertices[:, 0] |
| 69 | |
| 70 | |
| 71 | normals = torch.cross(v01, v02, dim=-1) |
| 72 | normals = normals / torch.norm(normals, dim=-1, keepdim=True).clamp(min=eps) |
| 73 | |
| 74 | vt01 = triangled_vertices_uv[:, 1] - triangled_vertices_uv[:, 0] |
| 75 | vt02 = triangled_vertices_uv[:, 2] - triangled_vertices_uv[:, 0] |
| 76 | |
| 77 | f = 1.0 / (vt01[..., 0] * vt02[..., 1] - vt01[..., 1] * vt02[..., 0]) |
| 78 | |
| 79 | tangents = f[..., np.newaxis] * ( |
| 80 | v01 * vt02[..., 1][..., np.newaxis] - v02 * vt01[..., 1][..., np.newaxis]) |
| 81 | tangents = tangents / torch.norm(tangents, dim=-1, keepdim=True).clamp(min=eps) |
| 82 | |
| 83 | |
| 84 | bitangents = torch.cross(normals, tangents, dim=-1) |
| 85 | bitangents = bitangents / torch.norm(bitangents, dim=-1, keepdim=True).clamp(min=eps) |
| 86 | |
| 87 | |
| 88 | #splat the tangent bitangent and normals from faces onto the vertices |
| 89 | v_t = torch.zeros(vertex_pos.shape[0],3) |
| 90 | v_b = torch.zeros(vertex_pos.shape[0],3) |
| 91 | v_n = torch.zeros(vertex_pos.shape[0],3) |
| 92 | for i in range(vertex_pos.shape[0]): |
| 93 | index = np.where(faces==i)[0] |
| 94 | v_t[i,:]=torch.mean(tangents[index],axis=0) |
| 95 | v_b[i,:]=torch.mean(bitangents[index],axis=0) |
| 96 | v_n[i,:]=torch.mean(normals[index],axis=0) |
| 97 | |
| 98 | # for f_t, f_b, f_n, f in zip(tangents,bitangents,normals, faces): |
| 99 | # for vertex_idx in f: |
| 100 | # v_t[vertex_idx,:]+=f_t |
| 101 | # v_b[vertex_idx,:]+=f_b |
| 102 | # v_n[vertex_idx,:]+=f_n |
| 103 | |
| 104 | |
| 105 | |
| 106 | v_t=torch.nn.functional.normalize(v_t) |
| 107 | v_b=torch.nn.functional.normalize(v_b) |
| 108 | v_n=torch.nn.functional.normalize(v_n) |