예제 #1
0
def ico_sphere(level: int = 0, device=None):
    """
    Create verts and faces for a unit ico-sphere, with all faces oriented
    consistently.

    Args:
        level: integer specifying the number of iterations for subdivision
               of the mesh faces. Each additional level will result in four new
               faces per face.
        device: A torch.device object on which the outputs will be allocated.

    Returns:
        Meshes object with verts and faces.
    """
    if device is None:
        device = torch.device("cpu")
    if level < 0:
        raise ValueError("level must be >= 0.")
    if level == 0:
        verts = torch.tensor(_ico_verts0, dtype=torch.float32, device=device)
        faces = torch.tensor(_ico_faces0, dtype=torch.int64, device=device)

    else:
        mesh = ico_sphere(level - 1, device)
        subdivide = SubdivideMeshes()
        mesh = subdivide(mesh)
        verts = mesh.verts_list()[0]
        verts /= verts.norm(p=2, dim=1, keepdim=True)
        faces = mesh.faces_list()[0]
    return Meshes(verts=[verts], faces=[faces])
예제 #2
0
    def simple_subdivide(self, with_init=False):
        # Create a mesh with one face and check the subdivided mesh has
        # 4 faces with the correct vertex coordinates.
        device = torch.device("cuda:0")
        verts = torch.tensor(
            [[0.5, 1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0]],
            dtype=torch.float32,
            device=device,
            requires_grad=True,
        )
        faces = torch.tensor([[0, 1, 2]], dtype=torch.int64, device=device)
        mesh = Meshes(verts=[verts], faces=[faces])
        mesh_init = mesh.clone() if with_init else None
        subdivide = SubdivideMeshes(meshes=mesh_init)
        new_mesh = subdivide(mesh)

        # Subdivided face:
        #
        #           v0
        #           /\
        #          /  \
        #         / f0 \
        #     v4 /______\ v3
        #       /\      /\
        #      /  \ f3 /  \
        #     / f2 \  / f1 \
        #    /______\/______\
        #  v2       v5       v1
        #
        gt_subdivide_verts = torch.tensor(
            [
                [0.5, 1.0, 0.0],
                [1.0, 0.0, 0.0],
                [0.0, 0.0, 0.0],
                [0.75, 0.5, 0.0],
                [0.25, 0.5, 0.0],
                [0.5, 0.0, 0.0],
            ],
            dtype=torch.float32,
            device=device,
        )
        gt_subdivide_faces = torch.tensor(
            [[0, 3, 4], [1, 5, 3], [2, 4, 5], [5, 4, 3]],
            dtype=torch.int64,
            device=device,
        )
        new_verts, new_faces = new_mesh.get_mesh_verts_faces(0)
        self.assertClose(new_verts, gt_subdivide_verts)
        self.assertClose(new_faces, gt_subdivide_faces)
        self.assertTrue(new_verts.requires_grad == verts.requires_grad)
예제 #3
0
 def test_subdivide_features(self):
     device = torch.device("cuda:0")
     mesh = ico_sphere(0, device)
     N = 10
     mesh = mesh.extend(N)
     edges = mesh.edges_packed()
     V = mesh.num_verts_per_mesh()[0]
     D = 256
     feats = torch.rand((N * V, D),
                        dtype=torch.float32,
                        device=device,
                        requires_grad=True)  # packed features
     app_feats = feats[edges].mean(1)
     subdivide = SubdivideMeshes()
     new_mesh, new_feats = subdivide(mesh, feats)
     gt_feats = torch.cat((feats.view(N, V, D), app_feats.view(N, -1, D)),
                          dim=1).view(-1, D)
     self.assertClose(new_feats, gt_feats)
     self.assertTrue(new_feats.requires_grad == gt_feats.requires_grad)
