class_docstr: Subdivide a triangle mesh by adding a new vertex at the center of each edge
  and dividing each face into four new faces. Vectors of vertex
  attributes can also be subdivided by averaging the values of the attributes
  at the two vertices which form each edge. This implementation
  preserves face orientation - if the vertices of a face are all ordered
  counter-clockwise, then the faces in the subdivided meshes will also have
  their vertices ordered counter-clockwise.
  
  If meshes is provided as an input, the initializer performs the relatively
  expensive computation of determining the new face indices. This one-time
  computation can be reused for all meshes with the same face topology
  but different vertex positions.
class_docstr_tok: ["Subdivide","a","triangle","mesh","by","adding","a","new","vertex","at","the","center","of","each","edge","and","dividing","each","face","into","four","new","faces",".","Vectors","of","vertex","attributes","can","also","be","subdivided","by","averaging","the","values","of","the","attributes","at","the","two","vertices","which","form","each","edge",".","This","implementation","preserves","face","orientation","-","if","the","vertices","of","a","face","are","all","ordered","counter-clockwise",",","then","the","faces","in","the","subdivided","meshes","will","also","have","their","vertices","ordered","counter-clockwise",".","If","meshes","is","provided","as","an","input",",","the","initializer","performs","the","relatively","expensive","computation","of","determining","the","new","face","indices",".","This","one-time","computation","can","be","reused","for","all","meshes","with","the","same","face","topology","but","different","vertex","positions","."]
docstr: Subdivide faces, verts (and optionally features) of a batch of meshes
  where each mesh can have different face topologies.
  
  Args:
      meshes: Meshes object representing a batch of meshes.
      feats: Per-vertex features to be subdivided along with the verts.
  
  Returns:
      2-element tuple containing
  
      - **new_meshes**: Meshes object of a batch of subdivided meshes.
      - **new_feats**: (optional) Tensor of subdivided feats, parallel to the
        (packed) vertices of the subdivided meshes. Only returned
        if feats is not None.
docstr_tok: ["Subdivide","faces",",","verts","(","and","optionally","features",")","of","a","batch","of","meshes","where","each","mesh","can","have","different","face","topologies",".","Args",":","meshes",":","Meshes","object","representing","a","batch","of","meshes",".","feats",":","Per-vertex","features","to","be","subdivided","along","with","the","verts",".","Returns",":","2-element","tuple","containing","-","*","*","new_meshes","*","*",":","Meshes","object","of","a","batch","of","subdivided","meshes",".","-","*","*","new_feats","*","*",":","(","optional",")","Tensor","of","subdivided","feats",",","parallel","to","the","(","packed",")","vertices","of","the","subdivided","meshes",".","Only","returned","if","feats","is","not","None","."]
code: def subdivide_heterogenerous(self, meshes, feats=None):
      """
      Subdivide faces, verts (and optionally features) of a batch of meshes
      where each mesh can have different face topologies.
  
      Args:
          meshes: Meshes object representing a batch of meshes.
          feats: Per-vertex features to be subdivided along with the verts.
  
      Returns:
          2-element tuple containing
  
          - **new_meshes**: Meshes object of a batch of subdivided meshes.
          - **new_feats**: (optional) Tensor of subdivided feats, parallel to the
            (packed) vertices of the subdivided meshes. Only returned
            if feats is not None.
      """
  
      # The computation of new faces is on face indices, so gradients do not
      # need to be tracked.
      verts = meshes.verts_packed()
      with torch.no_grad():
          new_faces = self.subdivide_faces(meshes)
          edges = meshes.edges_packed()
          face_to_mesh_idx = meshes.faces_packed_to_mesh_idx()
          edge_to_mesh_idx = meshes.edges_packed_to_mesh_idx()
          num_edges_per_mesh = edge_to_mesh_idx.bincount(
              minlength=self._N
          )
          num_verts_per_mesh = meshes.num_verts_per_mesh()
          num_faces_per_mesh = meshes.num_faces_per_mesh()
  
          # Add one new vertex at the midpoint of each edge.
          new_verts_per_mesh = (
              num_verts_per_mesh + num_edges_per_mesh
          )  # (N,)
          new_face_to_mesh_idx = torch.cat(
              [face_to_mesh_idx] * 4, dim=0
          )
  
          # Calculate the indices needed to group the new and existing verts
          # for each mesh.
          verts_sort_idx = _create_verts_index(
              num_verts_per_mesh, num_edges_per_mesh, meshes.device
          )  # (sum(V_n)+sum(E_n),)
  
          verts_ordered_idx_init = torch.zeros(
              new_verts_per_mesh.sum(),
              dtype=torch.int64,
              device=meshes.device,
          )  # (sum(V_n)+sum(E_n),)
  
          # Reassign vertex indices so that existing and new vertices for each
          # mesh are sequential.
          verts_ordered_idx = verts_ordered_idx_init.scatter_add(
              0,
              verts_sort_idx,
              torch.arange(
                  new_verts_per_mesh.sum(), device=meshes.device
              ),
          )
  
          # Retrieve vertex indices for each face.
          new_faces = verts_ordered_idx[new_faces]
  
          # Calculate the indices needed to group the existing and new faces
          # for each mesh.
          face_sort_idx = _create_faces_index(
              num_faces_per_mesh, device=meshes.device
          )
  
          # Reorder the faces to sequentially group existing and new faces
          # for each mesh.
          new_faces = new_faces[face_sort_idx]
          new_face_to_mesh_idx = new_face_to_mesh_idx[face_sort_idx]
          new_faces_per_mesh = new_face_to_mesh_idx.bincount(
              minlength=self._N
          )  # (sum(F_n)*4)
  
      # Add one new vertex at the midpoint of each edge by taking the average
      # of the verts that form each edge.
      new_verts = verts[edges].mean(dim=1)
      new_verts = torch.cat([verts, new_verts], dim=0)
  
      # Reorder the verts to sequentially group existing and new verts for
      # each mesh.
      new_verts = new_verts[verts_sort_idx]
  
      if feats is not None:
          new_feats = feats[edges].mean(dim=1)
          new_feats = torch.cat([feats, new_feats], dim=0)
          new_feats = new_feats[verts_sort_idx]
  
      verts_list = list(new_verts.split(new_verts_per_mesh.tolist(), 0))
      faces_list = list(new_faces.split(new_faces_per_mesh.tolist(), 0))
      new_verts_per_mesh_cumsum = torch.cat(
          [
              new_verts_per_mesh.new_full(size=(1,), fill_value=0.0),
              new_verts_per_mesh.cumsum(0)[:-1],
          ],
          dim=0,
      )
      faces_list = [
          faces_list[n] - new_verts_per_mesh_cumsum[n]
          for n in range(self._N)
      ]
      if feats is not None:
          feats_list = new_feats.split(new_verts_per_mesh.tolist(), 0)
      new_meshes = Meshes(verts=verts_list, faces=faces_list)
  
      if feats is None:
          return new_meshes
      else:
          new_feats = torch.cat(feats_list, dim=0)
          return new_meshes, new_feats
  
file_path: pytorch3d/pytorch3d/ops/subdivide_meshes.py
imports: import torch
  import torch.nn
  from pytorch3d.structures import Meshes
label_desc: Use image node_id 5 for calling the SubdivideMeshes obj's underlying member method code with example usage: obj.subdivide_heterogenerous(meshes, feats) and returns: new_meshes, new_meshes,  new_feats