Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'release/scripts/templates/operator_modal_view3d_raycast.py')
-rw-r--r--release/scripts/templates/operator_modal_view3d_raycast.py107
1 files changed, 107 insertions, 0 deletions
diff --git a/release/scripts/templates/operator_modal_view3d_raycast.py b/release/scripts/templates/operator_modal_view3d_raycast.py
new file mode 100644
index 00000000000..3236c08cc8c
--- /dev/null
+++ b/release/scripts/templates/operator_modal_view3d_raycast.py
@@ -0,0 +1,107 @@
+import bpy
+from mathutils import Vector
+from bpy_extras import view3d_utils
+
+
+def main(context, event, ray_max=10000.0):
+ """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 * ray_max)
+
+ scene.cursor_location = ray_target
+
+ def visible_objects_and_duplis():
+ """Loop over (object, matrix) pairs (mesh only)"""
+
+ for obj in context.visible_objects:
+ if obj.type == 'MESH':
+ yield (obj, obj.matrix_world.copy())
+
+ if obj.dupli_type != 'NONE':
+ obj.dupli_list_create(scene)
+ for dob in obj.dupli_list:
+ obj_dupli = dob.object
+ if obj_dupli.type == 'MESH':
+ yield (obj_dupli, dob.matrix.copy())
+
+ obj.dupli_list_clear()
+
+ def obj_ray_cast(obj, matrix):
+ """Wrapper for ray casting that moves the ray into object space"""
+
+ # get the ray relative to the object
+ matrix_inv = matrix.inverted()
+ ray_origin_obj = matrix_inv * ray_origin
+ ray_target_obj = matrix_inv * ray_target
+
+ # cast the ray
+ hit, normal, face_index = obj.ray_cast(ray_origin_obj, ray_target_obj)
+
+ if face_index != -1:
+ return hit, normal, face_index
+ else:
+ return None, None, None
+
+ # cast rays and find the closest object
+ best_length_squared = ray_max * ray_max
+ best_obj = None
+
+ for obj, matrix in visible_objects_and_duplis():
+ if obj.type == 'MESH':
+ hit, normal, face_index = obj_ray_cast(obj, matrix)
+ if hit is not None:
+ length_squared = (hit - ray_origin).length_squared
+ if length_squared < best_length_squared:
+ best_length_squared = length_squared
+ best_obj = obj
+
+ # now we have the object under the mouse cursor,
+ # we could do lots of stuff but for the example just select.
+ if best_obj is not None:
+ best_obj.select = True
+
+
+class ViewOperatorRayCast(bpy.types.Operator):
+ """Modal object selection with a ray cast"""
+ bl_idname = "view3d.modal_operator_raycast"
+ bl_label = "RayCast View Operator"
+
+ def modal(self, context, event):
+ if event.type in {'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE'}:
+ # allow navigation
+ return {'PASS_THROUGH'}
+ elif event.type == 'LEFTMOUSE':
+ main(context, event)
+ return {'RUNNING_MODAL'}
+ elif event.type in {'RIGHTMOUSE', 'ESC'}:
+ 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 register():
+ bpy.utils.register_class(ViewOperatorRayCast)
+
+
+def unregister():
+ bpy.utils.unregister_class(ViewOperatorRayCast)
+
+
+if __name__ == "__main__":
+ register()