TransWikia.com

bpy: How do you find the corners of a camera frustum?

Blender Asked by Robin Betts on September 29, 2021

… by which I mean the vectors from a perspective camera’s viewing point to the corners of the rendered rectangle, as displayed by the diagonal sides of a camera’s rectangular pyramid in a 3D View. (Normalized if you like, in Camera Space, if you like.)

The angle and view_frame attributes of a Camera don’t seem to carry this information, unless I’m mistaken?

There are quite a few answers on how to test whether a point is visible to a camera, that’s not quite the same thing.

Better still, and perhaps of more general use to others, too, would be a diagram of how bpy refers to a camera: what a Camera‘s important attributes actually mean, in 3D / device / screen space.

EDIT: following @batFINGER’s examples (I think?)..trying to get the render frame, I run this:

import bpy

scn = bpy.context.scene

rx = scn.render.resolution_x
ry = scn.render.resolution_y
cam_obj = scn.camera

if (cam_obj.name in bpy.data.cameras): 
          
    cam_mw = cam_obj.matrix_world
    cam = cam_obj.data
    vf = cam.view_frame()
    world_frame = [cam_mw @ v for v in vf]
    
    print (rx,ry)
    for v in world_frame:
        print (v)  

And, changing the render resolutions, visibly changing the shape of the frustum in the 3D view, I get these outputs:

1512 1371
<Vector (2.1208, -6.3833, 4.1026)>
<Vector (2.3175, -6.8641, 3.2482)>
<Vector (1.3703, -7.1821, 3.2090)>
<Vector (1.1736, -6.7013, 4.0635)>

427 1432
<Vector (2.1208, -6.3833, 4.1026)>
<Vector (2.3175, -6.8641, 3.2482)>
<Vector (1.3703, -7.1821, 3.2090)>
<Vector (1.1736, -6.7013, 4.0635)>

Which is puzzling me. There’s no change in the frame as a consequence of changing the proportions of the render – (the change isn’t even hidden in the camera’s world transform..)

SOLUTION: the camera’s .view_frame() method needs its optional named scene parameter to update.. until I know why, I don’t fancy making that an answer..

One Answer

Pass the scene to view frame

Think you got there in the end, here is @ideasman42's script modified to add empties to 5 points of frustum, for each camera object in scene.

All the info re resolution will come with the passed as keyword scene, else it defaults to None.

>>> C.scene.camera.data.view_frame(
view_frame()
Camera.view_frame(scene=None)
Return 4 points for the cameras frame (before object transformation)

Test script:

import bpy


def camera_as_planes(scene, obj):
    """
    Return planes in world-space which represent the camera view bounds.
    """
    from mathutils.geometry import normal
    print(obj.name)
    camera = obj.data
    # normalize to ignore camera scale
    matrix = obj.matrix_world.normalized()
    frame = [matrix @ v for v in camera.view_frame(scene=scene)]
    origin = matrix.to_translation()
    frame.append(origin)
    for p in frame:
        bpy.ops.object.empty_add(location=p)

# test call
scene = bpy.context.scene
cams = [o for o in scene.objects if o.type == 'CAMERA']
for cam in cams:
    camera_as_planes(scene, cam)

Correct answer by batFINGER on September 29, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP