diff options
author | Damien Picard <dam.pic@free.fr> | 2019-12-17 13:11:37 +0300 |
---|---|---|
committer | Damien Picard <dam.pic@free.fr> | 2020-01-24 02:50:51 +0300 |
commit | 81ed56cbce99c9991c989163c802b4cea42be58e (patch) | |
tree | 43843eeb00ae6173767fbf8b5ad0c47fe0b26235 /add_camera_rigs/build_rigs.py | |
parent | f5f442a7a665bf219755a014701aafe967f806e7 (diff) |
add_camera_rigs: refactor and cleanup
- Fix widgets’ names: they were hardcoded and didn’t follow the
preferences, leading to crashes.
- The UI was put back into the Item category, instead of Create,
because it is not related to object creation.
- Fix some strange topology in two widget shapes.
- UI and operators use a new poll method, so that they work when
either the rig or the camera is selected.
- The composition guides UI was converted to a panel, so that they may
be drag-selected.
- Marker binding and DOF object operators were converted to the
`bpy.data` API, making them simpler.
- Bones were moved around so that they are more similar between rigs.
- They were scaled down to be 1 unit long, a simpler length — for
instance, widgets are the same size as modeled. Widgets were
scaled up to compensate.
- The camera and aim bones were placed at 1.7 unit high, to be
approximately at a standing human’s eyes’ height if the scene is
in meters.
- Much of the rig generation was refactored to deduplicate code
between the two rig types.
- Automatic renaming to `.000` was removed, since Blender already
handles duplicate names.
- Widget prefix and collection were renamed to `WGT-` and `Widgets`
respectively. This is to be closer to Rigify, hopefully unifying
them.
- The GPL license header was added to every file.
- Some cleanup was done to better respect Python’s PEP 8.
Reviewed By: Wayne Dixon
Differential Revision: https://developer.blender.org/D6543
Diffstat (limited to 'add_camera_rigs/build_rigs.py')
-rw-r--r-- | add_camera_rigs/build_rigs.py | 645 |
1 files changed, 200 insertions, 445 deletions
diff --git a/add_camera_rigs/build_rigs.py b/add_camera_rigs/build_rigs.py index c7303198..1a37bc6e 100644 --- a/add_camera_rigs/build_rigs.py +++ b/add_camera_rigs/build_rigs.py @@ -1,6 +1,25 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + import bpy +from bpy_extras import object_utils from bpy.types import Operator -from math import radians +from math import radians, pi from rna_prop_ui import rna_idprop_ui_prop_get from .create_widgets import (create_root_widget, create_widget, @@ -9,518 +28,254 @@ from .create_widgets import (create_root_widget, ) -def build_dolly_rig(context): - """Operator to build the dolly rig""" - # Set the bone layers - boneLayer = (False, True, False, False, False, False, False, False, - False, False, False, False, False, False, False, False, - False, False, False, False, False, False, False, False, - False, False, False, False, False, False, False, False) - - # Add the new armature object: - bpy.ops.object.armature_add() - rig = context.active_object - - # it will try to name the rig "Dolly_rig" but if that name exists it will - # add 000 to the name - if "Dolly_rig" not in context.scene.objects: - rig.name = "Dolly_rig" - else: - rig.name = "Dolly_rig.000" - rig["rig_id"] = "Dolly_rig" - - bpy.ops.object.mode_set(mode='EDIT') - - # Remove default bone: +def create_dolly_bones(rig, bone_layers): bones = rig.data.edit_bones - bones.remove(bones[0]) - # Add new bones: + # Add new bones root = bones.new("Root") - root.tail = (0.0, 3.0, 0.0) + root.tail = (0.0, 1.0, 0.0) + root.show_wire = True - bpy.ops.object.mode_set(mode='EDIT') - ctrlAimChild = bones.new("aim_MCH") - ctrlAimChild.head = (0.0, 5.0, 3.0) - ctrlAimChild.tail = (0.0, 7.0, 3.0) - ctrlAimChild.layers = boneLayer + ctrl_aim_child = bones.new("Aim_shape_rotation-MCH") + ctrl_aim_child.head = (0.0, 10.0, 1.7) + ctrl_aim_child.tail = (0.0, 11.0, 1.7) + ctrl_aim_child.layers = bone_layers - ctrlAim = bones.new("Aim") - ctrlAim.head = (0.0, 5.0, 3.0) - ctrlAim.tail = (0.0, 7.0, 3.0) + ctrl_aim = bones.new("Aim") + ctrl_aim.head = (0.0, 10.0, 1.7) + ctrl_aim.tail = (0.0, 11.0, 1.7) + ctrl_aim.show_wire = True ctrl = bones.new("Camera") - ctrl.head = (0.0, 0.0, 3.0) - ctrl.tail = (0.0, 2.0, 3.0) + ctrl.head = (0.0, 0.0, 1.7) + ctrl.tail = (0.0, 1.0, 1.7) + ctrl.show_wire = True - # Setup hierarchy: + # Setup hierarchy ctrl.parent = root - ctrlAim.parent = root - ctrlAimChild.parent = ctrlAim - - # jump into pose mode and change bones to euler - bpy.ops.object.mode_set(mode='POSE') - for x in bpy.context.object.pose.bones: - x.rotation_mode = 'XYZ' - - # jump into pose mode and add the custom bone shapes - bpy.ops.object.mode_set(mode='POSE') - bpy.context.object.pose.bones["Root"].custom_shape = bpy.data.objects[ - "WDGT_Camera_root"] # add the widget as custom shape - # set the wireframe checkbox to true - bpy.context.object.data.bones["Root"].show_wire = True - bpy.context.object.pose.bones[ - "Aim"].custom_shape = bpy.data.objects["WDGT_Aim"] - bpy.context.object.data.bones["Aim"].show_wire = True - bpy.context.object.pose.bones["Aim"].custom_shape_transform = bpy.data.objects[ - rig.name].pose.bones["aim_MCH"] # sets the "At" field to the child - bpy.context.object.pose.bones[ - "Camera"].custom_shape = bpy.data.objects["WDGT_Camera"] - bpy.context.object.data.bones["Camera"].show_wire = True - - # jump into object mode - bpy.ops.object.mode_set(mode='OBJECT') - - # Add constraints to bones: - con = rig.pose.bones['aim_MCH'].constraints.new('COPY_ROTATION') - con.target = rig - con.subtarget = "Camera" - - con = rig.pose.bones['Camera'].constraints.new('TRACK_TO') - con.target = rig - con.subtarget = "Aim" - con.use_target_z = True - - # Add custom Bone property to Camera bone - ob = bpy.context.object.pose.bones['Camera'] - prop = rna_idprop_ui_prop_get(ob, "lock", create=True) - ob["lock"] = 1.0 - prop["soft_min"] = prop["min"] = 0.0 - prop["soft_max"] = prop["max"] = 1.0 - - # Add Driver to Lock/Unlock Camera from Aim Target - rig = bpy.context.view_layer.objects.active - pose_bone = bpy.data.objects[rig.name].pose.bones['Camera'] - - constraint = pose_bone.constraints["Track To"] - inf_driver = constraint.driver_add('influence') - inf_driver.driver.type = 'SCRIPTED' - var = inf_driver.driver.variables.new() - var.name = 'var' - var.type = 'SINGLE_PROP' - - # Target the Custom bone property - var.targets[0].id = bpy.data.objects[rig.name] - var.targets[0].data_path = 'pose.bones["Camera"]["lock"]' - inf_driver.driver.expression = 'var' - - # Add custom property for the lens / add the driver after the camera is created - ob = bpy.context.object.pose.bones['Camera'] - prop = rna_idprop_ui_prop_get(ob, "focal_length", create=True) - ob["focal_length"] = 50.0 - prop["soft_min"] = prop["min"] = 1.0 - prop["default"] = 50.0 - prop["soft_max"] = prop["max"] = 5000.0 - - # Add custom property for the focus distance / add the driver after the camera is created - ob = bpy.context.object.pose.bones['Camera'] - prop = rna_idprop_ui_prop_get(ob, "focus_distance", create=True) - ob["focus_distance"] = 10.00 - prop["soft_min"] = prop["min"] = 0.0 - prop["soft_max"] = prop["max"] = 1000.0 - - # Add custom property for the f-stop / add the driver after the camera is created - ob = bpy.context.object.pose.bones['Camera'] - prop = rna_idprop_ui_prop_get(ob, "f-stop", create=True) - ob["f-stop"] = 2.8 - prop["soft_min"] = prop["min"] = 0.1 - prop["soft_max"] = prop["max"] = 128.00 - - # Add the camera object: - bpy.ops.object.mode_set(mode='OBJECT') - - bpy.ops.object.camera_add() - cam = bpy.context.active_object - - # Name the Camera Object - if 'Dolly_camera' not in context.scene.objects: - cam.name = "Dolly_camera" - else: - cam.name = "Dolly_camera.000" - - # this will name the camera data - cam.data.name = cam.name - - cam_data_name = bpy.context.object.data.name - bpy.data.cameras[cam_data_name].display_size = 1.0 - cam.rotation_euler = [radians(90), 0, 0] # rotate the camera 90 degrees in x - - cam.location = (0.0, -2.0, 0.0) # move the camera to the correct postion - cam.parent = rig - cam.parent_type = "BONE" - cam.parent_bone = "Camera" - - # Add Driver to link the camera lens to the custom property on the armature - pose_bone = bpy.data.objects[rig.name].pose.bones['Camera'] - lens_driver = cam.data.driver_add("lens") - lens_driver.driver.type = 'SCRIPTED' - var = lens_driver.driver.variables.new() - var.name = 'var' - var.type = 'SINGLE_PROP' - - # Target the Custom bone property - var.targets[0].id = bpy.data.objects[rig.name] - var.targets[0].data_path = 'pose.bones["Camera"]["focal_length"]' - lens_driver.driver.expression = 'var' - - # Add Driver to link the camera focus distance to the custom property on the armature - pose_bone = bpy.data.objects[rig.name].pose.bones['Camera'] - lens_driver = cam.data.driver_add("dof.focus_distance") - lens_driver.driver.type = 'SCRIPTED' - var = lens_driver.driver.variables.new() - var.name = 'var' - var.type = 'SINGLE_PROP' - - # Target the Custom bone property - var.targets[0].id = bpy.data.objects[rig.name] - var.targets[0].data_path = 'pose.bones["Camera"]["focus_distance"]' - lens_driver.driver.expression = 'var' - - # Add Driver to link the camera f-stop to the custom property on the armature - pose_bone = bpy.data.objects[rig.name].pose.bones['Camera'] - lens_driver = cam.data.driver_add("dof.aperture_fstop") - lens_driver.driver.type = 'SCRIPTED' - var = lens_driver.driver.variables.new() - var.name = 'var' - var.type = 'SINGLE_PROP' - - # Target the Custom bone property - var.targets[0].id = bpy.data.objects[rig.name] - var.targets[0].data_path = 'pose.bones["Camera"]["f-stop"]' - lens_driver.driver.expression = 'var' - - # lock the location/rotation/scale of the camera - cam.lock_location = [True, True, True] - cam.lock_rotation = [True, True, True] - cam.lock_scale = [True, True, True] - - # Set new camera as active camera - bpy.context.scene.camera = cam - - # make sure the camera is selectable by default (this can be locked in the UI) - bpy.context.object.hide_select = False - - # make the rig the active object before finishing - bpy.context.view_layer.objects.active = rig - bpy.data.objects[cam.name].select_set(False) - bpy.data.objects[rig.name].select_set(True) - - return rig - + ctrl_aim.parent = root + ctrl_aim_child.parent = ctrl_aim -class ADD_CAMERA_RIGS_OT_build_dolly_rig(Operator): - bl_idname = "add_camera_rigs.build_dolly_rig" - bl_label = "Build Dolly Camera Rig" - bl_description = "Build a Camera Dolly Rig" - bl_options = {'REGISTER', 'UNDO'} - def execute(self, context): - # build the Widgets - if not "WDGT_Camera_root" in bpy.context.scene.objects: - create_root_widget(self, "Camera_root") - if not "WDGT_Camera" in bpy.context.scene.objects: - create_camera_widget(self, "Camera") - if not "WDGT_Aim" in bpy.context.scene.objects: - create_aim_widget(self, "Aim") - - # call the function to build the rig - build_dolly_rig(context) - - return {'FINISHED'} - - -def build_crane_rig(context): - # Define some useful variables: - boneLayer = (False, True, False, False, False, False, False, False, - False, False, False, False, False, False, False, False, - False, False, False, False, False, False, False, False, - False, False, False, False, False, False, False, False) - - # Add the new armature object: - bpy.ops.object.armature_add() - rig = context.active_object - - # it will try to name the rig "Crane_rig" but if that name exists it will - # add .000 to the name - if "Crane_rig" not in context.scene.objects: - rig.name = "Crane_rig" - else: - rig.name = "Crane_rig.000" - rig["rig_id"] = "Crane_rig" - - bpy.ops.object.mode_set(mode='EDIT') - - # Remove default bone: +def create_crane_bones(rig, bone_layers): bones = rig.data.edit_bones - bones.remove(bones[0]) - # Add new bones: + # Add new bones root = bones.new("Root") - root.tail = (0.0, 3.0, 0.0) + root.tail = (0.0, 1.0, 0.0) + root.show_wire = True - ctrlAimChild = bones.new("aim_MCH") - ctrlAimChild.head = (0.0, 10.0, 1.0) - ctrlAimChild.tail = (0.0, 12.0, 1.0) - ctrlAimChild.layers = boneLayer + ctrl_aim_child = bones.new("Aim_shape_rotation-MCH") + ctrl_aim_child.head = (0.0, 10.0, 1.7) + ctrl_aim_child.tail = (0.0, 11.0, 1.7) + ctrl_aim_child.layers = bone_layers - ctrlAim = bones.new("Aim") - ctrlAim.head = (0.0, 10.0, 1.0) - ctrlAim.tail = (0.0, 12.0, 1.0) + ctrl_aim = bones.new("Aim") + ctrl_aim.head = (0.0, 10.0, 1.7) + ctrl_aim.tail = (0.0, 11.0, 1.7) + ctrl_aim.show_wire = True ctrl = bones.new("Camera") - ctrl.head = (0.0, 1.0, 1.0) - ctrl.tail = (0.0, 3.0, 1.0) + ctrl.head = (0.0, 1.0, 1.7) + ctrl.tail = (0.0, 2.0, 1.7) arm = bones.new("Crane_arm") - arm.head = (0.0, 0.0, 1.0) - arm.tail = (0.0, 1.0, 1.0) + arm.head = (0.0, 0.0, 1.7) + arm.tail = (0.0, 1.0, 1.7) height = bones.new("Crane_height") height.head = (0.0, 0.0, 0.0) - height.tail = (0.0, 0.0, 1.0) + height.tail = (0.0, 0.0, 1.7) - # Setup hierarchy: + # Setup hierarchy ctrl.parent = arm ctrl.use_inherit_rotation = False ctrl.use_inherit_scale = False + ctrl.show_wire = True arm.parent = height arm.use_inherit_scale = False height.parent = root - ctrlAim.parent = root - ctrlAimChild.parent = ctrlAim - - # change display to BBone: it just looks nicer - bpy.context.object.data.display_type = 'BBONE' - # change display to wire for object - bpy.context.object.display_type = 'WIRE' + ctrl_aim.parent = root + ctrl_aim_child.parent = ctrl_aim - # jump into pose mode and change bones to euler - bpy.ops.object.mode_set(mode='POSE') - for x in bpy.context.object.pose.bones: - x.rotation_mode = 'XYZ' - - # lock the relevant loc, rot and scale - bpy.context.object.pose.bones[ - "Crane_arm"].lock_rotation = [False, True, False] - bpy.context.object.pose.bones["Crane_arm"].lock_scale = [True, False, True] - bpy.context.object.pose.bones["Crane_height"].lock_location = [True, True, True] - bpy.context.object.pose.bones["Crane_height"].lock_rotation = [True, True, True] - bpy.context.object.pose.bones["Crane_height"].lock_scale = [True, False, True] - - # add the custom bone shapes - bpy.context.object.pose.bones["Root"].custom_shape = bpy.data.objects[ - "WDGT_Camera_root"] # add the widget as custom shape - # set the wireframe checkbox to true - bpy.context.object.data.bones["Root"].show_wire = True - bpy.context.object.pose.bones[ - "Aim"].custom_shape = bpy.data.objects["WDGT_Aim"] - bpy.context.object.data.bones["Aim"].show_wire = True - bpy.context.object.pose.bones["Aim"].custom_shape_transform = bpy.data.objects[ - rig.name].pose.bones["aim_MCH"] # sets the "At" field to the child - bpy.context.object.pose.bones[ - "Camera"].custom_shape = bpy.data.objects["WDGT_Camera"] - bpy.context.object.data.bones["Camera"].show_wire = True - - # jump into object mode + # Jump into object mode bpy.ops.object.mode_set(mode='OBJECT') + pose_bones = rig.pose.bones + + # Lock the relevant loc, rot and scale + pose_bones["Crane_arm"].lock_rotation = (False, True, False) + pose_bones["Crane_arm"].lock_scale = (True, False, True) + pose_bones["Crane_height"].lock_location = (True, True, True) + pose_bones["Crane_height"].lock_rotation = (True, True, True) + pose_bones["Crane_height"].lock_scale = (True, False, True) + + +def build_camera_rig(context, mode): + bone_layers = tuple(i == 1 for i in range(32)) + view_layer = bpy.context.view_layer - # Add constraints to bones: - con = rig.pose.bones['aim_MCH'].constraints.new('COPY_ROTATION') + rig_name = mode.capitalize() + "_Rig" + rig_data = bpy.data.armatures.new(rig_name) + rig = object_utils.object_data_add(context, rig_data, name=rig_name) + rig["rig_id"] = "%s" % rig_name + view_layer.objects.active = rig + rig.location = context.scene.cursor.location + + bpy.ops.object.mode_set(mode='EDIT') + + # Add new bones + if mode == "DOLLY": + create_dolly_bones(rig, bone_layers) + elif mode == "CRANE": + create_crane_bones(rig, bone_layers) + + # Jump into object mode and change bones to euler + bpy.ops.object.mode_set(mode='OBJECT') + pose_bones = rig.pose.bones + for b in pose_bones: + b.rotation_mode = 'XYZ' + + # Add custom properties to the armature’s Camera bone, + # so that all properties may be animated in a single action + # Add driver after the camera is created + + # Lens property + pb = pose_bones['Camera'] + pb["lens"] = 50.0 + prop = rna_idprop_ui_prop_get(pb, "lens", create=True) + prop["default"] = 50.0 + prop["min"] = 1.0 + prop["max"] = 1000000.0 + prop["soft_max"] = 5000.0 + + # DOF Focus Distance property + pb = pose_bones['Camera'] + pb["focus_distance"] = 10.0 + prop = rna_idprop_ui_prop_get(pb, "focus_distance", create=True) + prop["default"] = 10.0 + prop["min"] = 0.0 + + # DOF F-Stop property + pb = pose_bones['Camera'] + pb["aperture_fstop"] = 2.8 + prop = rna_idprop_ui_prop_get(pb, "aperture_fstop", create=True) + prop["default"] = 2.8 + prop["min"] = 0.0 + prop["soft_min"] = 0.1 + prop["soft_max"] = 128.0 + + # Build the widgets + root_widget = create_root_widget("Camera_Root") + camera_widget = create_camera_widget("Camera") + aim_widget = create_aim_widget("Aim") + + # Add the custom bone shapes + pose_bones["Root"].custom_shape = root_widget + pose_bones["Aim"].custom_shape = aim_widget + pose_bones["Camera"].custom_shape = camera_widget + + # Set the "At" field to the child + pose_bones["Aim"].custom_shape_transform = pose_bones["Aim_shape_rotation-MCH"] + + # Add constraints to bones + con = pose_bones['Aim_shape_rotation-MCH'].constraints.new('COPY_ROTATION') con.target = rig con.subtarget = "Camera" - con = rig.pose.bones['Camera'].constraints.new('TRACK_TO') + con = pose_bones['Camera'].constraints.new('TRACK_TO') con.target = rig con.subtarget = "Aim" con.use_target_z = True - # Add custom Bone property to Camera bone - ob = bpy.context.object.pose.bones['Camera'] - prop = rna_idprop_ui_prop_get(ob, "lock", create=True) - ob["lock"] = 1.0 - prop["soft_min"] = prop["min"] = 0.0 - prop["soft_max"] = prop["max"] = 1.0 - - # Add Driver to Lock/Unlock Camera from Aim Target - rig = bpy.context.view_layer.objects.active - pose_bone = bpy.data.objects[rig.name].pose.bones['Camera'] - - constraint = pose_bone.constraints["Track To"] - inf_driver = constraint.driver_add('influence') - inf_driver.driver.type = 'SCRIPTED' - var = inf_driver.driver.variables.new() - var.name = 'var' - var.type = 'SINGLE_PROP' - - # Target the Custom bone property - var.targets[0].id = bpy.data.objects[rig.name] - var.targets[0].data_path = 'pose.bones["Camera"]["lock"]' - inf_driver.driver.expression = 'var' - - # Add custom property for the lens / add the driver after the camera is created - ob = bpy.context.object.pose.bones['Camera'] - prop = rna_idprop_ui_prop_get(ob, "focal_length", create=True) - ob["focal_length"] = 50.0 - prop["soft_min"] = prop["min"] = 1.0 - prop["default"] = 50.0 - prop["soft_max"] = prop["max"] = 5000.0 - - # Add custom property for the focus distance / add the driver after the camera is created - ob = bpy.context.object.pose.bones['Camera'] - prop = rna_idprop_ui_prop_get(ob, "focus_distance", create=True) - ob["focus_distance"] = 10.00 - prop["soft_min"] = prop["min"] = 0.0 - prop["soft_max"] = prop["max"] = 1000.0 - - # Add custom property for the focus distance / add the driver after the camera is created - ob = bpy.context.object.pose.bones['Camera'] - prop = rna_idprop_ui_prop_get(ob, "focus_distance", create=True) - ob["focus_distance"] = 10.00 - prop["soft_min"] = prop["min"] = 0.0 - prop["soft_max"] = prop["max"] = 1000.0 - - # Add custom property for the f-stop / add the driver after the camera is created - ob = bpy.context.object.pose.bones['Camera'] - prop = rna_idprop_ui_prop_get(ob, "f-stop", create=True) - ob["f-stop"] = 2.8 - prop["soft_min"] = prop["min"] = 0.1 - prop["soft_max"] = prop["max"] = 128.00 - - # Add the camera object: - bpy.ops.object.mode_set(mode='OBJECT') + # Change display to BBone: it just looks nicer + bpy.context.object.data.display_type = 'BBONE' + # Change display to wire for object + bpy.context.object.display_type = 'WIRE' + + # Add the camera object + cam_name = "%s_Camera" % mode.capitalize() + cam_data = bpy.data.cameras.new(cam_name) + cam = object_utils.object_data_add(context, cam_data, name=cam_name) + view_layer.objects.active = cam + context.scene.camera = cam + + cam.data.display_size = 1.0 + cam.rotation_euler[0] = pi / 2.0 # Rotate the camera 90 degrees in x - bpy.ops.object.camera_add() - cam = bpy.context.active_object - - # this will name the Camera Object - if 'Crane_camera' not in context.scene.objects: - cam.name = "Crane_camera" - else: - cam.name = "Crane_camera.000" - - # this will name the camera Data Object - if "Crane_camera" not in bpy.context.scene.objects.data.camera: - cam.data.name = "Crane_camera" - else: - cam.data.name = "Crane_camera.000" - - cam_data_name = bpy.context.object.data.name - bpy.data.cameras[cam_data_name].display_size = 1.0 - cam.rotation_euler = [radians(90), 0, 0] # rotate the camera 90 degrees in x - cam.location = (0.0, -2.0, 0.0) # move the camera to the correct postion + cam.location = (0.0, -1.0, 0.0) # Move the camera to the correct position cam.parent = rig cam.parent_type = "BONE" cam.parent_bone = "Camera" - # Add Driver to link the camera lens to the custom property on the armature - pose_bone = bpy.data.objects[rig.name].pose.bones['Camera'] - lens_driver = cam.data.driver_add("lens") - lens_driver.driver.type = 'SCRIPTED' - var = lens_driver.driver.variables.new() - var.name = 'var' - var.type = 'SINGLE_PROP' - - # Target the Custom bone property - var.targets[0].id = bpy.data.objects[rig.name] - var.targets[0].data_path = 'pose.bones["Camera"]["focal_length"]' - lens_driver.driver.expression = 'var' - - # Add Driver to link the camera focus distance to the custom property on the armature - pose_bone = bpy.data.objects[rig.name].pose.bones['Camera'] - lens_driver = cam.data.driver_add("dof.focus_distance") - lens_driver.driver.type = 'SCRIPTED' - var = lens_driver.driver.variables.new() - var.name = 'var' - var.type = 'SINGLE_PROP' - - # Target the Custom bone property - var.targets[0].id = bpy.data.objects[rig.name] - var.targets[0].data_path = 'pose.bones["Camera"]["focus_distance"]' - lens_driver.driver.expression = 'var' - - # Add Driver to link the camera f-stop to the custom property on the armature - pose_bone = bpy.data.objects[rig.name].pose.bones['Camera'] - lens_driver = cam.data.driver_add("dof.aperture_fstop") - lens_driver.driver.type = 'SCRIPTED' - var = lens_driver.driver.variables.new() - var.name = 'var' - var.type = 'SINGLE_PROP' - - # Target the Custom bone property - var.targets[0].id = bpy.data.objects[rig.name] - var.targets[0].data_path = 'pose.bones["Camera"]["f-stop"]' - lens_driver.driver.expression = 'var' - - # the location/rotation/scale of the camera - cam.lock_location = [True, True, True] - cam.lock_rotation = [True, True, True] - cam.lock_scale = [True, True, True] - - # Set new camera as active camera - bpy.context.scene.camera = cam - - # make sure the camera is selectable by default (this can be locked in the UI) - bpy.context.object.hide_select = False - - # make the rig the active object before finishing - bpy.context.view_layer.objects.active = rig - bpy.data.objects[cam.name].select_set(False) - bpy.data.objects[rig.name].select_set(True) + # Lock camera transforms + cam.lock_location = (True,) * 3 + cam.lock_rotation = (True,) * 3 + cam.lock_scale = (True,) * 3 + + # Add drivers to link the camera properties to the custom props + # on the armature + for prop_from, prop_to in (("lens", "lens"), + ("focus_distance", "dof.focus_distance"), + ("aperture_fstop", "dof.aperture_fstop")): + driver = cam.data.driver_add(prop_to) + driver.driver.type = 'SCRIPTED' + var = driver.driver.variables.new() + var.name = 'var' + var.type = 'SINGLE_PROP' + + # Target the custom bone property + var.targets[0].id = rig + var.targets[0].data_path = 'pose.bones["Camera"]["%s"]' % prop_from + driver.driver.expression = 'var' + + # Make the rig the active object + for ob in view_layer.objects: + ob.select_set(False) + rig.select_set(True) + view_layer.objects.active = rig return rig -class ADD_CAMERA_RIGS_OT_build_crane_rig(Operator): - bl_idname = "add_camera_rigs.build_crane_rig" - bl_label = "Build Crane Camera Rig" - bl_description = "Build a Camera Crane Rig" +class OBJECT_OT_build_camera_rig(Operator): + bl_idname = "object.build_camera_rig" + bl_label = "Build Camera Rig" + bl_description = "Build a Camera Rig" bl_options = {'REGISTER', 'UNDO'} - def execute(self, context): - # build the Widgets - if not "WDGT_Camera_root" in bpy.context.scene.objects: - create_root_widget(self, "Camera_root") - if not "WDGT_Camera" in bpy.context.scene.objects: - create_camera_widget(self, "Camera") - if not "WDGT_Aim" in bpy.context.scene.objects: - create_aim_widget(self, "Aim") - - # call the function to build the rig - build_crane_rig(context) + mode: bpy.props.EnumProperty(items= + (('DOLLY',) * 3, + ('CRANE',) * 3,), + name="mode", + description="", default="DOLLY") + def execute(self, context): + # Build the rig + build_camera_rig(context, self.mode) return {'FINISHED'} -# dolly and crane entries in the Add Object > Camera Menu def add_dolly_crane_buttons(self, context): + """Dolly and crane entries in the Add Object > Camera Menu""" if context.mode == 'OBJECT': - self.layout.operator( - ADD_CAMERA_RIGS_OT_build_dolly_rig.bl_idname, + op = self.layout.operator( + OBJECT_OT_build_camera_rig.bl_idname, text="Dolly Camera Rig", icon='CAMERA_DATA' ) - self.layout.operator( - ADD_CAMERA_RIGS_OT_build_crane_rig.bl_idname, + op.mode = "DOLLY" + op = self.layout.operator( + OBJECT_OT_build_camera_rig.bl_idname, text="Crane Camera Rig", icon='CAMERA_DATA' ) + op.mode = "CRANE" classes = ( - ADD_CAMERA_RIGS_OT_build_dolly_rig, - ADD_CAMERA_RIGS_OT_build_crane_rig, + OBJECT_OT_build_camera_rig, ) |