Skip to content

Instantly share code, notes, and snippets.

@semagnum
Created March 7, 2023 21:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save semagnum/2604c2a4e37ddafe1845f9d0116fc4dc to your computer and use it in GitHub Desktop.
Save semagnum/2604c2a4e37ddafe1845f9d0116fc4dc to your computer and use it in GitHub Desktop.
Blender operator to shoot a ray into the scene and draw a 3D cube on the closest face
import bpy
from bpy_extras import view3d_utils
import gpu
from gpu_extras.batch import batch_for_shader
from mathutils import Vector
def draw(shade, bat):
shade.bind()
shade.uniform_float("color", (1, 0, 0, 0.25))
bat.draw(shade)
def remove(handler):
bpy.types.SpaceView3D.draw_handler_remove(handler, 'WINDOW')
for area in bpy.context.window.screen.areas:
if area.type == 'VIEW_3D':
area.tag_redraw()
indices = (
(0, 1, 3), (0, 2, 3), (4, 5, 7), (4, 6, 7),
(0, 4, 5), (0, 1, 5), (2, 0, 4), (2, 6, 4),
(1, 3, 7), (1, 5, 7), (3, 2, 6), (3, 6, 7))
def main(context, event, cor):
"""Run this function on left mouse, execute the ray cast"""
# get the context arguments
scene = context.scene
region = context.region
rv3d = context.region_data
coord = event.mouse_region_x, event.mouse_region_y
# get the ray from the viewport and mouse
view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
ray_target = ray_origin + view_vector
isHit, loc, normal, index, hit_obj, matrix = scene.ray_cast(context.evaluated_depsgraph_get(), ray_origin, view_vector)
if isHit:
return hit_obj, index, matrix
return None, 0, None
class ViewOperatorRayCast(bpy.types.Operator):
"""Modal object selection with a ray cast"""
bl_idname = "view3d.modal_operator_raycast"
bl_label = "RayCast View Operator"
def __init__(self):
self.prev_obj = None
self.prev_index = 0
self.shader = None
self.batch = None
self.draw_handler = None
def modal(self, context, event):
if event.type in {'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE'}:
# allow navigation
return {'PASS_THROUGH'}
elif event.type == 'MOUSEMOVE':
coords = [
Vector((-0.05, -0.05, -0.05)), Vector((+0.05, -0.05, -0.05)),
Vector((-0.05, +0.05, -0.05)), Vector((+0.05, +0.05, -0.05)),
Vector((-0.05, -0.05, +0.05)), Vector((+0.05, -0.05, +0.05)),
Vector((-0.05, +0.05, +0.05)), Vector((+0.05, +0.05, +0.05))]
hit_obj, index, matrix = main(context, event, coords)
if hit_obj is not None and (self.prev_obj != hit_obj or self.prev_index != index):
face_world_loc = matrix @ (hit_obj.data.polygons[index].center)
coords = [face_world_loc + c for c in coords]
self.shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
self.batch = batch_for_shader(self.shader, 'TRIS', {"pos": coords}, indices=indices)
if self.draw_handler is not None:
remove(self.draw_handler)
self.draw_handler = bpy.types.SpaceView3D.draw_handler_add(draw, (self.shader, self.batch), 'WINDOW', 'POST_VIEW')
for area in bpy.context.window.screen.areas:
if area.type == 'VIEW_3D':
area.tag_redraw()
self.prev_obj = hit_obj
self.prev_index = index
return {'RUNNING_MODAL'}
elif event.type in {'RIGHTMOUSE', 'ESC'}:
if self.draw_handler is not None:
remove(self.draw_handler)
return {'CANCELLED'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
if context.space_data.type == 'VIEW_3D':
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
self.report({'WARNING'}, "Active space must be a View3d")
return {'CANCELLED'}
def menu_func(self, context):
self.layout.operator(ViewOperatorRayCast.bl_idname, text="Raycast View Modal Operator")
# Register and add to the "view" menu (required to also use F3 search "Raycast View Modal Operator" for quick access).
def register():
bpy.utils.register_class(ViewOperatorRayCast)
bpy.types.VIEW3D_MT_view.append(menu_func)
def unregister():
bpy.utils.unregister_class(ViewOperatorRayCast)
bpy.types.VIEW3D_MT_view.remove(menu_func)
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment