kaolin.ops.conversions

API

kaolin.ops.conversions.marching_tetrahedra(vertices, tets, sdf, return_tet_idx=False)

Convert discrete signed distance fields encoded on tetrahedral grids to triangle meshes using marching tetrahedra algorithm as described in An efficient method of triangulating equi-valued surfaces by using tetrahedral cells. The output surface is differentiable with respect to input vertex positions and the SDF values. For more details and example usage in learning, see Deep Marching Tetrahedra: a Hybrid Representation for High-Resolution 3D Shape Synthesis NeurIPS 2021.

Parameters
  • vertices (torch.tensor) – batched vertices of tetrahedral meshes, of shape \((\text{batch_size}, \text{num_vertices}, 3)\).

  • tets (torch.tensor) – unbatched tetrahedral mesh topology, of shape \((\text{num_tetrahedrons}, 4)\).

  • sdf (torch.tensor) – batched SDFs which specify the SDF value of each vertex, of shape \((\text{batch_size}, \text{num_vertices})\).

  • return_tet_idx (optional, bool) – if True, return index of tetrahedron where each face is extracted. Default: False.

Returns

  • the list of vertices for mesh converted from each tetrahedral grid.

  • the list of faces for mesh converted from each tetrahedral grid.

  • the list of indices that correspond to tetrahedra where faces are extracted.

Return type

(list[torch.Tensor], list[torch.LongTensor], (optional) list[torch.LongTensor])

Example

>>> vertices = torch.tensor([[[0, 0, 0],
...               [1, 0, 0],
...               [0, 1, 0],
...               [0, 0, 1]]], dtype=torch.float)
>>> tets = torch.tensor([[0, 1, 2, 3]], dtype=torch.long)
>>> sdf = torch.tensor([[-1., -1., 0.5, 0.5]], dtype=torch.float)
>>> verts_list, faces_list, tet_idx_list = marching_tetrahedra(vertices, tets, sdf, True)
>>> verts_list[0]
tensor([[0.0000, 0.6667, 0.0000],
        [0.0000, 0.0000, 0.6667],
        [0.3333, 0.6667, 0.0000],
        [0.3333, 0.0000, 0.6667]])
>>> faces_list[0]
tensor([[3, 0, 1],
        [3, 2, 0]])
>>> tet_idx_list[0]
tensor([0, 0])
kaolin.ops.conversions.pointclouds_to_voxelgrids(pointclouds, resolution, origin=None, scale=None, return_sparse=False)

Converts pointclouds to voxelgrids. It separates the 3D space into empty voxelgrid, and for each boxes, if there is a corresponding point, set that voxelgrid to be occupied.

Will convert only points in the range [0, 1] after been shifted and scaled as following (pointclouds - origin) * scale.

Parameters
  • pointclouds (torch.Tensor) – Exact batched pointclouds, of shape \((\text{batch_size}, \text{num_points}, 3)\).

  • resolution (int) – Resolution of output voxelgrids.

  • origin (optional, torch.Tensor) – Origin of the voxelgrid in the pointcloud coordinates, of shape \((\text{batch_size}, 3)\). Default: torch.min(pointcloud, dim=1)[0].

  • scale (optional, torch.Tensor) – Scale by which we divide the pointclouds’ coordinates, of shape \((\text{batch_size})\). Default: torch.max(torch.max(pointclouds, dim=1)[0] - origin, dim=1)[0].

  • return_sparse (optional, bool) – Whether to return a sparse voxelgrids or not. Default: False.

Returns

Exact batched voxelgrids, of shape \((\text{batch_size}, \text{resolution}, \text{resolution}, \text{resolution})\). If return_sparse is True, a sparse FloatTensor is returned.

Return type

(torch.Tensor or torch.FloatTensor)

Example

>>> pointclouds = torch.tensor([[[0, 0, 0],
...                              [1, 1, 1],
...                              [2, 2, 2]]], dtype=torch.float)
>>> pointclouds_to_voxelgrids(pointclouds, 3)
tensor([[[[1., 0., 0.],
          [0., 0., 0.],
          [0., 0., 0.]],

         [[0., 0., 0.],
          [0., 1., 0.],
          [0., 0., 0.]],

         [[0., 0., 0.],
          [0., 0., 0.],
          [0., 0., 1.]]]])
kaolin.ops.conversions.sdf_to_voxelgrids(sdf, bbox_center=0.0, bbox_dim=1.0, init_res=32, upsampling_steps=0)

Converts SDFs to voxelgrids.

For each SDF returns a voxel grid with resolution \(init\_res * 2 ^ {upsampling\_steps} + 1\) (so the underlying voxel resolution is \(init\_res * 2 ^ {upsampling\_steps}\)) where each grid point holds a binary value determined by the sign of the SDF at the location of the grid point after normalizing the voxel grid to the bounding box defined by bbox_center and bbox_dim.

This solution is largely borrowed from “Multiresolution IsoSurface Extraction (MISE)” proposed in the CVPR 2019 paper “Occupancy Networks: Learning 3D Reconstruction in Function Space”: https://arxiv.org/abs/1906.02739. Instead of evaluating SDF values of all grid points at high resolution, this function incrementally builds an octree and only evaluate dense grid points around the surface.

Parameters
  • sdf (list[callable]) – A list of callable that takes 3D coordinates as a torch.Tensor, of shape \((\text{num_points}, 3)\) and output the N corresponding SDF values as a torch.Tensor, of shape \((\text{num_points})\).

  • bbox_center (optional, float) – Center of the surface’s bounding box. Default: 0.

  • bbox_dim (optional, float) – Largest dimension of the surface’s bounding box. Default: 1.

  • init_res (optional, int) – The initial resolution of the voxelgrids, should be large enough to properly define the surface. Default: 32.

  • upsampling_steps (optional, int) – Number of times the initial resolution will be doubled. Default: 0.

Returns

Binary voxelgrids, of shape \((\text{batch_size}, \text{init_res} * 2 ^ \text{upsampling_steps} + 1)\).

Return type

(torch.Tensor)

Example

>>> def sphere(points):
...     return torch.sum(points ** 2, 1) ** 0.5 - 0.5
>>> sdf_to_voxelgrids([sphere], init_res=4)
tensor([[[[0., 0., 0., 0., 0.],
          [0., 0., 0., 0., 0.],
          [0., 0., 1., 0., 0.],
          [0., 0., 0., 0., 0.],
          [0., 0., 0., 0., 0.]],

         [[0., 0., 0., 0., 0.],
          [0., 1., 1., 1., 0.],
          [0., 1., 1., 1., 0.],
          [0., 1., 1., 1., 0.],
          [0., 0., 0., 0., 0.]],

         [[0., 0., 1., 0., 0.],
          [0., 1., 1., 1., 0.],
          [1., 1., 1., 1., 1.],
          [0., 1., 1., 1., 0.],
          [0., 0., 1., 0., 0.]],

         [[0., 0., 0., 0., 0.],
          [0., 1., 1., 1., 0.],
          [0., 1., 1., 1., 0.],
          [0., 1., 1., 1., 0.],
          [0., 0., 0., 0., 0.]],

         [[0., 0., 0., 0., 0.],
          [0., 0., 0., 0., 0.],
          [0., 0., 1., 0., 0.],
          [0., 0., 0., 0., 0.],
          [0., 0., 0., 0., 0.]]]])
kaolin.ops.conversions.trianglemeshes_to_voxelgrids(vertices, faces, resolution, origin=None, scale=None, return_sparse=False)

Converts meshes to surface voxelgrids of a given resolution. It first upsamples triangle mesh’s vertices to given resolution, then it performs a box test. If a voxel contains a triangle vertex, set that voxel to 1. Vertex will be offset and scaled as following: \(\text{normalized_vertices} = (\text{vertices} - \text{origin}) / \text{scale}\) the voxelgrids will only be generated in the range [0, 1] of normalized_vertices.

Parameters
  • vertices (torch.tensor) – Batched vertices of the input meshes, of shape \((\text{batch_size}, \text{num_vertices}, 3)\).

  • faces (torch.tensor) – Unbatched faces of the meshes, of shape \((\text{num_faces}, 3)\).

  • resolution (int) – desired resolution of generated voxelgrid.

  • origin (torch.tensor) – Origin of the voxelgrid in the mesh coordinates, of shape \((\text{batch_size}, 3)\). Default: torch.min(vertices, dim=1)[0].

  • scale (torch.tensor) – The scale by which we divide the vertex position, of shape \((\text{batch_size})\). Default: torch.max(torch.max(vertices, dim=1)[0] - origin, dim=1)[0].

  • return_sparse (optional, bool) – If True, sparse tensor is returned. Default: False.

Returns

Binary batched voxelgrids, of shape \((\text{batch_size}, \text{resolution}, \text{resolution}, \text{resolution})\). If return_sparse is True, sparse tensor is returned.

Return type

(torch.Tensor or torch.FloatTensor)

Example

>>> vertices = torch.tensor([[[0, 0, 0],
...                           [1, 0, 0],
...                           [0, 0, 1]]], dtype=torch.float)
>>> faces = torch.tensor([[0, 1, 2]], dtype=torch.long)
>>> origin = torch.zeros((1, 3))
>>> scale = torch.ones((1))
>>> trianglemeshes_to_voxelgrids(vertices, faces, 3, origin, scale)
tensor([[[[1., 1., 1.],
          [0., 0., 0.],
          [0., 0., 0.]],

         [[1., 1., 0.],
          [0., 0., 0.],
          [0., 0., 0.]],

         [[1., 0., 0.],
          [0., 0., 0.],
          [0., 0., 0.]]]])
kaolin.ops.conversions.unbatched_mesh_to_spc(face_vertices, level)

Convert a mesh into a Structured Point Cloud octree.

The conversion is using a conservative rasterization process, the resulting octree is fully wrapping the mesh.

Note

The mesh will be voxelized in the range \([-1, 1]\) of the vertices coordinate system.

