| | import numpy as np |
| | import torch |
| | from torch.nn import functional as F |
| | |
| |
|
| | def uv_to_xyz_and_normals(verts, f, fmap, bmap, ftov): |
| | vn = estimate_vertex_normals(verts, f, ftov) |
| | pixels_to_set = torch.nonzero(fmap+1) |
| | x_to_set = pixels_to_set[:,0] |
| | y_to_set = pixels_to_set[:,1] |
| | b_coords = bmap[x_to_set, y_to_set, :] |
| | f_coords = fmap[x_to_set, y_to_set] |
| | v_ids = f[f_coords] |
| | points = (b_coords[:,0,None]*verts[:,v_ids[:,0]] |
| | + b_coords[:,1,None]*verts[:,v_ids[:,1]] |
| | + b_coords[:,2,None]*verts[:,v_ids[:,2]]) |
| | normals = (b_coords[:,0,None]*vn[:,v_ids[:,0]] |
| | + b_coords[:,1,None]*vn[:,v_ids[:,1]] |
| | + b_coords[:,2,None]*vn[:,v_ids[:,2]]) |
| | return points, normals, vn, f_coords |
| |
|
| | def estimate_vertex_normals(v, f, ftov): |
| | face_normals = TriNormalsScaled(v, f) |
| | non_scaled_normals = torch.einsum('ij,bjk->bik', ftov, face_normals) |
| | norms = torch.sum(non_scaled_normals ** 2.0, 2) ** 0.5 |
| | norms[norms == 0] = 1.0 |
| | return torch.div(non_scaled_normals, norms[:,:,None]) |
| |
|
| | def TriNormalsScaled(v, f): |
| | return torch.cross(_edges_for(v, f, 1, 0), _edges_for(v, f, 2, 0)) |
| |
|
| | def _edges_for(v, f, cplus, cminus): |
| | return v[:,f[:,cplus]] - v[:,f[:,cminus]] |
| |
|
| | def psbody_get_face_visibility(v, n, f, cams, normal_threshold=0.5): |
| | bn, nverts, _ = v.shape |
| | nfaces, _ = f.shape |
| | vis_f = np.zeros([bn, nfaces], dtype='float32') |
| | for i in range(bn): |
| | vis, n_dot_cam = visibility_compute(v=v[i], n=n[i], f=f, cams=cams) |
| | vis_v = (vis == 1) & (n_dot_cam > normal_threshold) |
| | vis_f[i] = np.all(vis_v[0,f],1) |
| | return vis_f |
| |
|
| | def compute_uvsampler(vt, ft, tex_size=6): |
| | """ |
| | For this mesh, pre-computes the UV coordinates for |
| | F x T x T points. |
| | Returns F x T x T x 2 |
| | """ |
| | uv = obj2nmr_uvmap(ft, vt, tex_size=tex_size) |
| | uv = uv.reshape(-1, tex_size, tex_size, 2) |
| | return uv |
| |
|
| | def obj2nmr_uvmap(ft, vt, tex_size=6): |
| | """ |
| | Converts obj uv_map to NMR uv_map (F x T x T x 2), |
| | where tex_size (T) is the sample rate on each face. |
| | """ |
| | |
| | uv_map_for_verts = vt[ft] |
| |
|
| | |
| | uv_map_for_verts[:, :, 1] = 1 - uv_map_for_verts[:, :, 1] |
| |
|
| | |
| | uv_map_for_verts = (2 * uv_map_for_verts) - 1 |
| |
|
| | alpha = np.arange(tex_size, dtype=np.float) / (tex_size - 1) |
| | beta = np.arange(tex_size, dtype=np.float) / (tex_size - 1) |
| | import itertools |
| | |
| | coords = np.stack([p for p in itertools.product(*[alpha, beta])]) |
| |
|
| | |
| | v2 = uv_map_for_verts[:, 2] |
| | v0v2 = uv_map_for_verts[:, 0] - uv_map_for_verts[:, 2] |
| | v1v2 = uv_map_for_verts[:, 1] - uv_map_for_verts[:, 2] |
| | |
| | uv_map = np.dstack([v0v2, v1v2]).dot(coords.T) + v2.reshape(-1, 2, 1) |
| |
|
| | |
| | uv_map = np.transpose(uv_map, (0, 2, 1)).reshape(-1, tex_size, tex_size, 2) |
| |
|
| | return uv_map |
| |
|