Goal: Efficiently cut out (holes) or trim off regions of dense meshes defined by editable polyline or bezier curves which are snapped to a mesh surface.


  1. My narrow use is to cut teeth out of scanned model data.
  2. Cut meshes data into articulating parts to print models larger than 3d print volumes
  3. Cleaning boundaries of 3d scanned data
  4. Cut holes in meshes (see the 10 or so related questions here)

Related Topics:

  1. Standard Knife tool:
    Cons: No way to edit cut path once clicked, slow on dense meshes, sometimes skips faces.
  2. Knife Project: Cons: Doesn't always work if not a good view path or on dense triangle meshes. Here you can see the result with a bezier I manually paced on surface (visualized with a thickness) and the cut from knife project. enter image description here
  3. Grease Cutter: Cons: Uses boolean
  4. Sculpt Trim: Cons: Not implemented, cut not editable


  1. I have written a simple user interface for defining the desired cut path. enter image description here

  2. The segment intersections are calculated and previewed. Segments which failed to successfully cut are displayed in red, so the cut can be altered. enter image description here

    1. I now have a list of edges in the oringal Bmesh, and corresponding intersection points. And to finish "cutting" I need to split those edges at the intersection points (create new verts), connect the new verts with new edges. Optionally, split the new edges to actually separate a piece of the mesh.

Problem enter image description here This method has been extremely slow. >2 minutes. Calculating the cut locations for this example was instantaneous.

    for v, ed in zip(new_cos, ed_map):
        ed_pcts = {}
        ed_pcts[ed] = .5   
        geom = bmesh.ops.bisect_edges(bm, edges = [ed],cuts = 1,edge_percents = ed_pcts)
        geom['geom_split'][0].co = v
        new_verts += [geom['geom_split'][0].index]

    for i in range(0,len(new_verts)):
        v_pair = [bm.verts[new_verts[i]], bm.verts[new_verts[i-1]]]
        ed_geom = bmesh.ops.connect_vert_pair(bm, verts = v_pair, verts_exclude = [], faces_exclude = [])`
  • using mesh.ops.bisect_edges and passing in all of my edges, and then simply passing all of the new vertices to bmesh.ops.connect_verts vastly improves the performace, however I have not been able to get the edge_percents argument for bmesh.ops.bisect_edges to work. It seems to be completely ignored. Cut's really fast, but doesn't cut in the right place, it just bisects the intersected edges at the midpoint.

enter image description here

  • $\begingroup$ well...I feel dumb, the returned verts from bmesh.ops.bisect_edges are in the same order the input edges are in, so it's as simple as assigning their location to them $\endgroup$
    – patmo141
    Commented Oct 5, 2015 at 4:27
  • $\begingroup$ If you want to answer your own question you can use the answer box below. $\endgroup$ Commented Oct 5, 2015 at 10:03
  • $\begingroup$ yeah, I know, I just wasn't ready to after spending all that time crafting a nice question, to realize the answer is so obvious. $\endgroup$
    – patmo141
    Commented Oct 5, 2015 at 13:36

1 Answer 1


This code snippet assumes some existing variables which were pre-calculated

bme     : blender BMesh
ed_map  : all the edges to be bisected into 2 edges
new_cos : desired positions of bisection, in same order as ed_map

geom =  bmesh.ops.bisect_edges(self.bme, 
                               edges = ed_map,
                               cuts = 1,
                               edge_percents = {})

new_bmverts = [ele for ele in geom['geom_split'] if isinstance(ele, bmesh.types.BMVert)]

#assign the locations to the new vertices, which were automatically
#placed at edge midpoints
for v, co in zip(new_bmverts, new_cos):
        v.co = co

#connect the new vertices, to cut across the individual faces
ed_geom = bmesh.ops.connect_verts(bme, 
                                  verts = new_bmverts, 
                                  faces_exclude = [], 
                                  check_degenerate = False)
new_edges = ed_geom['edges']

#optionally, split the new edges, to make 2 separate mesh pieces
bmesh.ops.split_edges(bme, edges = new_edges, verts = [], use_verts = False) 

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .