Hello, I have to Boolean Union ca. 150 objects. I have code (below) that works very well on lists of 10-20 selected objects. But if the object count is higher, then Blender calculates forever. Therefor I would like to split the 150-object-list into ca. 10 15-object-lists. Only a pretty small modification of the code below is needed - how can I do this best please? Many thanks!
Here is the code I have already:
##START “UNION OF SELECTED OBJECTS”:
sce = bpy.context.scene
myobjectlistlength = len(bpy.context.selected_objects)
bpy.context.selected_objects[0].name
myobjectlistlength
[B]for index in range(0, myobjectlistlength):
print (index)
bpy.context.selected_objects[index].name
for index in range(0, myobjectlistlength-2):
print (index)
sce = bpy.context.scene
##we always just retrieve the new next element with index 1, because the list gets
##shorter and shorter with each new union:
bpy.context.selected_objects[1].name
myobjectlistlength
index+1
mymodifier = originalunionobject.modifiers.new(‘mymodifier’, ‘BOOLEAN’)
mymodifier.operation = ‘UNION’
nextobject = sce.objects.get(bpy.context.selected_objects[1].name)
mymodifier.object = nextobject
bpy.context.scene.objects.active = originalunionobject
bpy.ops.object.modifier_apply(apply_as=‘DATA’, modifier=“mymodifier”)
sce.objects.unlink(nextobject)
##END “UNION OF SELECTED OBJECTS”[/B]
@batFINGER - he wants boolean union, not just simply joining objects.
@chrissie - without wraping the code in the tags batFINGER mentions, we cant tell where the indents are and thus cant help. Or you could upload to pasteall.org.
I’ve been wanting something like this for a long time, but been to lazy to try code it
I’m Not sure how much of an improvement would be achieved by splitting the list into smaller parts. If there is no intersection then join would be alot quicker to achieve the same result. Even changing the originally posted code with a simple bounding box intersection test to either join or add and apply modifier would speed it up IMO. Splitting the list into non intersecting sets, joining then using union would be my suggestion. Surely each and all of the 150 objects don’t intersect each other.
I too have this need.
What I have is a bunch (appx 200) of spheres and cylinders that I need to boolean together (like a molecule). Unfortunately I cannot join them and boolean them because they are randomly indexed.
here’s a picture (and a closeup) for example:
Sorry for the dreadful lighting. So each cylinder and each sphere are disconnected objects, and the cylinders “penetrate” into the spheres. I have tried some code snippets suggested by others but none comes close.
What I’m thinking is to somehow, starting with any randomly chosen sphere, to sequentially boolean every connecting cylinder, then proceed to iteratively repeat this process until everything’s connected. Unfortunately since i’m new to blender scripting and python i’m crazy stuck.
hm… if there was a way to add vertices on edges at intersection points, one could do that and then select only the outside vertices, invert selection and delete verts
Hi! Here is what I created / used (“quick and dirty”, but it works for me):
<b>##START “UNION OF SELECTED OBJECTS”:
sce = bpy.context.scene
myobjectlistlength = len(bpy.context.selected_objects)
bpy.context.selected_objects[0].name
myobjectlistlength
[B]for</b> index <b>in</b> range(0, myobjectlistlength):
print (index)
bpy.context.selected_objects[index].name
originalunionobject = sce.objects.get(bpy.context.selected_objects[0].name)
originalunionobject_name = bpy.context.selected_objects[0].name
mymodifier = originalunionobject.modifiers.new('mymodifier', 'BOOLEAN')
mymodifier.operation = 'UNION'
nextobject = sce.objects.get(bpy.context.selected_objects[1].name)
mymodifier.object = nextobject
bpy.context.scene.objects.active = originalunionobject
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="mymodifier")
sce.objects.unlink(nextobject)
<b># for</b> index <b>in</b> range(0, 10):
<b>for</b> index <b>in</b> range(0, myobjectlistlength-2):
print (index)
sce = bpy.context.scene
##we always just retrieve the new next element with index 1, because the list gets
##shorter and shorter with each new union:
bpy.context.selected_objects[1].name
myobjectlistlength
index+1
mymodifier = originalunionobject.modifiers.new('mymodifier', 'BOOLEAN')
mymodifier.operation = 'UNION'
nextobject = sce.objects.get(bpy.context.selected_objects[1].name)
mymodifier.object = nextobject
bpy.context.scene.objects.active = originalunionobject
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="mymodifier")
sce.objects.unlink(nextobject)
##END “UNION OF SELECTED OBJECTS[/B]
You first select all objects to boolean union.
Then execute the code in the python console.
I once had a memory problem when I wanted to boolean union too many objects in one go.
I created a variant of the code which 1st unioned in chunks of 15, then unioned those.
Let me know if you need this.
got it triggered out how to Union boolean many objects:
#!BPY
“”"
Name: ‘Muli Boolean Union’
Blender: 242
Group: ‘Misc’
Tooltip: ‘trying’
“”"
from Blender import *
from Blender import Draw, Scene, Object
from Blender.Mathutils import Rand
runs through all objects and boolean:union them together
def supb(scn, sel):
i = 0
for objss in sel:
if i == 0:
objFirst = objss
i = 1
else: # i == 1
if i == 1:
objSecond = objss
i = 2
# adding modifier
mods = objFirst.modifiers # adding a modifier
mod = mods.append(Modifier.Types.BOOLEAN) # with boolean
mod[Modifier.Settings.OPERATION] = 1 # and union
# doing the modifier
mod[Modifier.Settings.OBJECT] = objSecond # adding the element to the modifier
objFirst.makeDisplayList() # doing the modifier
# deleting the old two
scn.unlink( objFirst )
scn.unlink( objSecond )
else:
i = 3
Window.RedrawAll() #??
def main():
scn = Scene.GetCurrent()
if not scn.objects.context:
return
sel = scn.objects.context
objects = [ob for ob in scn.objects.context]
Count = len(objects)
i = 0
while i < 10:
i = i + 1
f = Count
for i in range(0, f):
supb( scn, sel )
sel = scn.objects.context
Window.RedrawAll()
if name == ‘main’:
main()
also here is a script, which Looks good…was not working with me:
The commented code is not working, but I think the problems come from blender’s boolean operation itself.
(I try to manually combine those segments, blender(2.76) tells me it can not excute bool operation)
update: I come up with a new idea!!! We can first do the “difference boolean operation” between each pair (as the pre processing). To ensure every two segments are not collided.
I realize this is old, but I came across the thread when I need to do the same thing (for a ball and stick molecular model). Taking pieces from other scripts I came up with something that does exactly this. It uses the selected objects so if you start with something that has many objects (I’ve used it on structures with ~1200 objects imported as VRML2) it can be faster to select it in chunks instead of trying to do it all in one pass. Also, make sure there are no internal objects. PyMol stick representations always put out extra spheres at the end.
import bpy
import bmesh
from mathutils.bvhtree import BVHTree
def bmesh_copy_from_object(obj, transform=True, triangulate=True, apply_modifiers=False):
"""
Returns a transformed, triangulated copy of the mesh
"""
assert(obj.type == 'MESH')
if apply_modifiers and obj.modifiers:
me = obj.to_mesh(bpy.context.scene, True, 'PREVIEW', calc_tessface=False)
bm = bmesh.new()
bm.from_mesh(me)
bpy.data.meshes.remove(me)
else:
me = obj.data
if obj.mode == 'EDIT':
bm_orig = bmesh.from_edit_mesh(me)
bm = bm_orig.copy()
else:
bm = bmesh.new()
bm.from_mesh(me)
# Remove custom data layers to save memory
for elem in (bm.faces, bm.edges, bm.verts, bm.loops):
for layers_name in dir(elem.layers):
if not layers_name.startswith("_"):
layers = getattr(elem.layers, layers_name)
for layer_name, layer in layers.items():
layers.remove(layer)
if transform:
bm.transform(obj.matrix_world)
if triangulate:
bmesh.ops.triangulate(bm, faces=bm.faces)
return bm
def bmesh_check_intersect_objects(obj, obj2):
"""
Check if any faces intersect with the other object
returns a boolean
"""
assert(obj != obj2)
# Triangulate
bm = bmesh_copy_from_object(obj, transform=True, triangulate=True)
bm2 = bmesh_copy_from_object(obj2, transform=True, triangulate=True)
intersect = False
BMT1 = BVHTree.FromBMesh(bm)
BMT2 = BVHTree.FromBMesh(bm2)
overlap_pairs = BMT1.overlap(BMT2)
#print (len(overlap_pairs))
if len(overlap_pairs) > 0:
intersect = True
return intersect
sce = bpy.context.scene
myobjectlistlength = len(bpy.context.selected_objects)
startlist = len(bpy.context.selected_objects)
i = 0
while i < myobjectlistlength or myobjectlistlength > 1:
sce.update()
obj1 = bpy.context.selected_objects[0]
for obj2 in bpy.context.selected_objects:
if obj1.name == obj2.name:
continue
#print(obj1.name)
#print(obj2.name)
intersect = bmesh_check_intersect_objects(obj1, obj2)
if intersect:
mymodifier = obj1.modifiers.new('mymodifier', 'BOOLEAN')
mymodifier.operation = 'UNION'
mymodifier.object = obj2
bpy.context.scene.objects.active = obj1
bpy.ops.object.convert(target='MESH')
sce.objects.unlink(obj2)
myobjectlistlength = len(bpy.context.selected_objects)
print("Objects left to merge: %s" % myobjectlistlength)
i = i+1
This seemed like a great idea, but it didn’t work for me. The places where the once individual objects meet don’t result in joined vertices after the intersection. This had implications down the road for 3D printing.
I actually tried this again, realizing that I hadn’t attempted it after removing the fully internal spheres that were in my object. After removing the internal spheres it worked great! Now I’m feeling silly or spending so much time writing that script.