3
$\begingroup$

To align active camera to match the current view I could simply pan, zoom or rotate the view. Select active camera from outliner then hit Ctrl + Alt + Numpad 0. I only wonder, is there a way to write this in python?

I have dug into sites and look for a way to hack it. Most of it are related on aligning view to camera, align camera to objects, or outdated. No way I could find on camera to view.

So far, i have found few scripts and this script...

bpy.ops.view3d.camera_to_view()

... this would get me into runtime error "RuntimeError: Operator bpy.ops.view3d.view_selected.poll() expected a view3d region"

and this script...

bpy.ops.view3d.camera_to_view_selected()

...seem made all sense, but I wouldn't know how or where to start with it. Is it possible to write a script on Ctrl + Alt Numpad 0?

$\endgroup$

1 Answer 1

3
$\begingroup$

You have found the right command bpy.ops.view3d.camera_to_view() but it can't be run as is from the Python console. The error message means that the op can only be run from a 3D Viewport context. There are (at least) two solutions:

  • Create an operator class that performs the operation and make sure you invoke it from a 3D Viewport context. Here's a class I use for adding a new camera to a scene.
class TOOL_OT_add_camera(Operator):
    bl_idname = "camera.add"
    bl_label = "add camera"
    bl_description = "add a camera in the viewport"
    bl_options = {"REGISTER", "UNDO"}

    def execute(self, context):
        """ Add a new camera to the scene, make it the active camera,
            and match it to the current view.
        """

        camera_data = bpy.data.cameras.new(name="Camera")
        if camera_data is None:
            return {"CANCELLED"}

        my_camera = bpy.data.objects.new("Camera", camera_data)

        if my_camera is None:
            return {"CANCELLED"}

        bpy.context.scene.collection.objects.link(my_camera)
        context.scene.camera = my_camera

        bpy.ops.view3d.camera_to_view()
        return {"FINISHED"}
  • Override the context. Here's sample code that will do that:
win = bpy.context.window
scr = win.screen
areas3d  = [area for area in scr.areas if area.type == 'VIEW_3D']
region   = [region for region in areas3d[0].regions if region.type == 'WINDOW']

override = {
    'window': win,
    'screen': scr,
    'area'  : areas3d[0],
    'region': region[0],
    'scene' : bpy.context.scene,
}

bpy.ops.view3d.camera_to_view(override)

Note that this code makes a couple of assumptions; mainly that the interesting 3D viewport will be the first one on the list of 3D viewport areas. Since mostly we operate with only one 3D viewport this is usually true.

In this case, the example override is overkill and can be simplified to

areas3d  = [area for area in bpy.context.window.screen.areas if area.type == 'VIEW_3D']
bpy.ops.view3d.camera_to_view({'area':areas3d[0]})

You can read more about operator overrides in the bpy ops introduction. The above code was adapted from this answer to "python - How do I override context for bpy.ops.mesh.loopcut?"

Note that this will only work if you have an active camera.

3.2 Update

Context overrides are deprecated in Blender 3.2 and are scheduled to be removed in Blender 3.3 The replacement is temp_override. The manual has examples of how to use the new function.

$\endgroup$
3
  • $\begingroup$ Works great, thanks for clear insights on operator overrides. Worth of knowledge $\endgroup$
    – sirrus
    Commented Feb 28, 2022 at 16:01
  • $\begingroup$ @sirrus you're welcome. If you haven't already you might want to read What should I do when someone answers my question? and perhaps accept my answer. $\endgroup$ Commented Feb 28, 2022 at 16:19
  • $\begingroup$ Thank you for sharing this about deprecation on Context Overide... Acknowledged! $\endgroup$
    – sirrus
    Commented Aug 18, 2022 at 19:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .