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”: https://search.ieice.org/bin/summary.php?id=e74-d_1_214.

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

  • faces (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_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')