10
$\begingroup$

This is a follow up to How to check if two meshes intersect in python with BVH Tree?

It appears that just calling overlap() on the BVH tree of two objects is not enough. Some sort of bmesh transform is required (this part confuses the hell out of me). I tried this in the code below, however I am still getting intersection on every object even if they are all not touching..

#delete objects that are intersecting
def delInter():
    #check every object for intersection with every other object
    for obj_now in obj_list:
        for obj_next in obj_list:
            print()
            if obj_now == obj_next:
                continue

            #create bmesh objects
            bm1 = bmesh.new()
            bm2 = bmesh.new()

            #fill bmesh data from objects
            bm1.from_mesh(scene.objects[obj_now].data)
            bm2.from_mesh(scene.objects[obj_next].data)            

            #fixed it here:
            bm1.transform(scene.objects[obj_now].matrix_world)
            bm2.transform(scene.objects[obj_next].matrix_world) 

            #make BVH tree from BMesh of objects
            obj_now_BVHtree = BVHTree.FromBMesh(bm1)
            obj_next_BVHtree = BVHTree.FromBMesh(bm2)           

            #get intersecting pairs
            inter = obj_now_BVHtree.overlap(obj_next_BVHtree)

            #if list is empty, no objects are touching
            if inter != []:
                print(obj_now + " and " + obj_next + " are touching!")
            else:
                print(obj_now + " and " + obj_next + " NOT touching!")
$\endgroup$
1
  • $\begingroup$ Whoops. Corrected! :) $\endgroup$
    – VSB
    Jan 15, 2017 at 0:29

4 Answers 4

6
$\begingroup$

Turns out I had to apply location to the BMesh I generated, I have edited code above to work:

        bm1.transform(scene.objects[obj_now].matrix_world)
        bm2.transform(scene.objects[obj_next].matrix_world) 

This is the reason I was getting intersection for every face and object, since they were all in the same location as far as BVHTree was concerned.

$\endgroup$
5
$\begingroup$

I added the missing context so the code can be used by anyone. Tested and working with 2.8.

import bpy, bmesh
from mathutils.bvhtree import BVHTree


#show objects that are intersecting
def intersection_check():
    #check every object for intersection with every other object
    for obj_now in obj_list:
        for obj_next in obj_list:
            print()
            if obj_now == obj_next:
                continue

            #create bmesh objects
            bm1 = bmesh.new()
            bm2 = bmesh.new()

            #fill bmesh data from objects
            bm1.from_mesh(scene.objects[obj_now].data)
            bm2.from_mesh(scene.objects[obj_next].data)            

            #fixed it here:
            bm1.transform(scene.objects[obj_now].matrix_world)
            bm2.transform(scene.objects[obj_next].matrix_world) 

            #make BVH tree from BMesh of objects
            obj_now_BVHtree = BVHTree.FromBMesh(bm1)
            obj_next_BVHtree = BVHTree.FromBMesh(bm2)           

            #get intersecting pairs
            inter = obj_now_BVHtree.overlap(obj_next_BVHtree)

            print("i got this far 1")

            #if list is empty, no objects are touching
            if inter != []:
                print(obj_now + " and " + obj_next + " are touching!")
            else:
                print(obj_now + " and " + obj_next + " NOT touching!")

# use active scene
scene =  bpy.context.scene

# define object list    
obj_list = ['object_a', 'object_b']

# Run it      
intersection_check()
$\endgroup$
2
  • $\begingroup$ This doesn't seem to work if objects are overlapping by just an edge or vertex... meaning an edge from one object is equal to the edge of another. If one object is moved over the other just a tick, then it flags overlap. My project has objects that start right at the point where one ends, using the same edge vertices. Overlap doesn't appear to be the proper solution in those cases. $\endgroup$
    – Sam Vimes
    Sep 18, 2019 at 22:25
  • $\begingroup$ @SamVimes I guess that is just how Blender (currently) works. Try a boolean operation of type union and see the result. That probably does not union as nice as if the objects would have overlapped by just the tiniest bit. $\endgroup$ Jan 1, 2021 at 13:46
0
$\begingroup$

I tried to copy this code/test myself, without any Blender Python knowledge. But was getting many errors. I had to add in some extra code/rename some stuff to get it to work. But here's what I got:

import bpy  #addbpy   <<ADD
import bmesh #addbmesh   <<ADD
import mathutils   #add mathutils  <<ADD

# get the current meshes   <<ADD
obj_list = bpy.data.meshes

# get the current scene  <ADD
scn = bpy.context.scene

# Define the BVH Tree  <ADD
BVHTree = mathutils.bvhtree.BVHTree


#Print objects that are intersecting
def delInter():
#check every object for intersection with every other object
  for obj_now in obj_list:
    for obj_next in obj_list:
    print()
     if obj_now == obj_next:
       continue

      #create bmesh objects
      bm1 = bmesh.new()
      bm2 = bmesh.new()

      #fill bmesh data from objects
      bm1.from_mesh(scn.objects[obj_now.name].data)   #<<  Add .name on both 
      lines.
      bm2.from_mesh(scn.objects[obj_next.name].data)  #<<  Add .name on both 
      lines.

      #fixed it here:
      bm1.transform(scn.objects[obj_now.name].matrix_world)   #<<  Add .name 
      on both lines.
      bm2.transform(scn.objects[obj_next.name].matrix_world)  #<<  Add .name 
      on both lines.

      #make BVH tree from BMesh of objects
      obj_now_BVHtree = BVHTree.FromBMesh(bm1)
      obj_next_BVHtree = BVHTree.FromBMesh(bm2)           

      #get intersecting pairs
      inter = obj_now_BVHtree.overlap(obj_next_BVHtree)

      #if list is empty, no objects are touching
      if inter != []:
       print(obj_now.name + " and " + obj_next.name + " are touching!")   # 
       <<  Add .name on both lines.
        else:
          print(obj_now.name + " and " + obj_next.name + " NOT touching!")  
          #<<  Add .name on both lines.


  delInter()  #Call FN
$\endgroup$
1
  • $\begingroup$ Please use 4 space indenting. $\endgroup$
    – batFINGER
    Aug 28, 2018 at 18:25
0
$\begingroup$

a similar code would return an empty list of indices:

import bpy, bmesh
from mathutils.bvhtree import BVHTree

list_of_obj = [ o for o in bpy.context.scene.objects]
the_object = list_of_obj[0]
the_other_object = list_of_obj[1]

BMESH_1 = bmesh.new()
BMESH_1.from_mesh(bpy.context.scene.objects[the_object.name].data)
BMESH_1.transform(the_object.matrix_world)
BVHtree_1 = BVHTree.FromBMesh(BMESH_1)


BMESH_2 = bmesh.new()
BMESH_2.from_mesh(bpy.context.scene.objects[the_other_object.name].data)
BMESH_2.transform(the_other_object.matrix_world)
BVHtree_2 = BVHTree.FromBMesh(BMESH_2)

inter = BVHtree_1.overlap(BVHtree_2)

print(inter)

is there a missing bmesh operation ?

EDIT : the above code actually works if any object matrix transformation has not been changed after the last scene update. To apply this code to objects which have been transformed within the same script for example, one can add the following line above the code:

bpy.context.scene.update() # as commented below by @batFINGER
$\endgroup$
0

You must log in to answer this question.

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