3
$\begingroup$

I'm working on a construction scene with a number of view layers managing the different work contexts (different buildings, different floors, structural elements, plumbing, electricity, etc.).

I'd like to :

  • Store the current viewport view properties (location, view direction, focal lens, etc.).
  • Be able to restore the view properties exactly as they were saved when I select this view layer at some point later in time.

Example in action :

  1. I'm working on the ground floor of building A.
  2. I create a view layer bld_a_flr0 and I store the view I'm currently in.
  3. I start working on the second floor of building B which is located 100 units away from building A.
  4. I create a view layer bld_b_flr2 and I store the view I'm currently in.
  5. I decide to go back to building A, so I change the view layer to bld_a_flr0 and I click on a button to restore the view layer and 3D view.

Clarifications :

  • I'm not talking about the camera properties, but the 3D viewport "virtual" camera.
  • I'm aware of the Stored Views add-on but I don't want the hassle of having to manually type view layer names and it is not manageable when the number of view layers grows.
  • Assume I'm using only one 3D viewport editor.
$\endgroup$
2
$\begingroup$

Although the exact functionality of the Stored Views add-on doesn't cut it, we're going to leverage it in our own script. Since it's shipped with Blender for free, we can assume pretty much everybody has access to it.

We're going to add a Panel in the View Layer properties to display our minimalistic interface. It should have 2 buttons (Operators), one to save the view, and one to restore the view.

At first we assume the user didn't install the add-on and suggest enabling it directly from the panel if it isn't already enabled.

enter image description here

For some reason the add-on needs to be initialized every time we save & load the file, but we're not here to discuss that or refactor its code so we'll just roll with it.

enter image description here

Now that we have initialized the add-on, we can click on the "Save" button to store the current view.

enter image description here

Move the camera, tweak some view properties, and click on "Load" to return back to the saved view !

enter image description here

import bpy


class GU_OT_view_layer_save_or_load_stored_view(bpy.types.Operator):
    bl_label = "Save or Load View Layer Stored View"
    bl_idname = "view_layer.save_or_load_stored_view"
    index: bpy.props.IntProperty(description="Stored View Index")
    save_or_load: bpy.props.BoolProperty(description= "False : Save, True : Load")

    @classmethod
    def poll(cls, context):
        # Check if at least one View 3D area exists in the current screen
        if any(a for a in context.screen.areas if a.type == "VIEW_3D"):
            return True
        else:
            if bpy.app.version >= (3, 0, 0):
                cls.poll_message_set("No 3D Viewport available")
            return False

    def execute(self, context):
        # Import the POV class from stored views add-on which offers view saving & loading features
        from space_view3d_stored_views.core import POV

        view_3d_area = next(a for a in context.screen.areas if a.type == "VIEW_3D")
        if self.index >= 0:
            view = context.scene.stored_views.view_list[self.index]
        else:
            # We add a new entry since this view layer is not registered
            view = context.scene.stored_views.view_list.add()
            view.name = context.view_layer.name

        pov = POV(self.index)
        pov.view3d = view_3d_area.spaces[0]  # Patching this since it references a wrong space data
        if self.save_or_load:
            pov.update_v3d(view.pov)
        else:
            pov.from_v3d(view.pov)

        return {"FINISHED"}


class GU_PT_view_layer_stored_view(bpy.types.Panel):
    bl_label = "Stored View"
    bl_idname = "GU_PT_view_layer_stored_view"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "view_layer"

    def draw(self, context):
        scene = context.scene
        layout = self.layout

        if not hasattr(scene, "stored_views"):
            # Check if add-on is registered
            if hasattr(bpy.types, "VIEW3D_OT_stored_views_initialize"):
                layout.operator("view3d.stored_views_initialize")
            else:
                layout.label(text="\"Stored Views\" add-on is needed to access Stored Views", icon="ERROR")
                layout.operator("preferences.addon_enable").module = "space_view3d_stored_views"
            return
        
        view_layer = context.view_layer
        # If the view layer's view has already been saved, we find its entry index
        index = -1
        for i, view in enumerate(scene.stored_views.view_list):
            if view_layer.name == view.name:
                index = i
                break

        row = layout.row()
        save_op = row.operator("view_layer.save_or_load_stored_view", icon="EXPORT", text="Save")
        save_op.index = index
        save_op.save_or_load = False

        sub_row = row.row()
        load_op = sub_row.operator("view_layer.save_or_load_stored_view", icon="IMPORT", text="Load")
        load_op.index = index
        load_op.save_or_load = True
        sub_row.enabled = index >= 0  # Prevent loading view if it doesn't exist


if __name__ == "__main__":
    bpy.utils.register_class(GU_OT_view_layer_save_or_load_stored_view)
    bpy.utils.register_class(GU_PT_view_layer_stored_view)

Limitations

  • A major limitation is that the saved entries are referencing the view layers by name. If you change the view layer name, the reference will be lost and you won't be able to load the view from the interface. Despair not, for we can find the lost view in the regular add-on interface, in the View panel of the Right hand side panel of the 3D viewport :

enter image description here

Use the cube icon to load the view, click in the name field to rename to your current view layer name, click on the dot to save the current view, and click on the cross to delete the entry.

enter image description here

  • It relies on another add-on being shipped with blender, it may not be available in some versions ? I don't know.

  • Viewport camera movements do not register with the undo system, so it's not possible to undo the operations.

I'm not aware of other limitations at the moment.

Turning it into an add-on

I've voluntarily kept the scope as small as possible so currently this is just a script that's supposed to be run in the text editor. Here are great resources to turn the script into a full-on add-on :

https://www.youtube.com/watch?v=nKt6CtMH0no

https://docs.blender.org/manual/en/latest/advanced/scripting/addon_tutorial.html

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.