Cannot get ray_cast in blender to work

I am trying to use blender for tests like "line of sight". For this I want to use the ray_cast function (the raycasting function is not in the blender game engine). No matter what I try, I cannot get the code to work at all.

(suppose I have 2 objects, a and b)

When I try to transfer ray_cast from a to b, I can get the correct answer if this is the first time I used this function after opening the blender, and if at least one of the start or end location is on Origin. Subsequent ray_casts made after moving one object do not change the result (as in, I get the same result as the first time) even after manually updating the scene. If I try to use without the beginning or end of the origin, it returns null (Vector <0,0,0>, Vector <0,0,0>, -1)

I noticed that similar things happen with other rendering functions like Object.closest_point_on_mesh etc., can anyone help me? below is the code i use for rayCasting.

#

import bpy def main(): a = bpy.data.objects['a'] b = bpy.data.objects['b'] x = a.ray_cast(a.location,b.location) print(x[0]) main() 

#

+4
source share
2 answers

Well, the ray_cast function expects the start and end coordinates to be in the LOCAL coordinate system of the object in the .ray_cast object. This means that your a.location and b.location coordinates, which are global / world coordinates, must be converted to local coordinates.

In this way:

 globalcoordinate = Vector((x, y, z)) localcoordinateforobject = (globalcoordinate - object.location) * object.matrix_world.inverted() 

You can usually use matrix_world as described above, but this does not work for objects that rotate / scale without applying this rotation and scaling (Ctrl-A). Therefore, I share this code, which I use in many of my add-ons:

 def adapt(selobj): # Rotating / panning / zooming 3D view is handled here. # Creates a matrix. if selobj.rotation_mode == "AXIS_ANGLE": # object rotation_quaternionmode axisangle ang, x, y, z = selobj.rotation_axis_angle matrix = Matrix.Rotation(-ang, 4, Vector((x, y, z))) elif selobj.rotation_mode == "QUATERNION": # object rotation_quaternionmode euler w, x, y, z = selobj.rotation_quaternion x = -x y = -y z = -z quat = Quaternion([w, x, y, z]) matrix = quat.to_matrix() matrix.resize_4x4() else: # object rotation_quaternionmode euler ax, ay, az = selobj.rotation_euler mat_rotX = Matrix.Rotation(-ax, 4, 'X') mat_rotY = Matrix.Rotation(-ay, 4, 'Y') mat_rotZ = Matrix.Rotation(-az, 4, 'Z') if selobj.rotation_mode == "XYZ": matrix = mat_rotX * mat_rotY * mat_rotZ elif selobj.rotation_mode == "XZY": matrix = mat_rotX * mat_rotZ * mat_rotY elif selobj.rotation_mode == "YXZ": matrix = mat_rotY * mat_rotX * mat_rotZ elif selobj.rotation_mode == "YZX": matrix = mat_rotY * mat_rotZ * mat_rotX elif selobj.rotation_mode == "ZXY": matrix = mat_rotZ * mat_rotX * mat_rotY elif selobj.rotation_mode == "ZYX": matrix = mat_rotZ * mat_rotY * mat_rotX # handle object scaling sx, sy, sz = selobj.scale mat_scX = Matrix.Scale(sx, 4, Vector([1, 0, 0])) mat_scY = Matrix.Scale(sy, 4, Vector([0, 1, 0])) mat_scZ = Matrix.Scale(sz, 4, Vector([0, 0, 1])) matrix = mat_scX * mat_scY * mat_scZ * matrix return matrix 

It returns the right transformation matrix, called the "matrix" for the selobj object. Use it instead of object.matrix_world in the above code example.

+1
source

this should solve your problem:

 def main(): a = bpy.data.objects['a'] b = bpy.data.objects['b'] localA = a.matrix_world.inverted() * a.location localB = a.matrix_world.inverted() * b.location print(localA, localB) (location, normal, index) = a.ray_cast(localA, localB) print(location, normal, index) # reselect the originally selected face if(index > 0): a.data.polygons[index].select = True 
+2
source

Source: https://habr.com/ru/post/1486952/


All Articles