Compute a UV-space barycentric map where each texel contains barycentric coordinates for the closest point on a UV triangle. Args: vt: torch.Tensor Texture coordinates. Shape = [n_texcoords, 2] vti: torch.Tensor Face texture coordinate indices. Shape = [n_face
(
vt: torch.Tensor,
vti: torch.Tensor,
uv_shape: Union[Tuple[int, int], int],
flip_uv: bool = True,
)
| 184 | #incurs a copy to cpu |
| 185 | #generates uv space map where each pixel has the index of the triangle, the 3 vertex indices of the triangle and the barycentric weights |
| 186 | def compute_uv_space_data( |
| 187 | vt: torch.Tensor, |
| 188 | vti: torch.Tensor, |
| 189 | uv_shape: Union[Tuple[int, int], int], |
| 190 | flip_uv: bool = True, |
| 191 | ): |
| 192 | """Compute a UV-space barycentric map where each texel contains barycentric |
| 193 | coordinates for the closest point on a UV triangle. |
| 194 | Args: |
| 195 | vt: torch.Tensor |
| 196 | Texture coordinates. Shape = [n_texcoords, 2] |
| 197 | vti: torch.Tensor |
| 198 | Face texture coordinate indices. Shape = [n_faces, 3] |
| 199 | uv_shape: Tuple[int, int] or int |
| 200 | Shape of the texture map. (HxW) |
| 201 | flip_uv: bool |
| 202 | Whether or not to flip UV coordinates along the V axis (OpenGL -> numpy/pytorch convention). |
| 203 | Returns: |
| 204 | torch.Tensor: index_img: Face index image, shape [uv_shape[0], uv_shape[1]] |
| 205 | torch.Tensor: Barycentric coordinate map, shape [uv_shape[0], uv_shape[1], 3]Â |
| 206 | """ |
| 207 | |
| 208 | if isinstance(uv_shape, int): |
| 209 | uv_shape = (uv_shape, uv_shape) |
| 210 | |
| 211 | if flip_uv: |
| 212 | # Flip here because texture coordinates in some of our topo files are |
| 213 | # stored in OpenGL convention with Y=0 on the bottom of the texture |
| 214 | # unlike numpy/torch arrays/tensors. |
| 215 | vt = vt.clone() |
| 216 | vt[:, 1] = 1 - vt[:, 1] |
| 217 | |
| 218 | # Texel to UV mapping (as per OpenGL linear filtering) |
| 219 | # https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdf |
| 220 | # Sect. 8.14, page 261 |
| 221 | # uv=(0.5,0.5)/w is at the center of texel [0,0] |
| 222 | # uv=(w-0.5, w-0.5)/w is the center of texel [w-1,w-1] |
| 223 | # texel = floor(u*w - 0.5) |
| 224 | # u = (texel+0.5)/w |
| 225 | |
| 226 | uv_grid = torch.meshgrid( |
| 227 | torch.linspace(0.5, uv_shape[0] - 1 + 0.5, uv_shape[0]) / uv_shape[0], |
| 228 | torch.linspace(0.5, uv_shape[1] - 1 + 0.5, uv_shape[1]) / uv_shape[1], |
| 229 | indexing="ij") # HxW, v,u |
| 230 | uv_grid = torch.stack(uv_grid[::-1], dim=2) # HxW, u, v |
| 231 | uv = uv_grid.reshape(-1, 2).data.to("cpu").numpy() |
| 232 | vth = np.hstack((vt, vt[:, 0:1] * 0 + 1)) |
| 233 | uvh = np.hstack((uv, uv[:, 0:1] * 0 + 1)) |
| 234 | |
| 235 | # print("vth",vth) |
| 236 | |
| 237 | closest_points, barys, vertex_idxs, face_idxs = closest_point_barycentrics(uvh, vth, vti.numpy()) |
| 238 | |
| 239 | index_img = torch.from_numpy(face_idxs.reshape(uv_shape[0], uv_shape[1])).long() |
| 240 | vert_idxs_img = torch.from_numpy(vertex_idxs.reshape(uv_shape[0], uv_shape[1],3)).long() |
| 241 | bary_img = torch.from_numpy(barys.reshape(uv_shape[0], uv_shape[1], 3)).float() |
| 242 | return index_img, vert_idxs_img, bary_img |
| 243 |
no test coverage detected