def load_objs_as_meshes( files: list, device=None, load_textures: bool = True, create_texture_atlas: bool = False, texture_atlas_size: int = 4, texture_wrap: Optional[str] = "repeat", path_manager: Optional[PathManager] = None, ): """ Load meshes from a list of .obj files using the load_obj function, and return them as a Meshes object. This only works for meshes which have a single texture image for the whole mesh. See the load_obj function for more details. material_colors and normals are not stored. Args: files: A list of file-like objects (with methods read, readline, tell, and seek), pathlib paths or strings containing file names. device: Desired device of returned Meshes. Default: uses the current device for the default tensor type. load_textures: Boolean indicating whether material files are loaded create_texture_atlas, texture_atlas_size, texture_wrap: as for load_obj. path_manager: optionally a PathManager object to interpret paths. Returns: New Meshes object. """ mesh_list = [] for f_obj in files: verts, faces, aux = load_obj( f_obj, load_textures=load_textures, create_texture_atlas=create_texture_atlas, texture_atlas_size=texture_atlas_size, texture_wrap=texture_wrap, path_manager=path_manager, ) tex = None if create_texture_atlas: # TexturesAtlas type tex = TexturesAtlas(atlas=[aux.texture_atlas.to(device)]) else: # TexturesUV type tex_maps = aux.texture_images if tex_maps is not None and len(tex_maps) > 0: verts_uvs = aux.verts_uvs.to(device) # (V, 2) faces_uvs = faces.textures_idx.to(device) # (F, 3) image = list(tex_maps.values())[0].to(device)[None] tex = TexturesUV(verts_uvs=[verts_uvs], faces_uvs=[faces_uvs], maps=image) mesh = Meshes(verts=[verts.to(device)], faces=[faces.verts_idx.to(device)], textures=tex) mesh_list.append(mesh) if len(mesh_list) == 1: return mesh_list[0] return join_meshes_as_batch(mesh_list)
def _get_textures(self, tex_im): # tex_im is a tensor that contains the non-flipped and flipped albedo_map tex_im = tex_im.permute(0,2,3,1)/2.+0.5 # print(f"texture max: {torch.max(tex_im)}") # print(f"texture min: {torch.min(tex_im)}") b, h, w, c = tex_im.shape assert w == self.image_size and h == self.image_size, "Texture image has the wrong resolution." textures = TexturesUV(maps=tex_im, # texture maps are BxHxWx3 faces_uvs=self.tex_faces_uv.repeat(b, 1, 1), verts_uvs=self.tex_verts_uv.repeat(b, 1, 1)) return textures
def load_objs_as_meshes( files: list, device=None, load_textures: bool = True, create_texture_atlas: bool = False, texture_atlas_size: int = 4, texture_wrap: Optional[str] = "repeat", path_manager: Optional[PathManager] = None, ): """ Load meshes from a list of .obj files using the load_obj function, and return them as a Meshes object. This only works for meshes which have a single texture image for the whole mesh. See the load_obj function for more details. material_colors and normals are not stored. Args: files: A list of file-like objects (with methods read, readline, tell, and seek), pathlib paths or strings containing file names. device: Desired device of returned Meshes. Default: uses the current device for the default tensor type. load_textures: Boolean indicating whether material files are loaded create_texture_atlas, texture_atlas_size, texture_wrap: as for load_obj. path_manager: optionally a PathManager object to interpret paths. Returns: New Meshes object. """ mesh_list = [] for f_obj in files: verts, faces, aux = load_obj( f_obj, load_textures=load_textures, create_texture_atlas=create_texture_atlas, texture_atlas_size=texture_atlas_size, texture_wrap=texture_wrap, path_manager=path_manager, ) tex = None if create_texture_atlas: # TexturesAtlas type tex = TexturesAtlas(atlas=[aux.texture_atlas.to(device)]) else: # TexturesUV type tex_maps = aux.texture_images textures = [] if tex_maps is not None and len(tex_maps) > 0: verts_uvs = aux.verts_uvs.to(device) # (V, 2) faces_uvs = faces.textures_idx.to(device) # (F, 3) face_to_mat = faces.materials_idx # code for checking current_offset = 0 for mat_idx, (mat_name, tex_map) in enumerate(tex_maps.items()): image = tex_map.flip(0).unsqueeze(0).to(device) faces_mask = face_to_mat == mat_idx faces_verts_uvs = faces_uvs[faces_mask].unique() tex_verts_uvs = verts_uvs[faces_verts_uvs] tex_faces_uvs = faces_uvs[faces_mask] - current_offset tex = TexturesUV(verts_uvs=[tex_verts_uvs], faces_uvs=[tex_faces_uvs], maps=image, mat_names=[mat_name]) textures.append(tex) current_offset += tex_verts_uvs.shape[0] tex = textures[0] if len(textures) > 1: tex = tex.join_batch(textures[1:]).join_scene() mesh = Meshes(verts=[verts.to(device)], faces=[faces.verts_idx.to(device)], textures=tex, aux=aux) mesh_list.append(mesh) if len(mesh_list) == 1: return mesh_list[0] return join_meshes_as_batch(mesh_list)
def forward(self, verts, # under general camera coordinate rXdYfZ, N*V*3 faces, # indices in verts to define traingles, N*F*3 verts_uvs, # uv coordinate of corresponding verts, N*V*2 faces_uvs, # indices in verts to define triangles, N*F*3 tex_image, # under GCcd, N*H*W*3 R, # under GCcd, N*3*3 T, # under GCcd, N*3 f, # in pixel/m, N*1 C, # camera center, N*2 imgres, # int lightLoc = None): assert verts.shape[0] == 1,\ 'with some issues in pytorch3D, render 1 mesh per forward' # only need to convert either R and T or verts, we choose R and T here if self.convertToPytorch3D: R = torch.matmul(self.GCcdToPytorch3D, R) T = torch.matmul(self.GCcdToPytorch3D, T.unsqueeze(-1)).squeeze(-1) # prepare textures and mesh to render tex = TexturesUV( verts_uvs = verts_uvs, faces_uvs = faces_uvs, maps = tex_image ) mesh = Meshes(verts = verts, faces = faces, textures=tex) # Initialize a camera. The world coordinate is +Y up, +X left and +Z in. cameras = PerspectiveCameras( focal_length=f, principal_point=C, R=R, T=T, image_size=((imgres,imgres),), device=self.device ) # Define the settings for rasterization and shading. raster_settings = RasterizationSettings( image_size=imgres, blur_radius=0.0, faces_per_pixel=1, ) # Create a simple renderer by composing a rasterizer and a shader. # The simple textured shader will interpolate the texture uv coordinates # for each pixel, sample from a texture image. This renderer can # support lighting easily but we do not iimplement it. renderer = MeshRenderer( rasterizer=MeshRasterizer( cameras=cameras, raster_settings=raster_settings ), shader=SimpleShader( device=self.device ) ) # render the rendered image(s) images = renderer(mesh) return images