73 lines
2.3 KiB
Python
73 lines
2.3 KiB
Python
bl_info = {
|
|
"name": "Deselect Non-Intersecting Objects with Camera",
|
|
"author": "Ryan Schultz & GPT-5",
|
|
"version": (1, 0),
|
|
"blender": (4, 0, 0),
|
|
"location": "View3D > Select",
|
|
"description": "Deselects selected objects that do not intersect the camera plane",
|
|
"category": "Object",
|
|
}
|
|
|
|
import bpy
|
|
import mathutils
|
|
|
|
class OBJECT_OT_deselect_non_intersecting(bpy.types.Operator):
|
|
"""Deselect selected objects that do not intersect with the active camera plane"""
|
|
bl_idname = "object.deselect_non_intersecting"
|
|
bl_label = "Deselect Non-Intersecting with Camera"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
camera = context.scene.camera
|
|
if camera is None:
|
|
self.report({'WARNING'}, "No active camera found in the scene.")
|
|
return {'CANCELLED'}
|
|
|
|
cam_matrix = camera.matrix_world
|
|
cam_origin = cam_matrix.translation
|
|
cam_direction = cam_matrix.to_quaternion() @ mathutils.Vector((0.0, 0.0, -1.0))
|
|
|
|
plane_normal = cam_direction.normalized()
|
|
plane_point = cam_origin
|
|
|
|
def point_plane_distance(point):
|
|
return (point - plane_point).dot(plane_normal)
|
|
|
|
deselected = 0
|
|
for obj in context.selected_objects:
|
|
if obj == camera:
|
|
continue
|
|
|
|
bbox_world = [obj.matrix_world @ mathutils.Vector(corner) for corner in obj.bound_box]
|
|
distances = [point_plane_distance(p) for p in bbox_world]
|
|
min_d = min(distances)
|
|
max_d = max(distances)
|
|
|
|
intersects = (min_d <= 0.0 <= max_d) or (max_d <= 0.0 <= min_d)
|
|
|
|
if not intersects:
|
|
obj.select_set(False)
|
|
deselected += 1
|
|
|
|
self.report({'INFO'}, f"Deselected {deselected} object(s) not intersecting camera plane")
|
|
return {'FINISHED'}
|
|
|
|
|
|
def menu_func(self, context):
|
|
layout = self.layout
|
|
layout.separator()
|
|
layout.operator(OBJECT_OT_deselect_non_intersecting.bl_idname)
|
|
|
|
|
|
def register():
|
|
bpy.utils.register_class(OBJECT_OT_deselect_non_intersecting)
|
|
bpy.types.VIEW3D_MT_select_object.append(menu_func)
|
|
|
|
|
|
def unregister():
|
|
bpy.types.VIEW3D_MT_select_object.remove(menu_func)
|
|
bpy.utils.unregister_class(OBJECT_OT_deselect_non_intersecting)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
register()
|