chrissie
(chrissie)
March 25, 2017, 11:05am
1
I just found out there is a real bug in ray_cast.
Blender updated ray_cast in version 2.77, where it starts to return 4 values instead of 3. Since then there is a bug it seems. I am checking whether 2 objects interfere with coDEmanX’s great script from here: http://blender.stackexchange.com/questions/9073/how-to-check-if-two-meshes-intersect-in-python
It works very nicely until Blender 2.76. I wanted to port our code to 2.78 and detected the intersection-checking code does not work anymore. ray_cast is causing the trouble.
I am using:
obj1 = bpy.data.objects['Cylinder.6403']
obj2 = bpy.data.objects['Cylinder']
intersect = bmesh_check_intersect_objects(obj1, obj2)
if(intersect != 0):
print(obj1, ' intersects ', obj2)
on the 2 geos in the attached ray_cast_error.blend. When I move the geos around, I sometimes get correct intereference results, and sometimes not. If you test with the default positions in the file, and Blender 2.77+, then the result is incorrect (it says the 2 geos collide, where in fact they are not).
Here I call ray_cast with 3 / 4 return values depending on the Blender version:
<b> if ((bpy.app.version[0] == 2) and (bpy.app.version[1] < 77)):
#Return (location, normal, index):
location, normal, index = ray_cast(co_1, co_2)
else:
#Return (result, location, normal, index):
result, location, normal, index = ray_cast(co_1, co_2)
</b>
ray_cast_error.blend (481 KB)
Attached
Ko1
(Ko.)
March 25, 2017, 11:27am
2
New object and scene raycast functions also takes “origin vector” and “direction normal” as inputs.
Not “start” and “end” vectors like old versions.
<b>ray_cast(co_1, co_2 - co_1) </b># second vector to normal (assume mathutils.Vector)
chrissie
(chrissie)
March 29, 2017, 11:40am
4
New object and scene raycast functions also takes “origin vector” and “direction normal” as inputs.
Not “start” and “end” vectors like old versions.
<b>ray_cast(co_1, co_2 - co_1) </b># second vector to normal (assume mathutils.Vector)
Wow, I just tried it, in Blender 2.78, and it does not work???
This is the “check_intersect” code I am using:
<b>def bmesh_check_intersect_objects(obj, obj2):
#Check if any faces intersect with the other object
#
myresult = -1
# 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)
#
# If bm has more edges, use bm2 instead for looping over its edges
# (so we cast less rays from the simpler object to the more complex object)
#if len(bm.edges) > len(bm2.edges):
#bm2, bm = bm, bm2
#
# Create a real mesh (lame!)
scene = bpy.context.scene
me_tmp = bpy.data.meshes.new(name="~temp~")
bm2.to_mesh(me_tmp)
bm2.free()
obj_tmp = bpy.data.objects.new(name=me_tmp.name, object_data=me_tmp)
scene.objects.link(obj_tmp)
scene.update()
ray_cast = obj_tmp.ray_cast
#
intersect = False
#
EPS_NORMAL = 0.000001
EPS_CENTER = 0.01 # should always be bigger
#
#for ed in me_tmp.edges:
for ed in bm.edges:
v1, v2 = ed.verts
#
# setup the edge with an offset
co_1 = v1.co.copy()
co_2 = v2.co.copy()
co_mid = (co_1 + co_2) * 0.5
no_mid = (v1.normal + v2.normal).normalized() * EPS_NORMAL
co_1 = co_1.lerp(co_mid, EPS_CENTER) + no_mid
co_2 = co_2.lerp(co_mid, EPS_CENTER) + no_mid
#
#
if ((bpy.app.version[0] == 2) and (bpy.app.version[1] < 77)):
#Return (location, normal, index):
location, normal, index = ray_cast(co_1, co_2)
if index != -1:
myresult = 1
else:
#Return (result, location, normal, index):
#not yet tested, but should be ok:
result = ray_cast(co_1, co_2 - co_1)
# second vector to normal (assume mathutils.Vector)
#2.78: result, location, normal, index, object, matrix = ray_cast(<i>origin</i>, <i>direction</i>, <i>distance=1.70141e+38</i>)
print (result)
print (location)
print (index)
if result != -1:
myresult = 1
#
if myresult != -1:
intersect = True
break
#
scene.objects.unlink(obj_tmp)
bpy.data.objects.remove(obj_tmp)
bpy.data.meshes.remove(me_tmp)
#
scene.update()
#
return intersect
#END def
</b>
Ko1
(Ko.)
March 29, 2017, 12:42pm
5
Here different way to do this:
import bpy
import bmesh
from mathutils.bvhtree import BVHTree
b = bpy.data.objects
bm1, bm2 = bmesh.new(), bmesh.new()
bm1.from_mesh(b[0].data)
bm2.from_mesh(b[1].data)
bmesh.ops.transform(bm1, matrix=b[0].matrix_world, space=b[0].matrix_world, verts=bm1.verts)
bmesh.ops.transform(bm2, matrix=b[1].matrix_world, space=b[1].matrix_world, verts=bm2.verts)
T1 = BVHTree.FromBMesh(bm1)
T2 = BVHTree.FromBMesh(bm2)
if T1.overlap(T2):
out = True
else:
out = False
print(out)
Just change b[0] and b[1] to your objects.
chrissie
(chrissie)
March 29, 2017, 1:22pm
6
Here different way to do this:
import bpy
import bmesh
from mathutils.bvhtree import BVHTree
b = bpy.data.objects
bm1, bm2 = bmesh.new(), bmesh.new()
bm1.from_mesh(b[0].data)
bm2.from_mesh(b[1].data)
bmesh.ops.transform(bm1, matrix=b[0].matrix_world, space=b[0].matrix_world, verts=bm1.verts)
bmesh.ops.transform(bm2, matrix=b[1].matrix_world, space=b[1].matrix_world, verts=bm2.verts)
T1 = BVHTree.FromBMesh(bm1)
T2 = BVHTree.FromBMesh(bm2)
if T1.overlap(T2):
out = True
else:
out = False
print(out)
Just change b[0] and b[1] to your objects.
WOW, that’s working, MANY THANKS!!! You are great.
chrissie
(chrissie)
March 30, 2017, 12:58am
7
And it’s many times faster than the previous method