Guest User

Untitled

a guest
May 3rd, 2020
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.72 KB | None | 0 0
  1. import bpy
  2. from bpy_extras import view3d_utils
  3.  
  4.  
  5. def main(context, event):
  6.     """Run this function on left mouse, execute the ray cast"""
  7.     # get the context arguments
  8.     scene = context.scene
  9.     region = context.region
  10.     rv3d = context.region_data
  11.     coord = event.mouse_region_x, event.mouse_region_y
  12.  
  13.     # get the ray from the viewport and mouse
  14.     view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
  15.     ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
  16.  
  17.     ray_target = ray_origin + view_vector
  18.  
  19.     def visible_objects_and_duplis():
  20.         """Loop over (object, matrix) pairs (mesh only)"""
  21.  
  22.         depsgraph = context.evaluated_depsgraph_get()
  23.         for dup in depsgraph.object_instances:
  24.             if dup.is_instance:  # Real dupli instance
  25.                 obj = dup.instance_object
  26.                 yield (obj, dup.matrix_world.copy())
  27.             else:  # Usual object
  28.                 obj = dup.object
  29.                 yield (obj, obj.matrix_world.copy())
  30.  
  31.     def obj_ray_cast(obj, matrix):
  32.         """Wrapper for ray casting that moves the ray into object space"""
  33.  
  34.         # get the ray relative to the object
  35.         matrix_inv = matrix.inverted()
  36.         ray_origin_obj = matrix_inv @ ray_origin
  37.         ray_target_obj = matrix_inv @ ray_target
  38.         ray_direction_obj = ray_target_obj - ray_origin_obj
  39.  
  40.         # cast the ray
  41.         success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj)
  42.  
  43.         if success:
  44.             return location, normal, face_index
  45.         else:
  46.             return None, None, None
  47.  
  48.     # cast rays and find the closest object
  49.     best_length_squared = -1.0
  50.     best_obj = None
  51.  
  52.     for obj, matrix in visible_objects_and_duplis():
  53.         if obj.type == 'MESH':
  54.             hit, normal, face_index = obj_ray_cast(obj, matrix)
  55.             if hit is not None:
  56.                 hit_world = matrix @ hit
  57.                 scene.cursor.location = hit_world
  58.                 length_squared = (hit_world - ray_origin).length_squared
  59.                 if best_obj is None or length_squared < best_length_squared:
  60.                     best_length_squared = length_squared
  61.                     best_obj = obj
  62.                     best_face = face_index
  63.  
  64.     # now we have the object under the mouse cursor,
  65.     # we could do lots of stuff but for the example just select.
  66.     if best_obj is not None:
  67.         # for selection etc. we need the original object,
  68.         # evaluated objects are not in viewlayer
  69.         best_original = best_obj.original
  70.         best_original.select_set(True)
  71.         print(best_face)
  72.  
  73.  
  74. class ViewOperatorRayCast(bpy.types.Operator):
  75.     """Modal object selection with a ray cast"""
  76.     bl_idname = "view3d.modal_operator_raycast"
  77.     bl_label = "RayCast View Operator"
  78.  
  79.     def modal(self, context, event):
  80.         if event.type in {'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE'}:
  81.             # allow navigation
  82.             return {'PASS_THROUGH'}
  83.         elif event.type == 'LEFTMOUSE':
  84.             main(context, event)
  85.             return {'RUNNING_MODAL'}
  86.         elif event.type in {'RIGHTMOUSE', 'ESC'}:
  87.             return {'CANCELLED'}
  88.  
  89.         return {'RUNNING_MODAL'}
  90.  
  91.     def invoke(self, context, event):
  92.         if context.space_data.type == 'VIEW_3D':
  93.             context.window_manager.modal_handler_add(self)
  94.             return {'RUNNING_MODAL'}
  95.         else:
  96.             self.report({'WARNING'}, "Active space must be a View3d")
  97.             return {'CANCELLED'}
  98.  
  99.  
  100. def register():
  101.     bpy.utils.register_class(ViewOperatorRayCast)
  102.  
  103.  
  104. def unregister():
  105.     bpy.utils.unregister_class(ViewOperatorRayCast)
  106.  
  107.  
  108. if __name__ == "__main__":
  109.     register()
Add Comment
Please, Sign In to add comment