import trimesh import torch import numpy as np def subdivide(vertices, faces, attributes=None, face_index=None): """ Subdivide a mesh into smaller triangles. Note that if `face_index` is passed, only those faces will be subdivided and their neighbors won't be modified making the mesh no longer "watertight." Parameters ---------- vertices : (n, 3) float Vertices in space faces : (n, 3) int Indexes of vertices which make up triangular faces attributes: (n, d) float vertices attributes face_index : faces to subdivide. if None: all faces of mesh will be subdivided if (n,) int array of indices: only specified faces Returns ---------- new_vertices : (n, 3) float Vertices in space new_faces : (n, 3) int Remeshed faces """ if face_index is None: face_index = np.arange(len(faces)) else: face_index = np.asanyarray(face_index) # the (c,3) int set of vertex indices faces = faces[face_index] # the (c, 3, 3) float set of points in the triangles triangles = vertices[faces] # the 3 midpoints of each triangle edge # stacked to a (3 * c, 3) float mid = np.vstack([triangles[:, g, :].mean(axis=1) for g in [[0, 1], [1, 2], [2, 0]]]) # for adjacent faces we are going to be generating # the same midpoint twice so merge them here mid_idx = (np.arange(len(face_index) * 3)).reshape((3, -1)).T unique, inverse = trimesh.grouping.unique_rows(mid) mid = mid[unique] mid_idx = inverse[mid_idx] + len(vertices) # the new faces with correct winding f = np.column_stack([faces[:, 0], mid_idx[:, 0], mid_idx[:, 2], mid_idx[:, 0], faces[:, 1], mid_idx[:, 1], mid_idx[:, 2], mid_idx[:, 1], faces[:, 2], mid_idx[:, 0], mid_idx[:, 1], mid_idx[:, 2]]).reshape((-1, 3)) # add the 3 new faces per old face new_faces = np.vstack((faces, f[len(face_index):])) # replace the old face with a smaller face new_faces[face_index] = f[:len(face_index)] new_vertices = np.vstack((vertices, mid)) if attributes is not None: tri_att = attributes[faces] mid_att = np.vstack([tri_att[:, g, :].mean(axis=1) for g in [[0, 1], [1, 2], [2, 0]]]) mid_att = mid_att[unique] new_attributes = np.vstack((attributes, mid_att)) return new_vertices, new_faces, new_attributes, unique return new_vertices, new_faces, unique def subdivide_inorder(vertices, faces, unique): triangles = vertices[faces] mid = torch.vstack([triangles[:, g, :].mean(1) for g in [[0, 1], [1, 2], [2, 0]]]) mid = mid[unique] new_vertices = torch.vstack((vertices, mid)) return new_vertices