Skip to content
Snippets Groups Projects
  • Damien Picard's avatar
    81ed56cb
    add_camera_rigs: refactor and cleanup · 81ed56cb
    Damien Picard authored
    - 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
    81ed56cb
    History
    add_camera_rigs: refactor and cleanup
    Damien Picard authored
    - 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
operators.py 3.80 KiB
# ##### 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.types import Operator


def get_arm_and_cam(obj):
    if obj.type == 'ARMATURE':
        cam = None
        for child in obj.children:
            if child.type == 'CAMERA':
                cam = child
                break
        if cam is not None:
            return obj, cam
    elif (obj.type == 'CAMERA'
          and obj.parent is not None
          and "rig_id" in obj.parent
          and obj.parent["rig_id"].lower() in {"dolly_rig", "crane_rig"}):
        return obj.parent, obj
    return None, None


class CameraRigMixin():
    @classmethod
    def poll(cls, context):
        if context.active_object is not None:
            return get_arm_and_cam(context.active_object) != (None, None)

        return False


class ADD_CAMERA_RIGS_OT_set_scene_camera(Operator, CameraRigMixin):
    bl_idname = "add_camera_rigs.set_scene_camera"
    bl_label = "Make Camera Active"
    bl_description = "Makes the camera parented to this rig the active scene camera"

    def execute(self, context):
        arm, cam = get_arm_and_cam(context.active_object)
        scene_cam = context.scene.camera

        if cam is not None and cam is not scene_cam:
            context.scene.camera = cam
            return {'FINISHED'}

        return {'CANCELLED'}


class ADD_CAMERA_RIGS_OT_add_marker_bind(Operator, CameraRigMixin):
    bl_idname = "add_camera_rigs.add_marker_bind"
    bl_label = "Add Marker and Bind Camera"
    bl_description = "Add marker to current frame then bind rig camera to it (for camera switching)"

    def execute(self, context):
        arm, cam = get_arm_and_cam(context.active_object)

        marker = context.scene.timeline_markers.new(
            "cam_" + str(context.scene.frame_current),
            frame=context.scene.frame_current
        )
        marker.camera = cam

        return {'FINISHED'}


class ADD_CAMERA_RIGS_OT_add_dof_object(Operator, CameraRigMixin):
    bl_idname = "add_camera_rigs.add_dof_object"
    bl_label = "Add DOF Object"
    bl_description = "Create Empty and add as DOF Object"

    def execute(self, context):
        arm, cam = get_arm_and_cam(context.active_object)
        bone = arm.data.bones['Aim_shape_rotation-MCH']

        # Add Empty
        empty_obj = bpy.data.objects.new("EmptyDOF", None)
        context.scene.collection.objects.link(empty_obj)

        # Parent to Aim Child bone
        empty_obj.parent = arm
        empty_obj.parent_type = "BONE"
        empty_obj.parent_bone = "Aim_shape_rotation-MCH"

        # Move to bone head
        empty_obj.location = bone.head

        # Make this new empty the dof_object
        cam.data.dof.use_dof = True
        cam.data.dof.focus_object = empty_obj

        return {'FINISHED'}


classes = (
    ADD_CAMERA_RIGS_OT_set_scene_camera,
    ADD_CAMERA_RIGS_OT_add_marker_bind,
    ADD_CAMERA_RIGS_OT_add_dof_object,
)


def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)


def unregister():
    from bpy.utils import unregister_class
    for cls in classes:
        unregister_class(cls)