Parameters
Returns

  • The generated octree, of size \((\text{num_nodes})\), where \(\text{num_nodes}\) depends on the geometry of the input mesh.

  • The indices of the face corresponding to each voxel at the highest level, of shape \((\text{num_voxels})\).

  • The barycentric coordinates of the voxel with respect to corresponding face of shape \((\text{num_vertices}, 2)\).

Return type

(torch.ByteTensor, torch.LongTensor, torch.FloatTensor)

kaolin.ops.conversions.unbatched_pointcloud_to_spc(pointcloud, level, features=None)

This function takes as input a single point-cloud - a set of continuous coordinates in 3D, and coverts it into a Structured Point Cloud (SPC), a compressed octree representation where the point cloud coordinates are quantized to integer coordinates.

Point coordinates are expected to be normalized to the range \([-1, 1]\). If a point is out of the range \([-1, 1]\) it will be clipped to it.

If features are specified, the current implementation will average features of points that inhabit the same quantized bucket.

Parameters
  • pointclouds (torch.Tensor) – An unbatched pointcloud, of shape \((\text{num_points}, 3)\). Coordinates are expected to be normalized to the range \([-1, 1]\).

  • level (int) – Maximum number of levels to use in octree hierarchy.

  • features (optional, torch.Tensor) – Feature vector containing information per point, of shape \((\text{num_points}, \text{feat_dim})\).

Returns

A Structured Point Cloud (SPC) object, holding a single-item batch.

Return type

(kaolin.rep.Spc)

kaolin.ops.conversions.voxelgrids_to_cubic_meshes(voxelgrids, is_trimesh=True)

Convert voxelgrids to meshes by replacing each occupied voxel with a cuboid mesh (unit cube). Each cube has 8 vertices and 6 (for quadmesh) or 12 faces (for triangular mesh). Internal faces are ignored. If is_trimesh==True, this function performs the same operation as “Cubify” defined in the ICCV 2019 paper “Mesh R-CNN”: https://arxiv.org/abs/1906.02739.

Parameters
  • voxelgrids (torch.Tensor) – binary voxel array, of shape \((\text{batch_size}, \text{X}, \text{Y}, \text{Z})\).

  • is_trimesh (optional, bool) – if True, the outputs are triangular meshes. Otherwise quadmeshes are returned. Default: True.

Returns

  • The list of vertices for each mesh.

  • The list of faces for each mesh.

Return type

(list[torch.Tensor], list[torch.LongTensor])

Example

>>> voxelgrids = torch.ones((1, 1, 1, 1))
>>> verts, faces = voxelgrids_to_cubic_meshes(voxelgrids)
>>> verts[0]
tensor([[0., 0., 0.],
        [0., 0., 1.],
        [0., 1., 0.],
        [0., 1., 1.],
        [1., 0., 0.],
        [1., 0., 1.],
        [1., 1., 0.],
        [1., 1., 1.]])
>>> faces[0]
tensor([[0, 1, 2],
        [5, 4, 7],
        [0, 4, 1],
        [6, 2, 7],
        [0, 2, 4],
        [3, 1, 7],
        [3, 2, 1],
        [6, 7, 4],
        [5, 1, 4],
        [3, 7, 2],
        [6, 4, 2],
        [5, 7, 1]])
kaolin.ops.conversions.voxelgrids_to_trianglemeshes(voxelgrids, iso_value=0.5)

Converts voxelgrids to triangle meshes using marching cube algorithm. Please refer to: Lorensen, William E.; Cline, Harvey E. in Marching cubes, A high resolution 3D surface construction algorithm

Parameters
  • voxelgrids (torch.Tensor) – Exact batched voxel array with shape \((\text{batch_size}, \text{X}, \text{Y}, \text{Z})\).

  • iso_value (optional, float) – Value in the range \([0, 1]\) used to determine whether a voxel is inside the surface or not. Isovalue is also used to interpolate newly created triangle vertices. Defaults to 0.5

Returns

  • The list of vertices of each mesh.

  • The list of faces of each mesh.

Return type

(list[torch.FloatTensor], list[torch.LongTensor])

Example

>>> voxelgrid = torch.tensor([[[[1, 0],
...                             [0, 0]],
...                            [[0, 0],
...                             [0, 0]]]], device='cuda', dtype=torch.uint8)
>>> vertices, faces = voxelgrids_to_trianglemeshes(voxelgrid)
>>> vertices[0]
tensor([[1.0000, 1.0000, 0.5000],
        [1.0000, 0.5000, 1.0000],
        [0.5000, 1.0000, 1.0000],
        [1.0000, 1.0000, 1.5000],
        [1.0000, 1.5000, 1.0000],
        [1.5000, 1.0000, 1.0000]], device='cuda:0')
>>> faces[0]
tensor([[0, 1, 2],
        [3, 2, 1],
        [4, 0, 2],
        [4, 2, 3],
        [0, 5, 1],
        [5, 3, 1],
        [4, 5, 0],
        [5, 4, 3]], device='cuda:0')