Shortcuts

Source code for mmhuman3d.utils.mesh_utils

import warnings
from typing import List

import torch
from pytorch3d.io import IO, save_obj
from pytorch3d.renderer import TexturesVertex
from pytorch3d.structures import (
    Meshes,
    Pointclouds,
    join_meshes_as_batch,
    join_meshes_as_scene,
    padded_to_list,
)

from mmhuman3d.utils.path_utils import prepare_output_path


[docs]def join_batch_meshes_as_scene( meshes: List[Meshes], include_textures: bool = True, ) -> Meshes: """Join meshes as a scene each batch. Only for pytorch3d meshes. The Meshes must share the same batch size, and arbitrary topology. They must all be on the same device. If include_textures is true, they must all be compatible, either all or none having textures, and all the Textures objects being the same type. If include_textures is False, textures are ignored. If not, ValueError would be raised in join_meshes_as_batch and join_meshes_as_scene. Args: meshes (List[Meshes]): A `list` of `Meshes` with the same batches. Required. include_textures: (bool) whether to try to join the textures. Returns: New Meshes which has join different Meshes by each batch. """ for mesh in meshes: mesh._verts_list = padded_to_list(mesh.verts_padded(), mesh.num_verts_per_mesh().tolist()) num_scene_size = len(meshes) num_batch_size = len(meshes[0]) for i in range(num_scene_size): assert len( meshes[i] ) == num_batch_size, 'Please make sure that the Meshes all have' 'the same batch size.' meshes_all = [] for j in range(num_batch_size): meshes_batch = [] for i in range(num_scene_size): meshes_batch.append(meshes[i][j]) meshes_all.append(join_meshes_as_scene(meshes_batch, include_textures)) meshes_final = join_meshes_as_batch(meshes_all, include_textures) return meshes_final
[docs]def mesh_to_pointcloud_vc( meshes: Meshes, include_textures: bool = True, alpha: float = 1.0, ) -> Pointclouds: """Convert pytorch3d `Meshes` to `PointClouds`. Args: meshes (Meshes): input meshes. include_textures (bool, optional): Whether include colors. Require the texture of input meshes is vertex color. Defaults to True. alpha (float, optional): transparency. Defaults to 1.0. Returns: Pointclouds: output pointclouds. """ assert isinstance( meshes.textures, TexturesVertex), 'textures of input meshes should be `TexturesVertex`' vertices = meshes.verts_padded() if include_textures: verts_rgb = meshes.textures.verts_features_padded() verts_rgba = torch.cat( [verts_rgb, torch.ones_like(verts_rgb)[..., 0:1] * alpha], dim=-1) else: verts_rgba = None pointclouds = Pointclouds(points=vertices, features=verts_rgba) return pointclouds
[docs]def save_meshes_as_plys(meshes: Meshes = None, verts: torch.Tensor = None, faces: torch.Tensor = None, verts_rgb: torch.Tensor = None, paths: List[str] = []) -> None: """Save meshes as .ply files. Mainly for vertex color meshes. Args: meshes (Meshes, optional): higher priority than (verts & faces & verts_rgb). Defaults to None. verts (torch.Tensor, optional): lower priority than meshes. Defaults to None. faces (torch.Tensor, optional): lower priority than meshes. Defaults to None. verts_rgb (torch.Tensor, optional): lower priority than meshes. Defaults to None. paths (List[str], optional): Output .ply file list. Defaults to []. """ if meshes is None: assert verts is not None and faces is not None, 'Not mesh input.' meshes = Meshes( verts=verts, faces=faces, textures=TexturesVertex( verts_features=verts_rgb) if verts_rgb is not None else None) else: if verts is not None or faces is not None or verts_rgb is not None: warnings.warn('Redundant input, will use meshes only.') assert len(paths) >= len(meshes), 'Not enough output paths.' writer = IO() if not isinstance(paths, list): paths = [paths] for idx in range(len(meshes)): assert paths[idx].endswith('.ply'), 'Please save as .ply files.' writer.save_mesh( meshes[idx], paths[idx], colors_as_uint8=True, binary=False)
[docs]def save_meshes_as_objs(meshes: Meshes = None, paths: List[str] = []) -> None: """Save meshes as .obj files. Mainly for uv texture meshes. Args: meshes (Meshes, optional): Defaults to None. paths (List[str], optional): Output .obj file list. Defaults to []. """ assert len(paths) >= len(meshes), 'Not enough output paths.' assert not isinstance(meshes.textures, TexturesVertex), 'For vertex ' 'color mesh please use save_meshes_as_plys.' if not isinstance(paths, list): paths = [paths] for idx in range(len(meshes)): prepare_output_path( paths[idx], allowed_suffix=['.obj'], path_type=['file']), 'Please save as .obj files.' save_obj( f=paths[idx], verts=meshes.verts_padded()[idx], faces=meshes.faces_padded()[idx], verts_uvs=meshes.textures.verts_uvs_padded()[idx], faces_uvs=meshes.textures.faces_uvs_padded()[idx], texture_map=meshes.textures.maps_padded()[idx])