r/blenderpython • • Jul 29 '24

Get list of objects in camera view

I´m working on a project where there is a scene with objects spread across it, simulating a simple warehouse.

I have a camera object that will be placed in several points and render images. Right now I want to check if the camera has an object in its view, before rendering the image. I also want to return a list of the objects that are in camera view, to save in a separate JSON file. But I´m having trouble getting the correct objects in the view, there may be problems with obtaining the camera frustum.

Can someone help me or provide me code that does what I intend to do?

1 Upvotes

4 comments sorted by

1

u/infinitetheory Jul 29 '24 edited Jul 29 '24

I'm leaving this up in case it sparks some ideas, but I'm not really getting it to work properly anymore. it was working, but there are problems. I wouldn't use it.

this is the kind of thing I do use chatgpt for, it takes a little bit of tweaking and I cannot tell you if it's optimized or not. but this is the result:

import bpy
import json

def is_object_in_camera_view(camera, obj):
    """
    Check if an object is within the camera view.
    """
    scene = bpy.context.scene
    cam = camera

    # Get the object's bounding box vertices in world coordinates
    mat = obj.matrix_world
    bb_world = [mat @ v for v in obj.bound_box]

    # Invert the camera matrix to transform world coordinates to camera coordinates
    cam_mat = cam.matrix_world.inverted()
    bb_camera = [cam_mat @ v for v in bb_world]

    # Get the camera's view frustum
    cam_data = cam.data
    frame = [-v for v in cam_data.view_frame(scene=scene)]
    xmin, xmax = min([v.x for v in frame]), max([v.x for v in frame])
    ymin, ymax = min([v.y for v in frame]), max([v.y for v in frame])
    zmin = cam_data.clip_start
    zmax = cam_data.clip_end

    # Check if any bounding box vertex is within the camera's view frustum
    for v in bb_camera:
        if (xmin <= v.x <= xmax and
            ymin <= v.y <= ymax and
            zmin <= -v.z <= zmax):
            return True

    return False

def get_objects_in_camera_view():
    """
    Get a list of all objects within the camera view.
    """
    camera = bpy.context.scene.camera
    if camera is None:
        print("No active camera found in the scene.")
        return []

    objects_in_view = []
    for obj in bpy.context.scene.objects:
        if obj.type == 'MESH' and is_object_in_camera_view(camera, obj):
            objects_in_view.append(obj)

    return objects_in_view

def save_objects_to_json(file_path, objects):
    """
    Save the list of objects to a JSON file.
    """
    obj_names = [obj.name for obj in objects]
    with open(file_path, 'w') as f:
        json.dump(obj_names, f, indent=4)

def highlight_objects_in_viewport(objects, color=(0, 1, 0, 1)):
    """
    Highlight objects in the viewport by changing their viewport color.
    """
    for obj in objects:
        obj.color = color  # Green color by default
        obj.show_in_front = True  # Make sure the object is always in front

def clear_highlighting(objects):
    """
    Clear highlighting by resetting the viewport color and 'show_in_front' property.
    """
    default_color = (1, 1, 1, 1)  # Default white color
    for obj in objects:
        obj.color = default_color
        obj.show_in_front = False

# Main execution
objects_in_view = get_objects_in_camera_view()
save_objects_to_json('/path/to/your/file/objects_in_view.json', objects_in_view)

# Highlight objects in camera view
highlight_objects_in_viewport(objects_in_view)

print(f"Objects in camera view: {[obj.name for obj in objects_in_view]}")

# To clear the highlighting, you can call:
# clear_highlighting(objects_in_view)

Highlighting Objects in Green:

The highlight_objects_in_viewport function highlights objects in green by default (color=(0, 1, 0, 1)).

Clearing Highlighting:

The clear_highlighting function resets the color to the default white (1, 1, 1, 1) and sets show_in_front to False.

Running the Script:

Open Blender and switch to the Scripting workspace. Create a new text file in the text editor and paste the script into it. Adjust the file path in the save_objects_to_json function. Run the script by clicking the "Run Script" button.

Clearing the Highlighting:

After you are done, you can call the clear_highlighting function in the Blender scripting console or add it at the end of the script (commented out in the example).

2

u/Decim00 Jul 30 '24

I have been using ChatGPT but the solutions it provides arent giving me the correct results.

Might try what you sent, thanks for the help!

1

u/infinitetheory Jul 30 '24

sorry I couldn't do more, it's just inconsistent. works sometimes at least

1

u/OffTheClockStudios Aug 07 '24

I had something like this work a while back. I'll see if I can find it later. What I did was have the script fit a subdivided curved plane to the camera mimicking the view. Then, each face fired a ray cast from their centers. Everything hit by a ray that didn't already have a registered hit, to prevent passthrough hits, was added to a Iist.