0
$\begingroup$

I have a collection of over 2000 small meshes. I want to automatically have them joined in case meshes touch each other. So, after running python code, I want to end up with fewer meshes.

I tried the following script (chatGPT):

import bpy

# Get a list of all the meshes in the scene
meshes = bpy.data.meshes

# Loop through each mesh
for mesh in meshes:

    # Create a list of all the other meshes that are touching this mesh
    touching_meshes = []
    for other_mesh in meshes:
        if mesh != other_mesh:
            for edge in mesh.edges:
                if edge.vertices[0] in other_mesh.vertices or edge.vertices[1] in other_mesh.vertices:
                    touching_meshes.append(other_mesh)
                    break

    # Join this mesh with all the other touching meshes
    for other_mesh in touching_meshes:
        bool_modifier = mesh.modifiers.new('bool', 'BOOLEAN')
        bool_modifier.object = bpy.data.objects[str(other_mesh.name)]
        bool_modifier.operation = 'UNION'
        bpy.ops.object.modifier_apply(modifier=bool_modifier.name)

but I get this error :

Python: Traceback (most recent call last): File "C:\Users\bartdh\AppData\Local\Temp\7zOC3093EA1\TsD0209-2.blend\Text.001", line 14, in TypeError: bpy_prop_collection.contains: expected a string or a tuple of strings

Thank you for any help.

$\endgroup$
4
  • 4
    $\begingroup$ GPT chat is barely reliable yet so shouldn't be used. And I can't see the bpy specified in the message in the code you provided. $\endgroup$ Mar 19, 2023 at 9:16
  • $\begingroup$ Do you just want to join them, or do you really want a boolean operation between the ones that overlap? $\endgroup$
    – lemon
    Mar 19, 2023 at 11:38
  • 1
    $\begingroup$ chatgpt wont be useful if you have no programming knowledge as you need to guide the AI to your solution which will take several follow up questions and understanding of what solution it was trying to propose. $\endgroup$ Mar 19, 2023 at 14:26
  • $\begingroup$ is the title of your question what you asked to gpt? this can be done but not (or too complex) for close non convex meshes. $\endgroup$
    – lemon
    Mar 19, 2023 at 18:59

1 Answer 1

1
$\begingroup$

This will operate on all selected objects (see the commented line if you want to operate on everything in a collection instead).

import bpy
import bmesh
from mathutils.bvhtree import BVHTree

if bpy.context.mode != 'OBJECT':
    bpy.ops.object.mode_set(mode='OBJECT')

# Use all selected objects
obs = list(bpy.context.selected_objects)
# Uncomment this to use all objects from a collection instead
#obs = list(bpy.data.collections["Collection"].objects)

obs = [ob for ob in obs if ob.type == 'MESH']

# Calculate BVHTrees for each object
# Adjust epsilon to change how strict "is touching" is
trees = []
for ob in obs:
    # Can't use BVHTree.FromObject, it doesn't use world space, see
    # devtalk.blender.org/t/bvhtree-fromobject-blender-2-8-wonkiness
    # Instead convert to BMesh and use that.
    bm = bmesh.new()
    bm.from_mesh(ob.data)  # Note: this is the unevaluated mesh
    bm.transform(ob.matrix_world)
    trees.append(BVHTree.FromBMesh(bm, epsilon=0.0))
    bm.free()

# Compute pairs (i,j) where obs[i] touches obs[j]
intersections = []
for i in range(0, len(trees)):
    for j in range(i + 1, len(trees)):
        if trees[i].overlap(trees[j]):
            intersections.append((i, j))
    trees[i] = None  # can GC this now

# Group into connected pieces
pieces = []
for i, j in intersections:
    pi, pj = None, None
    for index, piece in enumerate(pieces):
        if i in piece: pi = index
        if j in piece: pj = index
    if pi is None and pj is None:
        pieces.append(set([i, j]))
    elif pi is None:
        pieces[pj].add(i)
    elif pj is None:
        pieces[pi].add(j)
    elif pi != pj:
        pieces[pi].update(pieces[pj])
        del pieces[pj]

# Join all objects in each piece
for piece in pieces:
    bpy.ops.object.select_all(action='DESELECT')
    for i in piece:
        obs[i].select_set(True)
    for i in piece:
        bpy.context.view_layer.objects.active = obs[i]
        break
    bpy.ops.object.join()

Example showing touching cubes being joined into one object

$\endgroup$
3
  • $\begingroup$ This is super. Your code is performing exactly what I need. Many thanks $\endgroup$ Mar 20, 2023 at 10:24
  • $\begingroup$ @BartDeHantsetters, you should accept this answer and upvote it as you said "Your code is performing exactly what I need. Many thanks". Thanks $\endgroup$
    – lemon
    Mar 21, 2023 at 19:23
  • $\begingroup$ scurest, hi, your solution does not take evaluated meshes into account. Though, if it does, how do you imagine the "join part" to do it correctly (I mean, if objects have modifers, the join part as it is is hazardous). $\endgroup$
    – lemon
    Mar 21, 2023 at 19:26

You must log in to answer this question.

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