0
$\begingroup$

How to simplify this code to Switch to a specific camera view in each area?

import bpy


class C_0V0(bpy.types.Operator):
    bl_idname = "cam.c0v0"
    bl_label = "C_0V0"
    cam_name = "C_0V0"

    def execute(self, context):
        C = bpy.context
        # select cam in context area
        C.space_data.camera = bpy.data.objects["C_0V0"]

        # set scene cam
        for area in C.screen.areas:
            if area.type == 'VIEW_3D':
                A = C.area.spaces.active.camera

        C.scene.camera = bpy.data.objects[A.name]

        C.space_data.shading.color_type = 'OBJECT'
        C.space_data.region_3d.view_perspective = 'CAMERA'

        #cam view center
        bpy.ops.view3d.view_center_camera()

        # set cam attributes
        bpy.data.objects[A.name].lock_scale = (True, True, True)
        bpy.data.objects[A.name].lock_location = (True, True, True)
        bpy.data.objects[A.name].lock_rotation = (True, True, True)
        bpy.data.objects[A.name].scale = (1, 1, 1)
        bpy.data.cameras[A.name].display_size = 0.05
        bpy.data.cameras[A.name].background_images[0].alpha = 0
        bpy.data.cameras[A.name].dof.use_dof = False
        bpy.data.cameras[A.name].clip_start = 25
        bpy.data.cameras[A.name].clip_end = 100000
        bpy.data.cameras[A.name].background_images[0].scale = 1
        bpy.data.cameras[A.name].background_images[1].scale = 1
        bpy.data.cameras[A.name].background_images[2].scale = 1

        return {'FINISHED'}


class C_0V1(bpy.types.Operator):
    bl_idname = "cam.c0v1"
    bl_label = "C_0V1"
    cam_name = "C_0V1"

    def execute(self, context):
        C = bpy.context        
        # select cam in context area
        C.space_data.camera = bpy.data.objects["C_0V1"]

        # set scene cam
        for area in C.screen.areas:
            if area.type == 'VIEW_3D':
                A = C.area.spaces.active.camera

        C.scene.camera = bpy.data.objects[A.name]

        C.space_data.shading.color_type = 'OBJECT'
        C.space_data.region_3d.view_perspective = 'CAMERA'
        
        #cam view center
        bpy.ops.view3d.view_center_camera()

        # set cam attributes
        bpy.data.objects[A.name].lock_scale = (True, True, True)
        bpy.data.objects[A.name].lock_location = (True, True, True)
        bpy.data.objects[A.name].lock_rotation = (True, True, True)
        bpy.data.objects[A.name].scale = (1, 1, 1)
        bpy.data.cameras[A.name].display_size = 0.05
        bpy.data.cameras[A.name].background_images[0].alpha = 0
        bpy.data.cameras[A.name].dof.use_dof = False
        bpy.data.cameras[A.name].clip_start = 25
        bpy.data.cameras[A.name].clip_end = 100000
        bpy.data.cameras[A.name].background_images[0].scale = 1
        bpy.data.cameras[A.name].background_images[1].scale = 1
        bpy.data.cameras[A.name].background_images[2].scale = 1

        return {'FINISHED'}

addon_keymaps = []

def register():
    bpy.utils.register_class(C_0V0)
    bpy.utils.register_class(C_0V1)

def unregister():
    bpy.utils.unregister_class(C_0V0)
    bpy.utils.unregister_class(C_0V1)

if __name__ == "__main__":
    register()
