For some reason my raycast always returns zero location.

import bpy
import mathutils

originObj = bpy.context.active_object

#This converts tuple and Vectors to local or global
def globalToLocal(globalToLocalConv, objectForLocal, vectorOrTupleToConv):
vectorified = mathutils.Vector(vectorOrTupleToConv)
if globalToLocalConv:
    #global to local/object space
    return objectForLocal.matrix_world.inverted() @ vectorified
else :
    #local/object space to global
    return objectForLocal.matrix_world @ vectorified

#Actual rayCasting code
castResult = originObj.ray_cast(globalToLocal(True, originObj, originObj.location), 
    globalToLocal(True, originObj, (0, 0, originObj.location.z)))

print(castResult[0], castResult[1])#show if the ray hit and where

Any ideas as to why?

Here's a demo file(created on 2.83 but it has the same result in 2.93 portable edition) Also I'm an amateur with Python. The only other time I use it is for Robotics which has nothing to do with the Blender API. So maybe I'm missing something obvious?


1 Answer 1


I'm confused - are you wanting to detect the circle hitting the cube, the other way around, or detect the circle hitting itself? It would have been great to clarify that as well as a picture from the file:

circle and cube in 3D scene

Instead of waiting for feedback, I'll assume the first option is what you want based on your file naming convention. But first, regarding your main question of why it's returning zero, remember that the hit location given to you is in that object's local space. You don't need to convert it to local (as you did in your file). Second, self-intersections are possible, so it's best to add some epsilon to your origin (if part of the mesh is on that origin) so the ray cast doesn't accidentally hit itself at your origin.

In short, an object's ray_cast() is only aware of itself, and therefore can only hit its own mesh. You can use the context.scene.ray_cast() which is nice since you don't have to worry about coordinate conversion between spaces, but that means it can intersect any object.

If you want to use the object raycast, simply do the ray_cast() function on the obstacle instead. Here's the final result (some slight refactoring for readability for other users):

import bpy
import mathutils

context = bpy.context
originObj = context.active_object

obstacle = context.scene.objects['Obstacle']

def globalToLocal(objectForLocal, vectorOrTupleToConv):
    vectorified = mathutils.Vector(vectorOrTupleToConv)
    return objectForLocal.matrix_world.inverted() @ vectorified
def localToGlobal(obj, vectorOrTupleToConv):
    vectorified = mathutils.Vector(vectorOrTupleToConv)
    return obj.matrix_world @ vectorified
#Actual ray_cast code
origin = globalToLocal(obstacle, originObj.location)
obstacle_origin = mathutils.Vector((0,0,0))
direction = obstacle_origin - origin
is_hit, location, _, _ = obstacle.ray_cast(origin, direction)

if is_hit:
    '''moving some vertices to visualize the locations'''
    world_loc = localToGlobal(obstacle, location)
    #Ray visualized. Origin
    originObj.data.vertices[0].co = (0,0,0)
    #Raycast hit location
    originObj.data.vertices[1].co = globalToLocal(originObj, world_loc)

You must log in to answer this question.

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