4

So i need to perform some basic loop cut and slide operators on a mesh. The edge index is known and the slide amount is also fixed.

using override method from How do I override context for bpy.ops.mesh.loopcut? i am able to perform the cut successfully inside blender script editor. but when run without the UI the the script gives an error.

I would also like to know if there is an alternate non-UI based methods to perform loop cuts with proper UV updates

here's an example version which adds loop cuts and smooth operation. tested on Blender 2.83 script editor

import bpy

bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete(use_global=False)

bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 0)) bpy.ops.object.editmode_toggle()

win = bpy.context.window scr = win.screen areas3d = [area for area in scr.areas if area.type == 'VIEW_3D'] region = [region for region in areas3d[0].regions if region.type == 'WINDOW']

override = {'window':win, 'screen':scr, 'area' :areas3d[0], 'region':region[0], 'scene' :bpy.context.scene, }

bpy.ops.mesh.loopcut_slide(override, MESH_OT_loopcut={ "number_cuts":5, "smoothness":1, "falloff":'INVERSE_SQUARE', "object_index":0, "edge_index":4, "mesh_select_mode_init":(False, True, False) }, TRANSFORM_OT_edge_slide={ "value":0, "single_side":False, "use_even":False, "flipped":False, "use_clamp":True, "mirror":True, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "correct_uv":False, "release_confirm":False, "use_accurate":False})

bpy.ops.object.editmode_toggle()

```

Prime007
  • 183
  • 8

2 Answers2

3

Subdivide edge loops is a good fit for loop cut slide.

The loop cut and slide is an advanced operator that is doing a bit behind the scene. Can select a single edge and loop cut will select and cut the edge ring defined by the edge.

Bmesh subdivide edge operators

If an edge loop is fed into the bmesh subdivide edges operator with use grid fill it emulates a basic loop cut and slide.

enter image description here

As well there is the subdivide edge ring bmesh operator, which will throw an error if the edges submitted are not valid edge rings.

enter image description here Sub'd edge rings. Inverse square profile, factor 0.5

There are a number of options available for both operators, including setting the spacings of the cuts, and smooth falloff type.

Because loop cut and slide is subdividing the edges will notice a number of familiar options.

Consult the docs..

See Adding a Cuboid Mesh to see this in operation to create an $i \times j \times k$ cuboid.

Selecting the edge rings.

Have used a recursive method similar to that shown here.

How to find a mesh loops and rings

Have not added any checks re not finding a valid edge ring. (eg last edges found would want to be same or boundary)

Test script, select edge in edit mode and run script. Uses the active edge to select edge ring.

import bpy
import bmesh

cuts = 4

context = bpy.context ob = context.object me = ob.data

bm = bmesh.from_edit_mesh(me) edge = bm.select_history.active def edge_loops(edge): def walk(edge): yield edge edge.tag = True for l in edge.link_loops: loop = l.link_loop_radial_next.link_loop_next.link_loop_next if not (len(loop.face.verts) != 4 or loop.edge.tag): yield from walk(loop.edge) for e in bm.edges: e.tag = False return list(walk(edge))

if isinstance(edge, bmesh.types.BMEdge): ''' bmesh.ops.subdivide_edges( bm, edges=edge_loops(edge), cuts=cuts, smooth_falloff='INVERSE_SQUARE', use_grid_fill=True, ) ''' bmesh.ops.subdivide_edgering( bm, edges=edge_loops(edge), cuts=cuts, profile_shape='INVERSE_SQUARE', profile_shape_factor=0.0, )
bmesh.update_edit_mesh(me)

Note have used an edit mode bmesh by way of example. For object mode script load the bmesh as shown in your answer. IMO bisect is not going to give a good result if edge loop edges are not nicely aligned.

Please refrain from posting delete all objects code in question scripts when it is not necessary.

batFINGER
  • 84,216
  • 10
  • 108
  • 233
2

bmesh bisect does exactly this...but its not automated like bpy loopcut so make sure to select all the faces you need to cut and you'll need to provide the cutting location & direction yourself.

import bpy
import bmesh
import math
import mathutils

bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete(use_global=False) bpy.ops.mesh.primitive_plane_add(enter_editmode=False, align='WORLD', location=(0, 0, 0))

def bmesh_loopcut(bm,face_list,direction_axis,center='auto'): for f in bm.faces: f.select = False bm.faces.ensure_lookup_table()
for f in face_list: bm.faces[f].select = True

edges = [e for e in bm.edges if e.select == True]
faces = [f for f in bm.faces if f.select == True]

if center=='auto':    
    weights = [f.calc_area() for f in faces]
    weighted_centres = [f.calc_area() * f.calc_center_median() for f in faces]
    cutting_point = sum(weighted_centres, mathutils.Vector()) / sum(weights)
else:
    cutting_point = bpy.context.scene.cursor.location
geom = []
geom.extend(edges)
geom.extend(faces) 

result = bmesh.ops.bisect_plane(bm,dist=0.01,geom=geom,plane_co=cutting_point,plane_no=direction_axis)



Make a new BMesh

bm = bmesh.new()

obj = bpy.context.object

ob = obj me = ob.data bm = bmesh.new() bm.from_mesh(me)

face_cut=([0]) bmesh_loopcut(bm,face_cut,[1,0,0])

bm.to_mesh(me) bm.free() me.update()

```

Prime007
  • 183
  • 8