```
$\endgroup$

1 Answer 1

0
$\begingroup$

Difficult to answer since it can depend on what you are trying to achieve in general and from where your operators are called. You have some code redundancy spread over two operators. Whenever you repeat a lot of actions using the same code and variables it is usually a code idea to rewrite this part using a loop or a function call. Since your code is separated over two operators you could use function calls. A good example would be the part where you set cam attributes. You can define your own method outside of the two operators and call it from inside the operator classes. This could look like this:

import bpy

def set_cam_attributes(object: bpy.types.Object):
    if object.type != 'CAMERA':
        return
    
    object.lock_scale = (True, True, True)
    object.lock_location = (True, True, True)
    object.lock_rotation = (True, True, True)
    object.scale = (1, 1, 1)

    cam_data: bpy.types.Camera = object.data

    cam_data.display_size = 0.05
    cam_data.dof.use_dof = False
    cam_data.clip_start = 25
    cam_data.clip_end = 100000
    if cam_data.background_images:
        cam_data.background_images[0].alpha = 0
        cam_data.background_images[0].scale = 1
        cam_data.background_images[1].scale = 1
        cam_data.background_images[2].scale = 1

class C_0V0(bpy.types.Operator):
    bl_idname = "cam.c0v0"
    bl_label = "C_0V0"
    cam_name = "C_0V0"

    def execute(self, context):
        C = bpy.context
        # select cam in context area
        C.space_data.camera = bpy.data.objects["C_0V0"]

        # set scene cam
        for area in C.screen.areas:
            if area.type == 'VIEW_3D':
                A = C.area.spaces.active.camera

        C.scene.camera = bpy.data.objects[A.name]

        C.space_data.shading.color_type = 'OBJECT'
        C.space_data.region_3d.view_perspective = 'CAMERA'

        #cam view center
        bpy.ops.view3d.view_center_camera()

        # set cam attributes
        set_cam_attributes(bpy.data.objects["C_0V0"])

        return {'FINISHED'}


class C_0V1(bpy.types.Operator):
    bl_idname = "cam.c0v1"
    bl_label = "C_0V1"
    cam_name = "C_0V1"

    def execute(self, context):
        C = bpy.context        
        # select cam in context area
        C.space_data.camera = bpy.data.objects["C_0V1"]

        # set scene cam
        for area in C.screen.areas:
            if area.type == 'VIEW_3D':
                A = C.area.spaces.active.camera

        C.scene.camera = bpy.data.objects[A.name]

        C.space_data.shading.color_type = 'OBJECT'
        C.space_data.region_3d.view_perspective = 'CAMERA'
        
        #cam view center
        bpy.ops.view3d.view_center_camera()

        # set cam attributes
        set_cam_attributes(bpy.data.objects["C_0V1"])

        return {'FINISHED'}

addon_keymaps = []

def register():
    bpy.utils.register_class(C_0V0)
    bpy.utils.register_class(C_0V1)

def unregister():
    bpy.utils.unregister_class(C_0V0)
    bpy.utils.unregister_class(C_0V1)

if __name__ == "__main__":
    register()

Depending on what you are trying to do you could also rewrite this code to just use one operator using bpy.properties. Using a StringProperty you can query the camera name and execute code based on user input.

import bpy

class C_0V0(bpy.types.Operator):
    bl_idname = "cam.c0v0"
    bl_label = "C_0V0"
    cam_name = "C_0V0"

    cam_name: bpy.props.StringProperty(name="Camera Name",
                                       default="C_0V0")

    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self, width=400)

    def draw(self, context):
        self.layout.prop(self, "cam_name")

    def execute(self, context):
        C = bpy.context

        cam_object = None
        lf_index = C.scene.objects.find(self.cam_name)
        if lf_index != -1:
            if C.scene.objects[lf_index].type == 'CAMERA':
                cam_object = C.scene.objects[lf_index]

        if not cam_object:
            self.report({'ERROR'}, f"Camera with name \"{self.cam_name}\" not found")
            return {'CANCELLED'}

        C.space_data.camera = cam_object

        # set scene cam
        for area in C.screen.areas:
            if area.type == 'VIEW_3D':
                A = C.area.spaces.active.camera

        C.scene.camera = cam_object

        C.space_data.shading.color_type = 'OBJECT'
        C.space_data.region_3d.view_perspective = 'CAMERA'

        # cam view center
        bpy.ops.view3d.view_center_camera()

        # set cam attributes
        cam_object.lock_scale = (True, True, True)
        cam_object.lock_location = (True, True, True)
        cam_object.lock_rotation = (True, True, True)
        cam_object.scale = (1, 1, 1)

        cam_data: bpy.types.Camera = cam_object.data

        cam_data.display_size = 0.05
        cam_data.dof.use_dof = False
        cam_data.clip_start = 25
        cam_data.clip_end = 100000
        if cam_data.background_images:
            cam_data.background_images[0].alpha = 0
            cam_data.background_images[0].scale = 1
            cam_data.background_images[1].scale = 1
            cam_data.background_images[2].scale = 1

        return {'FINISHED'}


def register():
    bpy.utils.register_class(C_0V0)


def unregister():
    bpy.utils.unregister_class(C_0V0)


if __name__ == "__main__":
    register()

If you don't want user input, you could also use properties passed as arguments in operator calls. This would look something like this.

bpy.ops.cam.c0v0(cam_name="C_0V0") # call executed on camera "C_0V0"
bpy.ops.cam.c0v0(cam_name="C_0V1") # call executed on camera "C_0V1"
$\endgroup$
2
  • $\begingroup$ Thanks for the reply, it's like this, each class executes the same content, only the name is different, if there are 80 such classes, I have to write 80 such class.Someone has simplified this code but there is something wrong with his code.blender.stackexchange.com/questions/291133/… $\endgroup$
    – lee blues
    Commented Apr 26, 2023 at 1:05
  • $\begingroup$ before my code ca switch the area‘s camera in the current area where the mouse is located,it is this paragraph code: “bpy.context.space_data.camera = bpy.data.objects["C_0V0"]” change to “c.space_data.camera = bpy.data.objects[self.cam_name]” It doesn't work anymore.,But the new code can only switch the camera in one area now when there ara many areas in windows.Please tell me how to modify it $\endgroup$
    – lee blues
    Commented Apr 26, 2023 at 1:06

You must log in to answer this question.

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