[Mesh] load_obj, verts, faces_idx, verts_rgb
# Util function for loading meshes
from pytorch3d.io import load_objs_as_meshes, save_obj
from pytorch3d.loss import (
chamfer_distance,
mesh_edge_loss,
mesh_laplacian_smoothing,
mesh_normal_consistency,
)
# Data structures and functions for rendering
from pytorch3d.structures import Meshes
from pytorch3d.renderer import (
look_at_view_transform,
FoVPerspectiveCameras,
PointLights,
DirectionalLights,
Materials,
RasterizationSettings,
MeshRenderer,
MeshRasterizer,
SoftPhongShader,
SoftSilhouetteShader,
SoftPhongShader,
TexturesVertex
)
...
verts, faces_idx, _ = load_obj(obj_filename)
faces = faces_idx.verts_idx
# Initialize each vertex to be white in color.
verts_rgb = torch.ones_like(verts)[None] # (1, V, 3) --> None으로 배치차원 추가
textures = TexturesVertex(verts_features=verts_rgb.to(device))
# Create a Meshes object
mesh = Meshes(
verts=[verts.to(device)],
faces=[faces.to(device)],
textures=textures
)
# Render the plotly figure
fig = plot_scene({
"subplot1": {
"cow_mesh": mesh
}
})
fig.show()
pytorch3d.io offical document에서 pytorch3d.io.load_obj를 이해해봅시다.
pytorch3d.io.load_obj(f, load_textures=True, create_texture_atlas: bool = False, texture_atlas_size: int = 4, texture_wrap: Optional[str] = ‘repeat’, device: Union[str, torch.device] = ‘cpu’, path_manager: Optional[iopath.common.file_io.PathManager] = None)
Load a mesh from a .obj file and optionally textures from a .mtl file. Currently this handles verts, faces, vertex texture uv coordinates, normals, texture images and material reflectivity values.
Parameters:
- f – A file-like object (with methods read, readline, tell, and seek), a pathlib path or a string containing a file name.
- load_textures – Boolean indicating whether material files are loaded
- create_texture_atlas – Bool, If True a per face texture map is created and a tensor texture_atlas is also returned in aux.
- texture_atlas_size – Int specifying the resolution of the texture map per face when create_texture_atlas=True. A (texture_size, texture_size, 3) map is created per face.
- texture_wrap – string, one of [“repeat”, “clamp”]. This applies when computing the texture atlas. If texture_mode=”repeat”, for uv values outside the range [0, 1] the integer part is ignored and a repeating pattern is formed. If texture_mode=”clamp” the values are clamped to the range [0, 1]. If None, then there is no transformation of the texture values.
- device – Device (as str or torch.device) on which to return the new tensors.
- path_manager – optionally a PathManager object to interpret paths.
Example .obj file format:
# this is a comment
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
vt 0.748573 0.750412
vt 0.749279 0.501284
vt 0.999110 0.501077
vt 0.999455 0.750380
vn 0.000000 0.000000 -1.000000
vn -1.000000 -0.000000 -0.000000
vn -0.000000 -0.000000 1.000000
f 5/2/1 1/2/1 4/3/1
f 5/1/1 4/3/1 2/4/1
- 첫번째 triangle은 5/2/1, 1/2/1, 4/3/1 조합
- index of vertex/index of texture coordinate/index of normal 이므로
- index of vertex만 보면 –> 5번째, 1번째, 4번째 vertex
- index of coordinate만 보면 –> 2번째, 2번째, 3번째 texture coordinate
- index of normal만 보면 –> 1번째, 1번째, 1번째 normal (평평한 표면(facet)일 경우 triangle(=face)의 3개의 정점에 대한 normal은 같음)
- 두번째 triangle은 5/1/1, 4/3/1, 2/4/1 조합
- index of vertex/index of texture coordinate/index of normal 이므로
- index of vertex만 보면 –> 5번째, 4번째, 2번째 vertex
- index of coordinate만 보면 –> 1번째, 3번째, 4번째 texture coordinate
- index of normal만 보면 –> 1번째, 1번째, 1번째 normal (평평한 표면(facet)일 경우 triangle(=face)의 3개의 정점에 대한 normal은 같음)
The first character of the line denotes the type of input:
- v is a vertex
- vt is the texture coordinate of one vertex
- vn is the normal of one vertex
- f is a face
Faces are interpreted as follows:
5/2/1 describes the first vertex of the first triangle
- 5: index of vertex [1.000000 1.000000 -1.000000]
- 2: index of texture coordinate [0.749279 0.501284]
- 1: index of normal [0.000000 0.000000 -1.000000]
If there are faces with more than 3 vertices they are subdivided into triangles. Polygonal faces are assumed to have vertices ordered counter-clockwise so the (right-handed) normal points out of the screen e.g. a proper rectangular face would be specified like this:
0_________1
| |
| |
3 ________2
The face would be split into two triangles: (0, 2, 1) and (0, 3, 2), both of which are also oriented counter-clockwise and have normals pointing out of the screen.
Returns:
6-element tuple containing
- verts: FloatTensor of shape (V, 3).
- faces: NamedTuple with fields:
- verts_idx: LongTensor of vertex indices, shape (F, 3).
- normals_idx: (optional) LongTensor of normal indices, shape (F, 3).
- textures_idx: (optional) LongTensor of texture indices, shape (F, 3). This can be used to index into verts_uvs.
- materials_idx: (optional) List of indices indicating which material the texture is derived from for each face. If there is no material for a face, the index is -1. This can be used to retrieve the corresponding values in material_colors/texture_images after they have been converted to tensors or Materials/Textures data structures - see textures.py and materials.py for more info.
- aux: NamedTuple with fields:
- normals: FloatTensor of shape (N, 3)
- verts_uvs: FloatTensor of shape (T, 2), giving the uv coordinate per vertex. If a vertex is shared between two faces, it can have a different uv value for each instance. Therefore it is possible that the number of verts_uvs is greater than num verts i.e. T > V. vertex.
- material_colors: if load_textures=True and the material has associated properties this will be a dict of material names and properties of the form:
{ material_name_1: { "ambient_color": tensor of shape (1, 3), "diffuse_color": tensor of shape (1, 3), "specular_color": tensor of shape (1, 3), "shininess": tensor of shape (1) }, material_name_2: {}, ... }
If a material does not have any properties it will have an empty dict. If load_textures=False, material_colors will None.
- texture_images: if load_textures=True and the material has a texture map, this will be a dict of the form:
{ material_name_1: (H, W, 3) image, ... }
If load_textures=False, texture_images will None.
- texture_atlas: if load_textures=True and create_texture_atlas=True, this will be a FloatTensor of the form: (F, texture_size, textures_size, 3) If the material does not have a texture map, then all faces will have a uniform white texture. Otherwise texture_atlas will be None.
Leave a comment