I have a stack of ellipses with all normals aligned to the origin z (ie. pointing up) I want to programatically bridge the edges between each ellipse in order of height, but the underlying interpolation causes the following transformation. Note how the wider ellipse 3/4 of the way up the stack connects to the bottom one…
I’ve tried playing with the bridge edge loop settings in the scene inspector to see if there’s some tweaking that could resolve, but sadly not.
This is a toy example. The proper script will instantiate thousands of similar structures, so resolving by hand is not an option. Any advice would be greatly appreciated!!
Thanks for the suggestion, but I have tried an (inefficient) incremental implementation where I select the top face of the bottom most ellipse (they are sorted by name acc. to z_height), join with the next highest ellipse and then bridge: repeat.
for i in range(len(bpy.data.collections['InProgress'].all_objects)):
# Sort objects by Z height
coll = [x for x in bpy.data.collections['InProgress'].all_objects]
coll.sort(key=lambda x: x.name)
coll[0].select_set(True)
bpy.context.view_layer.objects.active = coll[0]
# Select topmost face of bottom most object
bpy.ops.object.editmode_toggle()
mesh = bpy.context.active_object.data
for p in mesh.polygons:
if p.normal.z == 1:
p.select=True
bpy.ops.object.editmode_toggle()
# Select next highest ellipse, join and bridge
coll[1].select_set(True)
bpy.context.view_layer.objects.active = coll[1]
bpy.ops.object.join()
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.bridge_edge_loops()
bpy.ops.object.editmode_toggle()
bpy.ops.object.select_all(action='DESELECT')
This process has the same outcome as the original issue if the ellipses are filled or if they are just rings, results in another problematic outcome:
Ok, I dont have the time to write it for you, but I’d recommend to rewrite it. To continue from from what you have here you could do the following. First join all those objects manually into one object and just operate on that single object. Stay in edit mode in your script for the bridging. Find the two lowest faces ( eg by comparing the centers z value) of those whose normals are pointing up, select just those and call the bridge command. Then find the face with the last upper height and the one above and so on.
Thanks a million @Debuk, that worked a treat. For anyone who is looking for a solution to a similar problem (Note that this solution will only hold for connecting objects perpendicular to the z-axis):
# Deselect all objects
bpy.ops.object.select_all(action='DESELECT')
# Join all objects
for o in bpy.data.collections['InProgress'].all_objects:
o.select_set(True)
bpy.context.view_layer.objects.active = o
bpy.ops.object.join()
# Enter edit mode
bpy.ops.object.editmode_toggle()
# Get a BMesh representation of the active mesh
obj = bpy.context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)
# Build a list of faces with ZNorm == 1, sorted by height
bm_faces = []
for face in bm.faces:
if face.normal.z == 1:
bm_faces.append([face, round(face.verts[0].co.z, 2)])
bm_faces.sort(key=lambda x: x[1], reverse=True)
# Iterate through the list connecting each face sequentially
for i in range(len(bm_faces)-1):
bpy.ops.mesh.select_all(action = 'DESELECT')
bm_faces[i][0].select=True
bm_faces[i+1][0].select=True
bpy.ops.mesh.bridge_edge_loops()
bpy.ops.object.editmode_toggle()