예제 #4
0
    def test_heterogeneous_meshes(self):
        device = torch.device("cuda:0")
        verts1 = torch.tensor(
            [[0.5, 1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0]],
            dtype=torch.float32,
            device=device,
            requires_grad=True,
        )
        faces1 = torch.tensor([[0, 1, 2]], dtype=torch.int64, device=device)
        verts2 = torch.tensor(
            [[0.5, 1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0],
             [1.5, 1.0, 0.0]],
            dtype=torch.float32,
            device=device,
            requires_grad=True,
        )
        faces2 = torch.tensor([[0, 1, 2], [0, 3, 1]],
                              dtype=torch.int64,
                              device=device)
        faces3 = torch.tensor([[0, 1, 2], [0, 2, 3]],
                              dtype=torch.int64,
                              device=device)
        mesh = Meshes(verts=[verts1, verts2, verts2],
                      faces=[faces1, faces2, faces3])
        subdivide = SubdivideMeshes()
        new_mesh = subdivide(mesh.clone())

        gt_subdivided_verts1 = torch.tensor(
            [
                [0.5, 1.0, 0.0],
                [1.0, 0.0, 0.0],
                [0.0, 0.0, 0.0],
                [0.75, 0.5, 0.0],
                [0.25, 0.5, 0.0],
                [0.5, 0.0, 0.0],
            ],
            dtype=torch.float32,
            device=device,
        )
        gt_subdivided_faces1 = torch.tensor(
            [[0, 3, 4], [1, 5, 3], [2, 4, 5], [5, 4, 3]],
            dtype=torch.int64,
            device=device,
        )
        # faces2:
        #
        #         v0 _______e2_______ v3
        #           /\              /
        #          /  \            /
        #         /    \          /
        #     e1 /      \ e0     / e4
        #       /        \      /
        #      /          \    /
        #     /            \  /
        #    /______________\/
        #  v2       e3      v1
        #
        # Subdivided faces2:
        #
        #         v0 _______v6_______ v3
        #           /\      /\      /
        #          /  \ f1 /  \ f3 /
        #         / f0 \  / f7 \  /
        #     v5 /______v4______\/v8
        #       /\      /\      /
        #      /  \ f6 /  \ f5 /
        #     / f4 \  / f2 \  /
        #    /______\/______\/
        #  v2       v7       v1
        #
        gt_subdivided_verts2 = torch.tensor(
            [
                [0.5, 1.0, 0.0],
                [1.0, 0.0, 0.0],
                [0.0, 0.0, 0.0],
                [1.5, 1.0, 0.0],
                [0.75, 0.5, 0.0],
                [0.25, 0.5, 0.0],
                [1.0, 1.0, 0.0],
                [0.5, 0.0, 0.0],
                [1.25, 0.5, 0.0],
            ],
            dtype=torch.float32,
            device=device,
        )
        gt_subdivided_faces2 = torch.tensor(
            [
                [0, 4, 5],
                [0, 6, 4],
                [1, 7, 4],
                [3, 8, 6],
                [2, 5, 7],
                [1, 4, 8],
                [7, 5, 4],
                [8, 4, 6],
            ],
            dtype=torch.int64,
            device=device,
        )
        gt_subdivided_verts3 = gt_subdivided_verts2.clone()
        gt_subdivided_verts3[-1, :] = torch.tensor([0.75, 0.5, 0],
                                                   dtype=torch.float32,
                                                   device=device)
        gt_subdivided_faces3 = torch.tensor(
            [
                [0, 4, 5],
                [0, 5, 6],
                [1, 7, 4],
                [2, 8, 5],
                [2, 5, 7],
                [3, 6, 8],
                [7, 5, 4],
                [8, 6, 5],
            ],
            dtype=torch.int64,
            device=device,
        )
        new_mesh_verts1, new_mesh_faces1 = new_mesh.get_mesh_verts_faces(0)
        new_mesh_verts2, new_mesh_faces2 = new_mesh.get_mesh_verts_faces(1)
        new_mesh_verts3, new_mesh_faces3 = new_mesh.get_mesh_verts_faces(2)
        self.assertClose(new_mesh_verts1, gt_subdivided_verts1)
        self.assertClose(new_mesh_faces1, gt_subdivided_faces1)
        self.assertClose(new_mesh_verts2, gt_subdivided_verts2)
        self.assertClose(new_mesh_faces2, gt_subdivided_faces2)
        self.assertClose(new_mesh_verts3, gt_subdivided_verts3)
        self.assertClose(new_mesh_faces3, gt_subdivided_faces3)
        self.assertTrue(new_mesh_verts1.requires_grad == verts1.requires_grad)
        self.assertTrue(new_mesh_verts2.requires_grad == verts2.requires_grad)
        self.assertTrue(new_mesh_verts3.requires_grad == verts2.requires_grad)
예제 #5
0
 def subdivide_meshes():
     subdivide = SubdivideMeshes(meshes=meshes_init)
     subdivide(meshes=meshes.clone())
     torch.cuda.synchronize()