diff options
author | Lucio Rossi <lucio.rossi75@gmail.com> | 2017-07-24 19:14:16 +0300 |
---|---|---|
committer | Lucio Rossi <lucio.rossi75@gmail.com> | 2017-07-24 19:14:30 +0300 |
commit | 33b0e2e9025965133656dd85506bbef62ca3183d (patch) | |
tree | 52f2368a79623272cadf64a9c1ca3ac209176231 | |
parent | 49230a4c122013bf851ab37b029e7d4f624d68ad (diff) |
Rigify 0.5: new features, Animation Tools and Quat/Euler converter
small fixes & UI improvements
-rw-r--r-- | rigify/__init__.py | 7 | ||||
-rw-r--r-- | rigify/generate.py | 11 | ||||
-rw-r--r-- | rigify/metarigs/Animals/bird.py | 2 | ||||
-rw-r--r-- | rigify/rigs/experimental/super_chain.py | 22 | ||||
-rw-r--r-- | rigify/rigs/faces/super_face.py | 60 | ||||
-rw-r--r-- | rigify/rigs/limbs/arm.py | 80 | ||||
-rw-r--r-- | rigify/rigs/limbs/leg.py | 104 | ||||
-rw-r--r-- | rigify/rigs/limbs/paw.py | 92 | ||||
-rw-r--r-- | rigify/rigs/limbs/simple_tentacle.py | 32 | ||||
-rw-r--r-- | rigify/rigs/limbs/super_limb.py | 33 | ||||
-rw-r--r-- | rigify/rigs/limbs/super_palm.py | 2 | ||||
-rw-r--r-- | rigify/rigs/limbs/ui.py | 10 | ||||
-rw-r--r-- | rigify/rigs/misc/__init__.py | 0 | ||||
-rw-r--r-- | rigify/rigs/misc/delta.py | 165 | ||||
-rw-r--r-- | rigify/rigs/spines/super_spine.py | 28 | ||||
-rw-r--r-- | rigify/rigs/utils.py | 21 | ||||
-rw-r--r-- | rigify/rot_mode.py | 359 | ||||
-rw-r--r-- | rigify/ui.py | 555 | ||||
-rw-r--r-- | rigify/utils.py | 99 |
19 files changed, 1411 insertions, 271 deletions
diff --git a/rigify/__init__.py b/rigify/__init__.py index b86b7038..802aed11 100644 --- a/rigify/__init__.py +++ b/rigify/__init__.py @@ -318,6 +318,10 @@ def register(): description="Defines the name of the Rig. If unset, in 'new' mode 'rig' will be used, in 'overwrite' mode the target rig name will be used", default="") + IDStore.rigify_transfer_only_selected = bpy.props.BoolProperty(name="Transfer Only Selected", description="Transfer selected bones only", default=True) + IDStore.rigify_transfer_start_frame = bpy.props.IntProperty(name="Start Frame", description="First Frame to Transfer", default=0, min= 0) + IDStore.rigify_transfer_end_frame = bpy.props.IntProperty(name="End Frame", description="Last Frame to Transfer", default=0, min= 0) + if (ui and 'legacy' in str(ui)) or bpy.context.user_preferences.addons['rigify'].preferences.legacy_mode: # update legacy on restart or reload bpy.context.user_preferences.addons['rigify'].preferences.legacy_mode = True @@ -347,6 +351,9 @@ def unregister(): del IDStore.rigify_rig_uis del IDStore.rigify_rig_ui del IDStore.rigify_rig_basename + del IDStore.rigify_transfer_only_selected + del IDStore.rigify_transfer_start_frame + del IDStore.rigify_transfer_end_frame bpy.utils.unregister_class(RigifyName) bpy.utils.unregister_class(RigifyParameters) diff --git a/rigify/generate.py b/rigify/generate.py index 01e5de28..42523490 100644 --- a/rigify/generate.py +++ b/rigify/generate.py @@ -134,6 +134,11 @@ def generate_rig(context, metarig): wgts_group_name = "WGTS_" + obj.name + # Get parented objects to restore later + childs = {} # {object: bone} + for child in obj.children: + childs[child] = child.parent_bone + # Remove all bones from the generated rig armature. bpy.ops.object.mode_set(mode='EDIT') for bone in obj.data.edit_bones: @@ -526,6 +531,12 @@ def generate_rig(context, metarig): metarig.data.pose_position = rest_backup obj.data.pose_position = 'POSE' + # Restore parent to bones + for child, sub_parent in childs.items(): + if sub_parent in obj.pose.bones: + mat = child.matrix_world.copy() + child.parent_bone = sub_parent + child.matrix_world = mat def create_selection_sets(obj, metarig): diff --git a/rigify/metarigs/Animals/bird.py b/rigify/metarigs/Animals/bird.py index 0c4f7d31..15b75a11 100644 --- a/rigify/metarigs/Animals/bird.py +++ b/rigify/metarigs/Animals/bird.py @@ -914,6 +914,7 @@ def create(obj): pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' + pbone.rigify_parameters.copy_rotation_axes = [False, False, False] pbone.bone.layers = [False, False, False, False, False, False, 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] try: pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] @@ -934,6 +935,7 @@ def create(obj): pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' + pbone.rigify_parameters.copy_rotation_axes = [False, False, False] pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] diff --git a/rigify/rigs/experimental/super_chain.py b/rigify/rigs/experimental/super_chain.py index cff25f2a..32c1b925 100644 --- a/rigify/rigs/experimental/super_chain.py +++ b/rigify/rigs/experimental/super_chain.py @@ -1310,24 +1310,38 @@ def parameters_ui(layout, params): col = r.column(align=True) row = col.row(align=True) + bone_layers = bpy.context.active_pose_bone.bone.layers[:] + for i in range(8): - row.prop(params, "tweak_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, "tweak_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) for i in range(16,24): - row.prop(params, "tweak_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, "tweak_layers", index=i, toggle=True, text="", icon=icon) col = r.column(align=True) row = col.row(align=True) for i in range(8,16): - row.prop(params, "tweak_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, "tweak_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) for i in range(24,32): - row.prop(params, "tweak_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, "tweak_layers", index=i, toggle=True, text="", icon=icon) def create_sample(obj): diff --git a/rigify/rigs/faces/super_face.py b/rigify/rigs/faces/super_face.py index f5121f90..dcdb1093 100644 --- a/rigify/rigs/faces/super_face.py +++ b/rigify/rigs/faces/super_face.py @@ -1031,26 +1031,26 @@ def add_parameters(params): RigifyParameters PropertyGroup """ - #Setting up extra layers for the tweak bones + # Setting up extra layers for the tweak bones params.primary_layers_extra = bpy.props.BoolProperty( - name = "primary_layers_extra", - default = True, - description = "" + name="primary_layers_extra", + default=True, + description="" ) params.primary_layers = bpy.props.BoolVectorProperty( - size = 32, - description = "Layers for the 1st tweak controls to be on", - default = tuple( [ i == 1 for i in range(0, 32) ] ) + size=32, + description="Layers for the 1st tweak controls to be on", + default=tuple([i == 1 for i in range(0, 32)]) ) params.secondary_layers_extra = bpy.props.BoolProperty( - name = "secondary_layers_extra", - default = True, - description = "" + name="secondary_layers_extra", + default=True, + description="" ) params.secondary_layers = bpy.props.BoolVectorProperty( - size = 32, - description = "Layers for the 2nd tweak controls to be on", - default = tuple( [ i == 1 for i in range(0, 32) ] ) + size=32, + description="Layers for the 2nd tweak controls to be on", + default=tuple([i == 1 for i in range(0, 32)]) ) @@ -1058,29 +1058,43 @@ def parameters_ui(layout, params): """ Create the ui for the rig parameters.""" layers = ["primary_layers", "secondary_layers"] + bone_layers = bpy.context.active_pose_bone.bone.layers[:] + for layer in layers: r = layout.row() r.prop( params, layer + "_extra" ) r.active = getattr( params, layer + "_extra" ) - + col = r.column(align=True) row = col.row(align=True) for i in range(8): - row.prop(params, layer, index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer, index=i, toggle=True, text="", icon=icon) row = col.row(align=True) - for i in range(16,24): - row.prop(params, layer, index=i, toggle=True, text="") - + for i in range(16, 24): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer, index=i, toggle=True, text="", icon=icon) + col = r.column(align=True) row = col.row(align=True) - - for i in range(8,16): - row.prop(params, layer, index=i, toggle=True, text="") + + for i in range(8, 16): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer, index=i, toggle=True, text="", icon=icon) row = col.row(align=True) - for i in range(24,32): - row.prop(params, layer, index=i, toggle=True, text="") + for i in range(24, 32): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer, index=i, toggle=True, text="", icon=icon) def create_sample(obj): diff --git a/rigify/rigs/limbs/arm.py b/rigify/rigs/limbs/arm.py index b5c07569..193e2034 100644 --- a/rigify/rigs/limbs/arm.py +++ b/rigify/rigs/limbs/arm.py @@ -4,7 +4,7 @@ from .ui import create_script from .limb_utils import * from mathutils import Vector from ...utils import copy_bone, flip_bone, put_bone, create_cube_widget -from ...utils import strip_org, make_deformer_name, create_widget +from ...utils import strip_org, strip_mch, make_deformer_name, create_widget from ...utils import create_circle_widget, create_sphere_widget, create_line_widget from ...utils import MetarigError, make_mechanism_name, org from ...utils import create_limb_widget, connected_children_names @@ -982,6 +982,52 @@ class Rig: var.targets[0].data_path = \ owner.path_from_id() + '[' + '"' + prop + '"' + ']' + @staticmethod + def get_future_names(bones): + + if len(bones) != 3: + return + + names = dict() + + uarm = strip_mch(strip_org(bones[0].name)) + farm = strip_mch(strip_org(bones[1].name)) + hand = strip_mch(strip_org(bones[2].name)) + + suffix='' + if uarm[-2:] == '.L' or uarm[-2:] == '.R': + suffix = uarm[-2:] + uarm = uarm.rstrip(suffix) + farm = farm.rstrip(suffix) + hand = hand.rstrip(suffix) + + # the following is declared in rig_ui + # controls = ['upper_arm_ik.L', 'upper_arm_fk.L', 'forearm_fk.L', 'hand_fk.L', 'hand_ik.L', 'MCH-hand_fk.L', + # 'upper_arm_parent.L'] + # tweaks = ['upper_arm_tweak.L.001', 'forearm_tweak.L', 'forearm_tweak.L.001'] + # ik_ctrl = ['hand_ik.L', 'MCH-upper_arm_ik.L', 'MCH-upper_arm_ik_target.L'] + # fk_ctrl = 'upper_arm_fk.L' + # parent = 'upper_arm_parent.L' + # hand_fk = 'hand_fk.L' + # pole = 'upper_arm_ik_target.L' + + names['controls'] = [uarm + '_ik', uarm + '_fk', farm + '_fk', hand + '_fk', hand + '_ik', + make_mechanism_name(hand + '_fk'), uarm + '_parent'] + names['ik_ctrl'] = [hand + '_ik', make_mechanism_name(uarm) + '_ik', make_mechanism_name(uarm) + '_ik_target'] + names['fk_ctrl'] = uarm + '_fk' + suffix + names['parent'] = uarm + '_parent' + suffix + names['hand_fk'] = hand + '_fk' + suffix + names['pole'] = uarm + '_ik_target' + suffix + names['limb_type'] = 'arm' + + if suffix: + for i, name in enumerate(names['controls']): + names['controls'][i] = name + suffix + for i, name in enumerate(names['ik_ctrl']): + names['ik_ctrl'][i] = name + suffix + + return names + def generate(self): bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones @@ -1105,7 +1151,9 @@ def parameters_ui(layout, params): r = layout.row() r.prop(params, "bbones") - for layer in [ 'fk', 'tweak' ]: + bone_layers = bpy.context.active_pose_bone.bone.layers[:] + + for layer in ['fk', 'tweak']: r = layout.row() r.prop(params, layer + "_extra_layers") r.active = params.tweak_extra_layers @@ -1114,23 +1162,35 @@ def parameters_ui(layout, params): row = col.row(align=True) for i in range(8): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) - for i in range(16,24): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + for i in range(16, 24): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) col = r.column(align=True) row = col.row(align=True) - for i in range(8,16): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + for i in range(8, 16): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) - for i in range(24,32): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + for i in range(24, 32): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) def create_sample(obj): @@ -1341,7 +1401,7 @@ def create_sample(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone = obj.pose.bones[bones['palm.01.L']] - pbone.rigify_type = 'palm' + pbone.rigify_type = 'limbs.super_palm' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False diff --git a/rigify/rigs/limbs/leg.py b/rigify/rigs/limbs/leg.py index 021f641b..6c76dd9f 100644 --- a/rigify/rigs/limbs/leg.py +++ b/rigify/rigs/limbs/leg.py @@ -5,7 +5,7 @@ from .ui import create_script from .limb_utils import * from mathutils import Vector from ...utils import copy_bone, flip_bone, put_bone, create_cube_widget -from ...utils import strip_org, make_deformer_name, create_widget +from ...utils import strip_org, strip_mch, make_deformer_name, create_widget from ...utils import create_circle_widget, create_sphere_widget, create_line_widget from ...utils import MetarigError, make_mechanism_name, org from ...utils import create_limb_widget, connected_children_names @@ -363,7 +363,7 @@ class Rig: # Rubber hose drivers pb = self.obj.pose.bones - for i,t in enumerate( tweaks[1:-1] ): + for i, t in enumerate(tweaks[1:-1]): # Create custom property on tweak bone to control rubber hose name = 'rubber_tweak' @@ -406,18 +406,18 @@ class Rig: def create_ik(self, parent): org_bones = self.org_bones - bpy.ops.object.mode_set(mode ='EDIT') + bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones ctrl = get_bone_name(org_bones[0], 'ctrl', 'ik') mch_ik = get_bone_name(org_bones[0], 'mch', 'ik') mch_target = get_bone_name(org_bones[0], 'mch', 'ik_target') - for o, ik in zip( org_bones, [ ctrl, mch_ik, mch_target ] ): - bone = copy_bone( self.obj, o, ik ) + for o, ik in zip(org_bones, [ctrl, mch_ik, mch_target]): + bone = copy_bone(self.obj, o, ik) - if org_bones.index(o) == len( org_bones ) - 1: - eb[ bone ].length /= 4 + if org_bones.index(o) == len(org_bones) - 1: + eb[bone].length /= 4 # Create MCH Stretch mch_str = copy_bone( @@ -687,6 +687,13 @@ class Rig: else: leg_parent = None + mch_name = get_bone_name(strip_org(org_bones[0]), 'mch', 'parent_socket') + mch_main_parent = copy_bone(self.obj, org_bones[0], mch_name) + eb[mch_main_parent].length = eb[org_bones[0]].length / 12 + eb[mch_main_parent].parent = eb[bones['parent']] + eb[mch_main_parent].roll = 0.0 + eb[bones['main_parent']].parent = eb[mch_main_parent] + # Create heel ctrl bone heel = get_bone_name(org_bones[2], 'ctrl', 'heel_ik') heel = copy_bone(self.obj, org_bones[2], heel) @@ -948,6 +955,10 @@ class Rig: 'max_y' : 1.05, 'owner_space' : 'LOCAL' }) + make_constraint(self, mch_main_parent, { + 'constraint': 'COPY_ROTATION', + 'subtarget': org_bones[0] + }) # Create ik/fk switch property pb_parent = pb[bones['main_parent']] @@ -1291,6 +1302,55 @@ class Rig: var.targets[0].data_path = \ owner.path_from_id() + '[' + '"' + prop + '"' + ']' + @staticmethod + def get_future_names(bones): + + if len(bones) != 4: + return + + names = dict() + + thigh = strip_mch(strip_org(bones[0].name)) + shin = strip_mch(strip_org(bones[1].name)) + foot = strip_mch(strip_org(bones[2].name)) + toe = strip_mch(strip_org(bones[3].name)) + + suffix = '' + if thigh[-2:] == '.L' or thigh[-2:] == '.R': + suffix = thigh[-2:] + thigh = thigh.rstrip(suffix) + shin = shin.rstrip(suffix) + foot = foot.rstrip(suffix) + toe = toe.rstrip(suffix) + + # the following is declared in rig_ui + # controls = ['thigh_ik.R', 'thigh_fk.R', 'shin_fk.R', 'foot_fk.R', 'toe.R', 'foot_heel_ik.R', 'foot_ik.R', + # 'MCH-foot_fk.R', 'thigh_parent.R'] + # tweaks = ['thigh_tweak.R.001', 'shin_tweak.R', 'shin_tweak.R.001'] + # ik_ctrl = ['foot_ik.R', 'MCH-thigh_ik.R', 'MCH-thigh_ik_target.R'] + # fk_ctrl = 'thigh_fk.R' + # parent = 'thigh_parent.R' + # foot_fk = 'foot_fk.R' + # pole = 'thigh_ik_target.R' + + names['controls'] = [thigh + '_ik', thigh + '_fk', shin + '_fk', foot + '_fk', toe, foot + '_heel_ik', + foot + '_ik', make_mechanism_name(foot + '_fk'), thigh + '_parent'] + names['ik_ctrl'] = [foot + '_ik', make_mechanism_name(thigh) + '_ik', make_mechanism_name(thigh) + '_ik_target'] + names['fk_ctrl'] = thigh + '_fk' + suffix + names['parent'] = thigh + '_parent' + suffix + names['foot_fk'] = foot + '_fk' + suffix + names['pole'] = thigh + '_ik_target' + suffix + + names['limb_type'] = 'leg' + + if suffix: + for i, name in enumerate(names['controls']): + names['controls'][i] = name + suffix + for i, name in enumerate(names['ik_ctrl']): + names['ik_ctrl'][i] = name + suffix + + return names + def generate(self): bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones @@ -1414,7 +1474,9 @@ def parameters_ui(layout, params): r = layout.row() r.prop(params, "bbones") - for layer in [ 'fk', 'tweak' ]: + bone_layers = bpy.context.active_pose_bone.bone.layers[:] + + for layer in ['fk', 'tweak']: r = layout.row() r.prop(params, layer + "_extra_layers") r.active = params.tweak_extra_layers @@ -1423,23 +1485,35 @@ def parameters_ui(layout, params): row = col.row(align=True) for i in range(8): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) - for i in range(16,24): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + for i in range(16, 24): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) col = r.column(align=True) row = col.row(align=True) - for i in range(8,16): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + for i in range(8, 16): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) - for i in range(24,32): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + for i in range(24, 32): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) def create_sample(obj): diff --git a/rigify/rigs/limbs/paw.py b/rigify/rigs/limbs/paw.py index 8c9dab20..9c39d87b 100644 --- a/rigify/rigs/limbs/paw.py +++ b/rigify/rigs/limbs/paw.py @@ -3,7 +3,7 @@ from .ui import create_script from .limb_utils import * from mathutils import Vector from ...utils import copy_bone, flip_bone, put_bone, create_cube_widget -from ...utils import strip_org, make_deformer_name, create_widget +from ...utils import strip_org, strip_mch, make_deformer_name, create_widget from ...utils import create_circle_widget, create_sphere_widget, create_line_widget from ...utils import MetarigError, make_mechanism_name, org from ...utils import create_limb_widget, connected_children_names @@ -672,6 +672,13 @@ class Rig: else: paw_parent = None + mch_name = get_bone_name(strip_org(org_bones[0]), 'mch', 'parent_socket') + mch_main_parent = copy_bone(self.obj, org_bones[0], mch_name) + eb[mch_main_parent].length = eb[org_bones[0]].length / 12 + eb[mch_main_parent].parent = eb[bones['parent']] + eb[mch_main_parent].roll = 0.0 + eb[bones['main_parent']].parent = eb[mch_main_parent] + # Create heel ctrl bone heel = get_bone_name(org_bones[2], 'ctrl', 'heel_ik') heel = copy_bone(self.obj, org_bones[2], heel) @@ -776,6 +783,10 @@ class Rig: 'max_y' : 1.05, 'owner_space' : 'LOCAL' }) + make_constraint(self, mch_main_parent, { + 'constraint': 'COPY_ROTATION', + 'subtarget': org_bones[0] + }) pb = self.obj.pose.bones @@ -1119,6 +1130,55 @@ class Rig: var.targets[0].data_path = \ owner.path_from_id() + '[' + '"' + prop + '"' + ']' + @staticmethod + def get_future_names(bones): + + if len(bones) != 4: + return + + names = dict() + + thigh = strip_mch(strip_org(bones[0].name)) + shin = strip_mch(strip_org(bones[1].name)) + foot = strip_mch(strip_org(bones[2].name)) + toe = strip_mch(strip_org(bones[3].name)) + + suffix = '' + if thigh[-2:] == '.L' or thigh[-2:] == '.R': + suffix = thigh[-2:] + thigh = thigh.rstrip(suffix) + shin = shin.rstrip(suffix) + foot = foot.rstrip(suffix) + toe = toe.rstrip(suffix) + + # the following is declared in rig_ui + # controls = ['thigh_ik.R', 'thigh_fk.R', 'shin_fk.R', 'foot_fk.R', 'toe.R', 'foot_heel_ik.R', 'foot_ik.R', + # 'MCH-foot_fk.R', 'thigh_parent.R'] + # tweaks = ['thigh_tweak.R.001', 'shin_tweak.R', 'shin_tweak.R.001'] + # ik_ctrl = ['foot_ik.R', 'MCH-thigh_ik.R', 'MCH-thigh_ik_target.R'] + # fk_ctrl = 'thigh_fk.R' + # parent = 'thigh_parent.R' + # foot_fk = 'foot_fk.R' + # pole = 'thigh_ik_target.R' + + names['controls'] = [thigh + '_ik', thigh + '_fk', shin + '_fk', foot + '_fk', toe, foot + '_heel_ik', + foot + '_ik', make_mechanism_name(foot + '_fk'), thigh + '_parent'] + names['ik_ctrl'] = [foot + '_ik', make_mechanism_name(thigh) + '_ik', make_mechanism_name(thigh) + '_ik_target'] + names['fk_ctrl'] = thigh + '_fk' + suffix + names['parent'] = thigh + '_parent' + suffix + names['foot_fk'] = foot + '_fk' + suffix + names['pole'] = thigh + '_ik_target' + suffix + + names['limb_type'] = 'paw' + + if suffix: + for i, name in enumerate(names['controls']): + names['controls'][i] = name + suffix + for i, name in enumerate(names['ik_ctrl']): + names['ik_ctrl'][i] = name + suffix + + return names + def generate(self): bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones @@ -1242,7 +1302,9 @@ def parameters_ui(layout, params): r = layout.row() r.prop(params, "bbones") - for layer in [ 'fk', 'tweak' ]: + bone_layers = bpy.context.active_pose_bone.bone.layers[:] + + for layer in ['fk', 'tweak']: r = layout.row() r.prop(params, layer + "_extra_layers") r.active = params.tweak_extra_layers @@ -1251,23 +1313,35 @@ def parameters_ui(layout, params): row = col.row(align=True) for i in range(8): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) - for i in range(16,24): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + for i in range(16, 24): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) col = r.column(align=True) row = col.row(align=True) - for i in range(8,16): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + for i in range(8, 16): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) - for i in range(24,32): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + for i in range(24, 32): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) def create_sample(obj): diff --git a/rigify/rigs/limbs/simple_tentacle.py b/rigify/rigs/limbs/simple_tentacle.py index d8ca1bf9..310ed7ab 100644 --- a/rigify/rigs/limbs/simple_tentacle.py +++ b/rigify/rigs/limbs/simple_tentacle.py @@ -249,7 +249,7 @@ def parameters_ui(layout, params): r = layout.row() col = r.column(align=True) row = col.row(align=True) - for i,axis in enumerate( [ 'x', 'y', 'z' ] ): + for i, axis in enumerate(['x', 'y', 'z']): row.prop(params, "copy_rotation_axes", index=i, toggle=True, text=axis) r = layout.row() @@ -259,24 +259,38 @@ def parameters_ui(layout, params): col = r.column(align=True) row = col.row(align=True) - for i in range( 8 ): # Layers 0-7 - row.prop(params, "tweak_layers", index=i, toggle=True, text="") + bone_layers = bpy.context.active_pose_bone.bone.layers[:] - row = col.row(align=True) + for i in range(8): # Layers 0-7 + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, "tweak_layers", index=i, toggle=True, text="", icon=icon) - for i in range( 16, 24 ): # Layers 16-23 - row.prop(params, "tweak_layers", index=i, toggle=True, text="") + row = col.row(align=True) + for i in range(16, 24): # Layers 16-23 + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, "tweak_layers", index=i, toggle=True, text="", icon=icon) + col = r.column(align=True) row = col.row(align=True) - for i in range( 8, 16 ): # Layers 8-15 - row.prop(params, "tweak_layers", index=i, toggle=True, text="") + for i in range(8, 16): # Layers 8-15 + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, "tweak_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) for i in range( 24, 32 ): # Layers 24-31 - row.prop(params, "tweak_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, "tweak_layers", index=i, toggle=True, text="", icon=icon) def create_sample(obj): diff --git a/rigify/rigs/limbs/super_limb.py b/rigify/rigs/limbs/super_limb.py index 8ce98a31..e5670829 100644 --- a/rigify/rigs/limbs/super_limb.py +++ b/rigify/rigs/limbs/super_limb.py @@ -23,6 +23,15 @@ class Rig: return self.limb.generate() + @staticmethod + def get_future_names(bones): + if bones[0].rigify_parameters.limb_type == 'arm': + return armRig.get_future_names(bones) + elif bones[0].rigify_parameters.limb_type == 'leg': + return legRig.get_future_names(bones) + elif bones[0].rigify_parameters.limb_type == 'paw': + return pawRig.get_future_names(bones) + def add_parameters(params): """ Add the parameters of this rig type to the @@ -121,7 +130,9 @@ def parameters_ui(layout, params): r = layout.row() r.prop(params, "bbones") - for layer in [ 'fk', 'tweak' ]: + bone_layers = bpy.context.active_pose_bone.bone.layers[:] + + for layer in ['fk', 'tweak']: r = layout.row() r.prop(params, layer + "_extra_layers") r.active = params.tweak_extra_layers @@ -130,23 +141,35 @@ def parameters_ui(layout, params): row = col.row(align=True) for i in range(8): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) for i in range(16,24): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) col = r.column(align=True) row = col.row(align=True) for i in range(8,16): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) for i in range(24,32): - row.prop(params, layer + "_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, layer + "_layers", index=i, toggle=True, text="", icon=icon) def create_sample(obj): diff --git a/rigify/rigs/limbs/super_palm.py b/rigify/rigs/limbs/super_palm.py index efcb5681..127d9d0c 100644 --- a/rigify/rigs/limbs/super_palm.py +++ b/rigify/rigs/limbs/super_palm.py @@ -308,7 +308,7 @@ def create_sample(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'YXZ' pbone = obj.pose.bones[bones['palm.01']] - pbone.rigify_type = 'palm' + pbone.rigify_type = 'limbs.super_palm' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, True, True) pbone.lock_rotation_w = False diff --git a/rigify/rigs/limbs/ui.py b/rigify/rigs/limbs/ui.py index 7783e06d..f04eb891 100644 --- a/rigify/rigs/limbs/ui.py +++ b/rigify/rigs/limbs/ui.py @@ -26,6 +26,11 @@ if is_selected( controls ): props.hand_ik = controls[4] props.pole = pole props.main_parent = parent + props = layout.operator("rigify.rotation_pole", text="Switch Rotation-Pole") + props.bone_name = controls[1] + props.window = "CURRENT" + props.toggle = True + props.bake = False # BBone rubber hose on each Respective Tweak @@ -76,6 +81,11 @@ if is_selected( controls ): props.footroll = controls[5] props.mfoot_ik = ik_ctrl[2] props.main_parent = parent + props = layout.operator("rigify.rotation_pole", text="Toggle Rotation and Pole") + props.bone_name = controls[1] + props.window = "CURRENT" + props.toggle = True + props.bake = False # BBone rubber hose on each Respective Tweak for t in tweaks: diff --git a/rigify/rigs/misc/__init__.py b/rigify/rigs/misc/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/rigify/rigs/misc/__init__.py +++ /dev/null diff --git a/rigify/rigs/misc/delta.py b/rigify/rigs/misc/delta.py deleted file mode 100644 index 84f3612b..00000000 --- a/rigify/rigs/misc/delta.py +++ /dev/null @@ -1,165 +0,0 @@ -#====================== 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 ======================== - -# <pep8 compliant> - -if False: - # This rig type is disabled due to its obscurity. - # However, some of the code may be useful in the future, so - # I'm leaving it here. - from math import acos - - import bpy - - from ...utils import MetarigError - from ...utils import copy_bone - from ...utils import org_name, make_mechanism_name - - - class Rig: - """ A delta rig. - Creates a setup that will place its child at its position in pose mode, - but will not modifying its child's position in edit mode. - This is a mechanism-only rig (no control or deformation bones). - - """ - def __init__(self, obj, bone, params): - """ Gather and validate data about the rig. - Store any data or references to data that will be needed later on. - In particular, store references to bones that will be needed. - Do NOT change any data in the scene. This is a gathering phase only. - - """ - bb = obj.data.bones - - if bb[bone].children is None: - raise MetarigError("RIGIFY ERROR: bone '%s': rig type requires one child" % org_name(bone.name)) - if bb[bone].use_connect is True: - raise MetarigError("RIGIFY ERROR: bone '%s': rig type cannot be connected to parent" % org_name(bone.name)) - - self.obj = obj - self.org_bones = {"delta": bone, "child": bb[bone].children[0].name} - self.org_names = [org_name(bone), org_name(bb[bone].children[0].name)] - - def generate(self): - """ Generate the rig. - Do NOT modify any of the original bones, except for adding constraints. - The main armature should be selected and active before this is called. - - """ - bpy.ops.object.mode_set(mode='EDIT') - eb = self.obj.data.edit_bones - - org_delta = self.org_bones["delta"] - org_delta_e = eb[self.org_bones["delta"]] - # org_child = self.org_bones["child"] # UNUSED - org_child_e = eb[self.org_bones["child"]] - - # Calculate the matrix for achieving the delta - child_mat = org_delta_e.matrix.invert() * org_child_e.matrix - mat = org_delta_e.matrix * child_mat.invert() - - # Create the delta bones. - delta_e = eb[copy_bone(self.obj, self.org_bones["delta"])] - delta_e.name = make_mechanism_name(self.org_names[0]) - delta = delta_e.name - - # Set the delta to the matrix's transforms - set_mat(self.obj, delta, mat) - - bpy.ops.object.mode_set(mode='OBJECT') - - # Constrain org_delta to delta - con = self.obj.pose.bones[org_delta].constraints.new('COPY_TRANSFORMS') - con.name = "delta" - con.target = self.obj - con.subtarget = delta - - def create_sample(obj): - # generated by rigify.utils.write_metarig - bpy.ops.object.mode_set(mode='EDIT') - arm = obj.data - - bones = {} - - bone = arm.edit_bones.new('delta') - bone.head[:] = 0.0000, -0.1198, 0.1253 - bone.tail[:] = -0.0000, -0.2483, 0.2785 - bone.roll = -0.0000 - bone.use_connect = False - bones['delta'] = bone.name - bone = arm.edit_bones.new('Bone') - bone.head[:] = -0.0000, 0.0000, 0.0000 - bone.tail[:] = -0.0000, 0.0000, 0.2000 - bone.roll = 0.0000 - bone.use_connect = False - bone.parent = arm.edit_bones[bones['delta']] - bones['Bone'] = bone.name - - bpy.ops.object.mode_set(mode='OBJECT') - pbone = obj.pose.bones[bones['delta']] - pbone.rigify_type = 'misc.delta' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone = obj.pose.bones[bones['Bone']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - - bpy.ops.object.mode_set(mode='EDIT') - for bone in arm.edit_bones: - bone.select = False - bone.select_head = False - bone.select_tail = False - for b in bones: - bone = arm.edit_bones[bones[b]] - bone.select = True - bone.select_head = True - bone.select_tail = True - arm.edit_bones.active = bone - - def set_mat(obj, bone_name, matrix): - """ Sets the bone to have the given transform matrix. - """ - a = obj.data.edit_bones[bone_name] - - a.head = (0, 0, 0) - a.tail = (0, 1, 0) - - a.transform(matrix) - - d = acos(a.matrix.to_quaternion().dot(matrix.to_quaternion())) * 2.0 - - roll_1 = a.roll + d - roll_2 = a.roll - d - - a.roll = roll_1 - d1 = a.matrix.to_quaternion().dot(matrix.to_quaternion()) - a.roll = roll_2 - d2 = a.matrix.to_quaternion().dot(matrix.to_quaternion()) - - if d1 > d2: - a.roll = roll_1 - else: - a.roll = roll_2 diff --git a/rigify/rigs/spines/super_spine.py b/rigify/rigs/spines/super_spine.py index a1991afd..c96af461 100644 --- a/rigify/rigs/spines/super_spine.py +++ b/rigify/rigs/spines/super_spine.py @@ -1103,24 +1103,38 @@ def parameters_ui(layout, params): col = r.column(align=True) row = col.row(align=True) + bone_layers = bpy.context.active_pose_bone.bone.layers[:] + for i in range(8): - row.prop(params, "tweak_layers", index=i, toggle=True, text="") + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, "tweak_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) - for i in range(16,24): - row.prop(params, "tweak_layers", index=i, toggle=True, text="") + for i in range(16, 24): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, "tweak_layers", index=i, toggle=True, text="", icon=icon) col = r.column(align=True) row = col.row(align=True) - for i in range(8,16): - row.prop(params, "tweak_layers", index=i, toggle=True, text="") + for i in range(8, 16): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, "tweak_layers", index=i, toggle=True, text="", icon=icon) row = col.row(align=True) - for i in range(24,32): - row.prop(params, "tweak_layers", index=i, toggle=True, text="") + for i in range(24, 32): + icon = "NONE" + if bone_layers[i]: + icon = "LAYER_ACTIVE" + row.prop(params, "tweak_layers", index=i, toggle=True, text="", icon=icon) def create_sample(obj): diff --git a/rigify/rigs/utils.py b/rigify/rigs/utils.py new file mode 100644 index 00000000..c08cb8f9 --- /dev/null +++ b/rigify/rigs/utils.py @@ -0,0 +1,21 @@ +from .limbs.super_limb import Rig as LimbRig +from ..utils import connected_children_names +import re + + +def get_limb_generated_names(rig): + + pbones = rig.pose.bones + names = dict() + + for b in pbones: + super_limb_orgs = [] + if re.match('^ORG', b.name) and b.rigify_type == 'limbs.super_limb': + super_limb_orgs.append(b) + children = connected_children_names(rig, b.name) + for child in children: + if re.match('^ORG', child) or re.match('^MCH', child): + super_limb_orgs.append(pbones[child]) + names[b.name] = LimbRig.get_future_names(super_limb_orgs) + + return names diff --git a/rigify/rot_mode.py b/rigify/rot_mode.py new file mode 100644 index 00000000..22def224 --- /dev/null +++ b/rigify/rot_mode.py @@ -0,0 +1,359 @@ +''' +Quat/Euler Rotation Mode Converter v0.1 + +This script/addon: + - Changes (pose) bone rotation mode + - Converts keyframes from one rotation mode to another + - Creates fcurves/keyframes in target rotation mode + - Deletes previous fcurves/keyframes. + - Converts multiple bones + - Converts multiple Actions + +TO-DO: + - To convert object's rotation mode (alrady done in Mutant Bob script, + but not done in this one. + - To understand "EnumProperty" and write it well. + - Code clean + - ... + +GitHub: https://github.com/MarioMey/rotation_mode_addon/ +BlenderArtist thread: http://blenderartists.org/forum/showthread.php?388197-Quat-Euler-Rotation-Mode-Converter + +Mutant Bob did the "hard code" of this script. Thanks him! +blender.stackexchange.com/questions/40711/how-to-convert-quaternions-keyframes-to-euler-ones-in-several-actions + + +''' + +# bl_info = { +# "name": "Quat/Euler Rotation Mode Converter", +# "author": "Mario Mey / Mutant Bob", +# "version": (0, 1), +# "blender": (2, 76, 0), +# 'location': '', +# "description": "Converts bones rotation mode", +# "warning": "", +# "wiki_url": "", +# "tracker_url": "https://github.com/MarioMey/rotation_mode_addon/", +# "category": "Animation"} + +import bpy + +order_list = ['QUATERNION', 'XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'] + + +class convert(): + def get_or_create_fcurve(self, action, data_path, array_index=-1, group=None): + for fc in action.fcurves: + if fc.data_path == data_path and (array_index < 0 or fc.array_index == array_index): + return fc + + fc = action.fcurves.new(data_path, array_index) + fc.group = group + return fc + + def add_keyframe_quat(self, action, quat, frame, bone_prefix, group): + for i in range(len(quat)): + fc = self.get_or_create_fcurve(action, bone_prefix + "rotation_quaternion", i, group) + pos = len(fc.keyframe_points) + fc.keyframe_points.add(1) + fc.keyframe_points[pos].co = [frame, quat[i]] + fc.update() + + def add_keyframe_euler(self, action, euler, frame, bone_prefix, group): + for i in range(len(euler)): + fc = self.get_or_create_fcurve(action, bone_prefix + "rotation_euler", i, group) + pos = len(fc.keyframe_points) + fc.keyframe_points.add(1) + fc.keyframe_points[pos].co = [frame, euler[i]] + fc.update() + + def frames_matching(self, action, data_path): + frames = set() + for fc in action.fcurves: + if fc.data_path == data_path: + fri = [kp.co[0] for kp in fc.keyframe_points] + frames.update(fri) + return frames + + # Converts only one group/bone in one action - Quat to euler + def group_qe(self, obj, action, bone, bone_prefix, order): + + pose_bone = bone + data_path = bone_prefix + "rotation_quaternion" + frames = self.frames_matching(action, data_path) + group = action.groups[bone.name] + + for fr in frames: + quat = bone.rotation_quaternion.copy() + for fc in action.fcurves: + if fc.data_path == data_path: + quat[fc.array_index] = fc.evaluate(fr) + euler = quat.to_euler(order) + + self.add_keyframe_euler(action, euler, fr, bone_prefix, group) + bone.rotation_mode = order + + # Converts only one group/bone in one action - Euler to Quat + def group_eq(self, obj, action, bone, bone_prefix, order): + + pose_bone = bone + data_path = bone_prefix + "rotation_euler" + frames = self.frames_matching(action, data_path) + group = action.groups[bone.name] + + for fr in frames: + euler = bone.rotation_euler.copy() + for fc in action.fcurves: + if fc.data_path == data_path: + euler[fc.array_index] = fc.evaluate(fr) + quat = euler.to_quaternion() + + self.add_keyframe_quat(action, quat, fr, bone_prefix, group) + bone.rotation_mode = order + + # One Action - One Bone + def one_act_one_bon(self, obj, action, bone, order): + do = False + bone_prefix = '' + + # What kind of conversion + cond1 = order == 'XYZ' + cond2 = order == 'XZY' + cond3 = order == 'YZX' + cond4 = order == 'YXZ' + cond5 = order == 'ZXY' + cond6 = order == 'ZYX' + + order_euler = cond1 or cond2 or cond3 or cond4 or cond5 or cond6 + order_quat = order == 'QUATERNION' + + for fcurve in action.fcurves: + if fcurve.group.name == bone.name: + + # If To-Euler conversion + if order != 'QUATERNION': + if fcurve.data_path.endswith('rotation_quaternion'): + do = True + bone_prefix = fcurve.data_path[:-len('rotation_quaternion')] + break + + # If To-Quat conversion + else: + if fcurve.data_path.endswith('rotation_euler'): + do = True + bone_prefix = fcurve.data_path[:-len('rotation_euler')] + break + + # If To-Euler conversion + if do and order != 'QUATERNION': + # Converts the group/bone from Quat to Euler + self.group_qe(obj, action, bone, bone_prefix, order) + + # Removes quaternion fcurves + for key in action.fcurves: + if key.data_path == 'pose.bones["' + bone.name + '"].rotation_quaternion': + action.fcurves.remove(key) + + # If To-Quat conversion + elif do: + # Converts the group/bone from Euler to Quat + self.group_eq(obj, action, bone, bone_prefix, order) + + # Removes euler fcurves + for key in action.fcurves: + if key.data_path == 'pose.bones["' + bone.name + '"].rotation_euler': + action.fcurves.remove(key) + + # Changes rotation mode to new one + bone.rotation_mode = order + + # One Action, selected bones + def one_act_sel_bon(self, obj, action, pose_bones, order): + for bone in pose_bones: + self.one_act_one_bon(obj, action, bone, order) + + # One action, all Bones (in Action) + def one_act_every_bon(self, obj, action, order): + + # Collects pose_bones that are in the action + pose_bones = set() + # Checks all fcurves + for fcurve in action.fcurves: + # Look for the ones that has rotation_euler + if order == 'QUATERNION': + if fcurve.data_path.endswith('rotation_euler'): + # If the bone from action really exists + if fcurve.group.name in obj.pose.bones: + if obj.pose.bones[fcurve.group.name] not in pose_bones: + pose_bones.add(obj.pose.bones[fcurve.group.name]) + else: + print(fcurve.group.name, 'does not exist in Armature. Fcurve-group is not affected') + + # Look for the ones that has rotation_quaternion + else: + if fcurve.data_path.endswith('rotation_quaternion'): + # If the bone from action really exists + if fcurve.group.name in obj.pose.bones: + if obj.pose.bones[fcurve.group.name] not in pose_bones: + pose_bones.add(obj.pose.bones[fcurve.group.name]) + else: + print(fcurve.group.name, 'does not exist in Armature. Fcurve-group is not affected') + + # Convert current action and pose_bones that are in each action + for bone in pose_bones: + self.one_act_one_bon(obj, action, bone, order) + + # All Actions, selected bones + def all_act_sel_bon(self, obj, pose_bones, order): + for action in bpy.data.actions: + for bone in pose_bones: + self.one_act_one_bon(obj, action, bone, order) + + # All actions, All Bones (in each Action) + def all_act_every_bon(self, obj, order): + for action in bpy.data.actions: + self.one_act_every_bon(obj, action, order) + + +convert = convert() + + +# def initSceneProperties(scn): +# +# bpy.types.Scene.order_list = bpy.props.EnumProperty( +# items = [('QUATERNION', 'QUATERNION', 'QUATERNION' ), +# ('XYZ', 'XYZ', 'XYZ' ), +# ('XZY', 'XZY', 'XZY' ), +# ('YXZ', 'YXZ', 'YXZ' ), +# ('YZX', 'YZX', 'YZX' ), +# ('ZXY', 'ZXY', 'ZXY' ), +# ('ZYX', 'ZYX', 'ZYX' ) ], +# name = "Order", +# description = "The target rotation mode") +# +# scn['order_list'] = 0 +# +# return +# +# initSceneProperties(bpy.context.scene) + + +# GUI (Panel) +# +class ToolsPanel(bpy.types.Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'TOOLS' + bl_category = "Tools" + bl_context = "posemode" + bl_label = 'Rigify Quat/Euler Converter' + + # draw the gui + def draw(self, context): + layout = self.layout + scn = context.scene + # ~ toolsettings = context.tool_settings + + col = layout.column(align=True) + row = col.row(align=True) + id_store = context.window_manager + + layout.prop(scn, 'order_list') + + if id_store.rigify_convert_only_selected: + icon = 'OUTLINER_DATA_ARMATURE' + else: + icon = 'ARMATURE_DATA' + + layout.prop(id_store, 'rigify_convert_only_selected', toggle=True, icon=icon) + + col = layout.column(align=True) + row = col.row(align=True) + + row.operator('rigify_quat2eu.current', icon='ACTION') + row = col.row(align=True) + row.operator('rigify_quat2eu.all', icon='NLA') + + +class CONVERT_OT_quat2eu_current_action(bpy.types.Operator): + bl_label = 'Convert Current Action' + bl_idname = 'rigify_quat2eu.current' + bl_description = 'Converts bones in current Action' + bl_options = {'REGISTER', 'UNDO'} + + # on mouse up: + def invoke(self, context, event): + self.execute(context) + return {'FINISHED'} + + def execute(op, context): + obj = bpy.context.active_object + pose_bones = bpy.context.selected_pose_bones + action = obj.animation_data.action + order = order_list[bpy.context.scene['order_list']] + id_store = context.window_manager + + if id_store.rigify_convert_only_selected: + convert.one_act_sel_bon(obj, action, pose_bones, order) + else: + convert.one_act_every_bon(obj, action, order) + + return {'FINISHED'} + + +class CONVERT_OT_quat2eu_all_actions(bpy.types.Operator): + bl_label = 'Convert All Actions' + bl_idname = 'rigify_quat2eu.all' + bl_description = 'Converts bones in every Action' + bl_options = {'REGISTER', 'UNDO'} + + # on mouse up: + def invoke(self, context, event): + self.execute(context) + return {'FINISHED'} + + def execute(op, context): + obj = bpy.context.active_object + pose_bones = bpy.context.selected_pose_bones + order = order_list[bpy.context.scene['order_list']] + id_store = context.window_manager + + if id_store.rigify_convert_only_selected: + convert.all_act_sel_bon(obj, pose_bones, order) + else: + convert.all_act_every_bon(obj, order) + + return {'FINISHED'} + + +def register(): + IDStore = bpy.types.WindowManager + + items = [('QUATERNION', 'QUATERNION', 'QUATERNION'), + ('XYZ', 'XYZ', 'XYZ'), + ('XZY', 'XZY', 'XZY'), + ('YXZ', 'YXZ', 'YXZ'), + ('YZX', 'YZX', 'YZX'), + ('ZXY', 'ZXY', 'ZXY'), + ('ZYX', 'ZYX', 'ZYX')] + + bpy.types.Scene.order_list = bpy.props.EnumProperty(items=items, name='Convert to', + description="The target rotation mode", default='QUATERNION') + + IDStore.rigify_convert_only_selected = bpy.props.BoolProperty( + name="Convert Only Selected", description="Convert selected bones only", default=True) + + bpy.utils.register_class(ToolsPanel) + bpy.utils.register_class(CONVERT_OT_quat2eu_current_action) + bpy.utils.register_class(CONVERT_OT_quat2eu_all_actions) + +def unregister(): + IDStore = bpy.types.WindowManager + + bpy.utils.unregister_class(ToolsPanel) + bpy.utils.unregister_class(CONVERT_OT_quat2eu_current_action) + bpy.utils.unregister_class(CONVERT_OT_quat2eu_all_actions) + + del IDStore.rigify_convert_only_selected + +# bpy.utils.register_module(__name__) diff --git a/rigify/ui.py b/rigify/ui.py index b35bda77..5850e23e 100644 --- a/rigify/ui.py +++ b/rigify/ui.py @@ -26,8 +26,12 @@ from .utils import get_rig_type, MetarigError from .utils import write_metarig, write_widget from .utils import unique_name from .utils import upgradeMetarigTypes, outdated_types +from .utils import get_keyed_frames, bones_in_frame +from .utils import overwrite_prop_animation +from .rigs.utils import get_limb_generated_names from . import rig_lists from . import generate +from . import rot_mode class DATA_PT_rigify_buttons(bpy.types.Panel): @@ -38,7 +42,7 @@ class DATA_PT_rigify_buttons(bpy.types.Panel): @classmethod def poll(cls, context): - return context.object.type == 'ARMATURE' + return context.object.type == 'ARMATURE' and context.active_object.data.get("rig_id") is None def draw(self, context): C = context @@ -51,6 +55,7 @@ class DATA_PT_rigify_buttons(bpy.types.Panel): WARNING = "Warning: Some features may change after generation" show_warning = False show_update_metarig = False + show_not_updatable = False check_props = ['IK_follow', 'root/parent', 'FK_limb_follow', 'IK_Stretch'] @@ -63,25 +68,50 @@ class DATA_PT_rigify_buttons(bpy.types.Panel): break for b in obj.pose.bones: if b.rigify_type in outdated_types.keys(): - show_update_metarig = True - break + if outdated_types[b.rigify_type]: + show_update_metarig = True + else: + show_update_metarig = False + show_not_updatable = True + break if show_warning: layout.label(text=WARNING, icon='ERROR') - layout.operator("pose.rigify_generate", text="Generate Rig", icon='POSE_HLT') + if show_not_updatable: + layout.label(text="WARNING: This metarig contains deprecated rigify rig-types and cannot be upgraded automatically.", icon='ERROR') + layout.label(text="If you want to use it anyway try enabling the legacy mode before generating again.") + + layout.operator("pose.rigify_switch_to_legacy", text="Switch to Legacy") + + enable_generate_and_advanced = not (show_not_updatable or show_update_metarig) + + if show_update_metarig: + + layout.label(text="This metarig contains old rig-types that can be automatically upgraded to benefit of rigify's new features.", icon='ERROR') + layout.label(text= "To use it as-is you need to enable legacy mode.",) + layout.operator("pose.rigify_upgrade_types", text="Upgrade Metarig") + + row = layout.row() + row.operator("pose.rigify_generate", text="Generate Rig", icon='POSE_HLT') + row.enabled = enable_generate_and_advanced + if id_store.rigify_advanced_generation: icon = 'UNLOCKED' else: icon = 'LOCKED' - layout.prop(id_store, "rigify_advanced_generation", toggle=True, icon=icon) + + col = layout.column() + col.enabled = enable_generate_and_advanced + row = col.row() + row.prop(id_store, "rigify_advanced_generation", toggle=True, icon=icon) if id_store.rigify_advanced_generation: - row = layout.row(align=True) + row = col.row(align=True) row.prop(id_store, "rigify_generate_mode", expand=True) - main_row = layout.row(align=True).split(percentage=0.3) + main_row = col.row(align=True).split(percentage=0.3) col1 = main_row.column() col2 = main_row.column() col1.label(text="Rig Name") @@ -119,16 +149,11 @@ class DATA_PT_rigify_buttons(bpy.types.Panel): row.prop_search(id_store, "rigify_rig_ui", id_store, "rigify_rig_uis", text="", icon='TEXT') row.enabled = (id_store.rigify_generate_mode == "overwrite") - row = layout.row() + row = col.row() row.prop(id_store, "rigify_force_widget_update") if id_store.rigify_generate_mode == 'new': row.enabled = False - if show_update_metarig: - layout.label(text="Some bones have old legacy rigify_type. Click to upgrade", icon='ERROR') - layout.operator("pose.rigify_upgrade_types", text="Upgrade Metarig") - - elif obj.mode == 'EDIT': # Build types list collection_name = str(id_store.rigify_collection).replace(" ", "") @@ -165,7 +190,7 @@ class DATA_PT_rigify_layer_names(bpy.types.Panel): @classmethod def poll(cls, context): - return context.object.type == 'ARMATURE' + return context.object.type == 'ARMATURE' and context.active_object.data.get("rig_id") is None def draw(self, context): layout = self.layout @@ -500,7 +525,7 @@ class DATA_PT_rigify_bone_groups(bpy.types.Panel): @classmethod def poll(cls, context): - return context.object.type == 'ARMATURE' + return context.object.type == 'ARMATURE' and context.active_object.data.get("rig_id") is None def draw(self, context): obj = context.object @@ -546,7 +571,7 @@ class BONE_PT_rigify_buttons(bpy.types.Panel): return False obj = context.object if obj: - return obj.mode == 'POSE' + return obj.mode == 'POSE' and context.active_object.data.get("rig_id") is None return False def draw(self, context): @@ -606,6 +631,7 @@ class BONE_PT_rigify_buttons(bpy.types.Panel): class VIEW3D_PT_tools_rigify_dev(bpy.types.Panel): bl_label = "Rigify Dev Tools" bl_category = 'Tools' + bl_context = "armature_edit" bl_space_type = 'VIEW_3D' bl_region_type = 'TOOLS' @@ -623,6 +649,57 @@ class VIEW3D_PT_tools_rigify_dev(bpy.types.Panel): r.operator("mesh.rigify_encode_mesh_widget", text="Encode Mesh Widget to Python") +class VIEW3D_PT_rigify_animation_tools(bpy.types.Panel): + bl_label = "Rigify Animation Tools" + bl_category = 'Tools' + bl_context = "posemode" + bl_space_type = 'VIEW_3D' + bl_region_type = 'TOOLS' + + @classmethod + def poll(cls, context): + return context.object.type == 'ARMATURE' and context.active_object.data.get("rig_id") is not None + + def draw(self, context): + obj = context.active_object + id_store = context.window_manager + if obj is not None: + row = self.layout.row() + + if id_store.rigify_transfer_only_selected: + icon = 'OUTLINER_DATA_ARMATURE' + else: + icon = 'ARMATURE_DATA' + + row.prop(id_store, 'rigify_transfer_only_selected', toggle=True, icon=icon) + + row = self.layout.row(align=True) + row.operator("rigify.ik2fk", text='IK2FK Pose', icon='SNAP_ON') + row.operator("rigify.fk2ik", text='FK2IK Pose', icon='SNAP_ON') + + row = self.layout.row(align=True) + row.operator("rigify.transfer_fk_to_ik", text='IK2FK Action', icon='ACTION_TWEAK') + row.operator("rigify.transfer_ik_to_fk", text='FK2IK Action', icon='ACTION_TWEAK') + + row = self.layout.row(align=True) + row.operator("rigify.clear_animation", text="Clear IK Action", icon='CANCEL').type = "IK" + row.operator("rigify.clear_animation", text="Clear FK Action", icon='CANCEL').type = "FK" + + row = self.layout.row(align=True) + op = row.operator("rigify.rotation_pole", icon='FORCE_HARMONIC', text='Switch to pole') + op.value = True + op.toggle = False + op.bake = True + op = row.operator("rigify.rotation_pole", icon='FORCE_MAGNETIC', text='Switch to rotation') + op.value = False + op.toggle = False + op.bake = True + row = self.layout.row(align=True) + row.prop(id_store, 'rigify_transfer_start_frame') + row.prop(id_store, 'rigify_transfer_end_frame') + row.operator("rigify.get_frame_range", icon='TIME', text='') + + def rigify_report_exception(operator, exception): import traceback import sys @@ -701,6 +778,22 @@ class UpgradeMetarigTypes(bpy.types.Operator): return {'FINISHED'} +class SwitchToLegacy(bpy.types.Operator): + """Switch to Legacy mode""" + + bl_idname = "pose.rigify_switch_to_legacy" + bl_label = "Legacy Mode will disable Rigify new features" + bl_description = 'Switches Rigify to Legacy Mode' + bl_options = {'UNDO'} + + def invoke(self, context, event): + return context.window_manager.invoke_confirm(self, event) + + def execute(self, context): + bpy.context.user_preferences.addons['rigify'].preferences.legacy_mode = True + return {'FINISHED'} + + class Sample(bpy.types.Operator): """Create a sample metarig to be modified before generating """ \ """the final rig""" @@ -815,9 +908,411 @@ class EncodeWidget(bpy.types.Operator): return {'FINISHED'} -#menu_func = (lambda self, context: self.layout.menu("INFO_MT_armature_metarig_add", icon='OUTLINER_OB_ARMATURE')) +class OBJECT_OT_GetFrameRange(bpy.types.Operator): + """Get start and end frame range""" + bl_idname = "rigify.get_frame_range" + bl_label = "Get Frame Range" + + def execute(self, context): + scn = context.scene + id_store = context.window_manager + + id_store.rigify_transfer_start_frame = scn.frame_start + id_store.rigify_transfer_end_frame = scn.frame_end + + return {'FINISHED'} + + +def FktoIk(rig, window='ALL'): + + scn = bpy.context.scene + id_store = bpy.context.window_manager + + rig_id = rig.data['rig_id'] + leg_ik2fk = eval('bpy.ops.pose.rigify_leg_ik2fk_' + rig_id) + arm_ik2fk = eval('bpy.ops.pose.rigify_arm_ik2fk_' + rig_id) + limb_generated_names = get_limb_generated_names(rig) + + if window == 'ALL': + frames = get_keyed_frames(rig) + frames = [f for f in frames if f in range(id_store.rigify_transfer_start_frame, id_store.rigify_transfer_end_frame+1)] + elif window == 'CURRENT': + frames = [scn.frame_current] + else: + frames = [scn.frame_current] + + if not id_store.rigify_transfer_only_selected: + pbones = rig.pose.bones + bpy.ops.pose.select_all(action='DESELECT') + else: + pbones = bpy.context.selected_pose_bones + bpy.ops.pose.select_all(action='DESELECT') + + for b in pbones: + for group in limb_generated_names: + if b.name in limb_generated_names[group].values() or b.name in limb_generated_names[group]['controls']\ + or b.name in limb_generated_names[group]['ik_ctrl']: + names = limb_generated_names[group] + if names['limb_type'] == 'arm': + func = arm_ik2fk + controls = names['controls'] + ik_ctrl = names['ik_ctrl'] + fk_ctrl = names['fk_ctrl'] + parent = names['parent'] + pole = names['pole'] + rig.pose.bones[controls[0]].bone.select = True + rig.pose.bones[controls[4]].bone.select = True + rig.pose.bones[pole].bone.select = True + rig.pose.bones[parent].bone.select = True + kwargs = {'uarm_fk': controls[1], 'farm_fk': controls[2], 'hand_fk': controls[3], + 'uarm_ik': controls[0], 'farm_ik': ik_ctrl[1], 'hand_ik': controls[4], + 'pole': pole, 'main_parent': parent} + args = (controls[0], controls[1], controls[2], controls[3], + controls[4], pole, parent) + else: + func = leg_ik2fk + controls = names['controls'] + ik_ctrl = names['ik_ctrl'] + fk_ctrl = names['fk_ctrl'] + parent = names['parent'] + pole = names['pole'] + rig.pose.bones[controls[0]].bone.select = True + rig.pose.bones[controls[6]].bone.select = True + rig.pose.bones[controls[5]].bone.select = True + rig.pose.bones[pole].bone.select = True + rig.pose.bones[parent].bone.select = True + kwargs = {'thigh_fk': controls[1], 'shin_fk': controls[2], 'foot_fk': controls[3], + 'mfoot_fk': controls[7], 'thigh_ik': controls[0], 'shin_ik': ik_ctrl[1], + 'foot_ik': controls[6], 'pole': pole, 'footroll': controls[5], 'mfoot_ik': ik_ctrl[2], + 'main_parent': parent} + args = (controls[0], controls[1], controls[2], controls[3], + controls[6], controls[5], pole, parent) + + for f in frames: + if not bones_in_frame(f, rig, *args): + continue + scn.frame_set(f) + func(**kwargs) + bpy.ops.anim.keyframe_insert_menu(type='BUILTIN_KSI_VisualLocRot') + bpy.ops.anim.keyframe_insert_menu(type='Scaling') + + bpy.ops.pose.select_all(action='DESELECT') + limb_generated_names.pop(group) + break + + +def IktoFk(rig, window='ALL'): + + scn = bpy.context.scene + id_store = bpy.context.window_manager + + rig_id = rig.data['rig_id'] + leg_fk2ik = eval('bpy.ops.pose.rigify_leg_fk2ik_' + rig_id) + arm_fk2ik = eval('bpy.ops.pose.rigify_arm_fk2ik_' + rig_id) + limb_generated_names = get_limb_generated_names(rig) + + if window == 'ALL': + frames = get_keyed_frames(rig) + frames = [f for f in frames if f in range(id_store.rigify_transfer_start_frame, id_store.rigify_transfer_end_frame+1)] + elif window == 'CURRENT': + frames = [scn.frame_current] + else: + frames = [scn.frame_current] + + if not id_store.rigify_transfer_only_selected: + bpy.ops.pose.select_all(action='DESELECT') + pbones = rig.pose.bones + else: + pbones = bpy.context.selected_pose_bones + bpy.ops.pose.select_all(action='DESELECT') + + for b in pbones: + for group in limb_generated_names: + if b.name in limb_generated_names[group].values() or b.name in limb_generated_names[group]['controls']\ + or b.name in limb_generated_names[group]['ik_ctrl']: + names = limb_generated_names[group] + if names['limb_type'] == 'arm': + func = arm_fk2ik + controls = names['controls'] + ik_ctrl = names['ik_ctrl'] + fk_ctrl = names['fk_ctrl'] + parent = names['parent'] + pole = names['pole'] + rig.pose.bones[controls[1]].bone.select = True + rig.pose.bones[controls[2]].bone.select = True + rig.pose.bones[controls[3]].bone.select = True + kwargs = {'uarm_fk': controls[1], 'farm_fk': controls[2], 'hand_fk': controls[3], + 'uarm_ik': controls[0], 'farm_ik': ik_ctrl[1], + 'hand_ik': controls[4]} + args = (controls[0], controls[1], controls[2], controls[3], + controls[4], pole, parent) + else: + func = leg_fk2ik + controls = names['controls'] + ik_ctrl = names['ik_ctrl'] + fk_ctrl = names['fk_ctrl'] + parent = names['parent'] + pole = names['pole'] + rig.pose.bones[controls[1]].bone.select = True + rig.pose.bones[controls[2]].bone.select = True + rig.pose.bones[controls[3]].bone.select = True + kwargs = {'thigh_fk': controls[1], 'shin_fk': controls[2], 'foot_fk': controls[3], + 'mfoot_fk': controls[7], 'thigh_ik': controls[0], 'shin_ik': ik_ctrl[1], + 'foot_ik': ik_ctrl[2], 'mfoot_ik': ik_ctrl[2]} + args = (controls[0], controls[1], controls[2], controls[3], + controls[6], controls[5], pole, parent) + + for f in frames: + if not bones_in_frame(f, rig, *args): + continue + scn.frame_set(f) + func(**kwargs) + bpy.ops.anim.keyframe_insert_menu(type='BUILTIN_KSI_VisualLocRot') + bpy.ops.anim.keyframe_insert_menu(type='Scaling') + + bpy.ops.pose.select_all(action='DESELECT') + limb_generated_names.pop(group) + break + + +def clearAnimation(act, type, names): + + bones = [] + for group in names: + if names[group]['limb_type'] == 'arm': + if type == 'IK': + bones.extend([names[group]['controls'][0], names[group]['controls'][4]]) + elif type == 'FK': + bones.extend([names[group]['controls'][1], names[group]['controls'][2], names[group]['controls'][3]]) + else: + if type == 'IK': + bones.extend([names[group]['controls'][0], names[group]['controls'][6], names[group]['controls'][5], + names[group]['controls'][4]]) + elif type == 'FK': + bones.extend([names[group]['controls'][1], names[group]['controls'][2], names[group]['controls'][3], + names[group]['controls'][4]]) + FCurves = [] + for fcu in act.fcurves: + words = fcu.data_path.split('"') + if (words[0] == "pose.bones[" and + words[1] in bones): + FCurves.append(fcu) + + if FCurves == []: + return + + for fcu in FCurves: + act.fcurves.remove(fcu) + + # Put cleared bones back to rest pose + bpy.ops.pose.loc_clear() + bpy.ops.pose.rot_clear() + bpy.ops.pose.scale_clear() + + # updateView3D() + + +def rotPoleToggle(rig, window='ALL', value=False, toggle=False, bake=False): + + scn = bpy.context.scene + id_store = bpy.context.window_manager + + rig_id = rig.data['rig_id'] + leg_fk2ik = eval('bpy.ops.pose.rigify_leg_fk2ik_' + rig_id) + arm_fk2ik = eval('bpy.ops.pose.rigify_arm_fk2ik_' + rig_id) + leg_ik2fk = eval('bpy.ops.pose.rigify_leg_ik2fk_' + rig_id) + arm_ik2fk = eval('bpy.ops.pose.rigify_arm_ik2fk_' + rig_id) + limb_generated_names = get_limb_generated_names(rig) + + if window == 'ALL': + frames = get_keyed_frames(rig) + frames = [f for f in frames if f in range(id_store.rigify_transfer_start_frame, id_store.rigify_transfer_end_frame+1)] + elif window == 'CURRENT': + frames = [scn.frame_current] + else: + frames = [scn.frame_current] + + if not id_store.rigify_transfer_only_selected: + bpy.ops.pose.select_all(action='DESELECT') + pbones = rig.pose.bones + else: + pbones = bpy.context.selected_pose_bones + bpy.ops.pose.select_all(action='DESELECT') + + for b in pbones: + for group in limb_generated_names: + names = limb_generated_names[group] + + if toggle: + new_pole_vector_value = not rig.pose.bones[names['parent']]['pole_vector'] + else: + new_pole_vector_value = value + + if b.name in names.values() or b.name in names['controls'] or b.name in names['ik_ctrl']: + if names['limb_type'] == 'arm': + func1 = arm_fk2ik + func2 = arm_ik2fk + controls = names['controls'] + ik_ctrl = names['ik_ctrl'] + fk_ctrl = names['fk_ctrl'] + parent = names['parent'] + pole = names['pole'] + rig.pose.bones[controls[0]].bone.select = not new_pole_vector_value + rig.pose.bones[controls[4]].bone.select = not new_pole_vector_value + rig.pose.bones[parent].bone.select = not new_pole_vector_value + rig.pose.bones[pole].bone.select = new_pole_vector_value + + kwargs1 = {'uarm_fk': controls[1], 'farm_fk': controls[2], 'hand_fk': controls[3], + 'uarm_ik': controls[0], 'farm_ik': ik_ctrl[1], + 'hand_ik': controls[4]} + kwargs2 = {'uarm_fk': controls[1], 'farm_fk': controls[2], 'hand_fk': controls[3], + 'uarm_ik': controls[0], 'farm_ik': ik_ctrl[1], 'hand_ik': controls[4], + 'pole': pole, 'main_parent': parent} + args = (controls[0], controls[4], pole, parent) + else: + func1 = leg_fk2ik + func2 = leg_ik2fk + controls = names['controls'] + ik_ctrl = names['ik_ctrl'] + fk_ctrl = names['fk_ctrl'] + parent = names['parent'] + pole = names['pole'] + rig.pose.bones[controls[0]].bone.select = not new_pole_vector_value + rig.pose.bones[controls[6]].bone.select = not new_pole_vector_value + rig.pose.bones[controls[5]].bone.select = not new_pole_vector_value + rig.pose.bones[parent].bone.select = not new_pole_vector_value + rig.pose.bones[pole].bone.select = new_pole_vector_value + + kwargs1 = {'thigh_fk': controls[1], 'shin_fk': controls[2], 'foot_fk': controls[3], + 'mfoot_fk': controls[7], 'thigh_ik': controls[0], 'shin_ik': ik_ctrl[1], + 'foot_ik': ik_ctrl[2], 'mfoot_ik': ik_ctrl[2]} + kwargs2 = {'thigh_fk': controls[1], 'shin_fk': controls[2], 'foot_fk': controls[3], + 'mfoot_fk': controls[7], 'thigh_ik': controls[0], 'shin_ik': ik_ctrl[1], + 'foot_ik': controls[6], 'pole': pole, 'footroll': controls[5], 'mfoot_ik': ik_ctrl[2], + 'main_parent': parent} + args = (controls[0], controls[6], controls[5], pole, parent) + + for f in frames: + if not bones_in_frame(f, rig, *args): + continue + scn.frame_set(f) + func1(**kwargs1) + rig.pose.bones[names['parent']]['pole_vector'] = new_pole_vector_value + func2(**kwargs2) + if bake: + bpy.ops.anim.keyframe_insert_menu(type='BUILTIN_KSI_VisualLocRot') + bpy.ops.anim.keyframe_insert_menu(type='Scaling') + overwrite_prop_animation(rig, rig.pose.bones[parent], 'pole_vector', new_pole_vector_value, [f]) + + bpy.ops.pose.select_all(action='DESELECT') + limb_generated_names.pop(group) + break + scn.frame_set(0) + + +class OBJECT_OT_IK2FK(bpy.types.Operator): + """ Snaps IK limb on FK limb at current frame""" + bl_idname = "rigify.ik2fk" + bl_label = "IK2FK" + bl_description = "Snaps IK limb on FK" + + def execute(self,context): + rig = context.object + id_store = context.window_manager + + FktoIk(rig, window='CURRENT') + + return {'FINISHED'} + + +class OBJECT_OT_FK2IK(bpy.types.Operator): + """ Snaps FK limb on IK limb at current frame""" + bl_idname = "rigify.fk2ik" + bl_label = "FK2IK" + bl_description = "Snaps FK limb on IK" + + def execute(self,context): + rig = context.object + + IktoFk(rig, window='CURRENT') + + return {'FINISHED'} + + +class OBJECT_OT_TransferFKtoIK(bpy.types.Operator): + """Transfers FK animation to IK""" + bl_idname = "rigify.transfer_fk_to_ik" + bl_label = "Transfer FK anim to IK" + bl_description = "Transfer FK animation to IK bones" + + def execute(self, context): + rig = context.object + id_store = context.window_manager + + FktoIk(rig) + + return {'FINISHED'} + + +class OBJECT_OT_TransferIKtoFK(bpy.types.Operator): + """Transfers FK animation to IK""" + bl_idname = "rigify.transfer_ik_to_fk" + bl_label = "Transfer IK anim to FK" + bl_description = "Transfer IK animation to FK bones" + + def execute(self, context): + rig = context.object + + IktoFk(rig) + + return {'FINISHED'} + + +class OBJECT_OT_ClearAnimation(bpy.types.Operator): + bl_idname = "rigify.clear_animation" + bl_label = "Clear Animation" + bl_description = "Clear Animation For FK or IK Bones" + type = StringProperty() + + def execute(self, context): + + use_global_undo = context.user_preferences.edit.use_global_undo + context.user_preferences.edit.use_global_undo = False + try: + rig = context.object + scn = context.scene + if not rig.animation_data: + return {'FINISHED'} + act = rig.animation_data.action + if not act: + return {'FINISHED'} + + clearAnimation(act, self.type, names=get_limb_generated_names(rig)) + finally: + context.user_preferences.edit.use_global_undo = use_global_undo + return {'FINISHED'} + + +class OBJECT_OT_Rot2Pole(bpy.types.Operator): + bl_idname = "rigify.rotation_pole" + bl_label = "Rotation - Pole toggle" + bl_description = "Toggles IK chain between rotation and pole target" + bone_name = bpy.props.StringProperty(default='') + window = bpy.props.StringProperty(default='ALL') + toggle = bpy.props.BoolProperty(default=True) + value = bpy.props.BoolProperty(default=True) + bake = bpy.props.BoolProperty(default=True) + + def execute(self, context): + rig = context.object + + if self.bone_name: + bpy.ops.pose.select_all(action='DESELECT') + rig.pose.bones[self.bone_name].bone.select = True + + rotPoleToggle(rig, window=self.window, toggle=self.toggle, value=self.value, bake=self.bake) + return {'FINISHED'} -#from bl_ui import space_info # ensure the menu is loaded first def register(): @@ -834,15 +1329,25 @@ def register(): bpy.utils.register_class(DATA_PT_rigify_layer_names) bpy.utils.register_class(DATA_PT_rigify_buttons) bpy.utils.register_class(BONE_PT_rigify_buttons) + bpy.utils.register_class(VIEW3D_PT_rigify_animation_tools) bpy.utils.register_class(VIEW3D_PT_tools_rigify_dev) bpy.utils.register_class(LayerInit) bpy.utils.register_class(Generate) bpy.utils.register_class(UpgradeMetarigTypes) + bpy.utils.register_class(SwitchToLegacy) bpy.utils.register_class(Sample) bpy.utils.register_class(EncodeMetarig) bpy.utils.register_class(EncodeMetarigSample) bpy.utils.register_class(EncodeWidget) - #space_info.INFO_MT_armature_add.append(ui.menu_func) + bpy.utils.register_class(OBJECT_OT_GetFrameRange) + bpy.utils.register_class(OBJECT_OT_FK2IK) + bpy.utils.register_class(OBJECT_OT_IK2FK) + bpy.utils.register_class(OBJECT_OT_TransferFKtoIK) + bpy.utils.register_class(OBJECT_OT_TransferIKtoFK) + bpy.utils.register_class(OBJECT_OT_ClearAnimation) + bpy.utils.register_class(OBJECT_OT_Rot2Pole) + + rot_mode.register() def unregister(): @@ -860,11 +1365,23 @@ def unregister(): bpy.utils.unregister_class(DATA_PT_rigify_layer_names) bpy.utils.unregister_class(DATA_PT_rigify_buttons) bpy.utils.unregister_class(BONE_PT_rigify_buttons) + bpy.utils.unregister_class(VIEW3D_PT_rigify_animation_tools) bpy.utils.unregister_class(VIEW3D_PT_tools_rigify_dev) bpy.utils.unregister_class(LayerInit) bpy.utils.unregister_class(Generate) bpy.utils.unregister_class(UpgradeMetarigTypes) + bpy.utils.unregister_class(SwitchToLegacy) bpy.utils.unregister_class(Sample) bpy.utils.unregister_class(EncodeMetarig) bpy.utils.unregister_class(EncodeMetarigSample) bpy.utils.unregister_class(EncodeWidget) + bpy.utils.unregister_class(OBJECT_OT_GetFrameRange) + bpy.utils.unregister_class(OBJECT_OT_FK2IK) + bpy.utils.unregister_class(OBJECT_OT_IK2FK) + bpy.utils.unregister_class(OBJECT_OT_TransferFKtoIK) + bpy.utils.unregister_class(OBJECT_OT_TransferIKtoFK) + bpy.utils.unregister_class(OBJECT_OT_ClearAnimation) + bpy.utils.unregister_class(OBJECT_OT_Rot2Pole) + + rot_mode.unregister() + diff --git a/rigify/utils.py b/rigify/utils.py index 0b17a390..dd324962 100644 --- a/rigify/utils.py +++ b/rigify/utils.py @@ -47,13 +47,22 @@ outdated_types = {"pitchipoy.limbs.super_limb": "limbs.super_limb", "pitchipoy.limbs.super_leg": "limbs.super_limb", "pitchipoy.limbs.super_front_paw": "limbs.super_limb", "pitchipoy.limbs.super_rear_paw": "limbs.super_limb", + "pitchipoy.limbs.super_finger": "limbs.super_finger", "pitchipoy.super_torso_turbo": "spines.super_spine", "pitchipoy.simple_tentacle": "limbs.simple_tentacle", "pitchipoy.super_face": "faces.super_face", "pitchipoy.super_palm": "limbs.super_palm", "pitchipoy.super_copy": "basic.super_copy", + "pitchipoy.tentacle": "", "palm": "limbs.super_palm", - "basic.copy": "basic.super_copy"} + "basic.copy": "basic.super_copy", + "biped.arm": "", + "biped.leg": "", + "finger": "", + "neck_short": "", + "misc.delta": "", + "spine": "" + } #======================================================================= # Error handling @@ -107,6 +116,14 @@ def strip_org(name): org_name = strip_org +def strip_mch(name): + """ Returns the name with ORG_PREFIX stripped from it. + """ + if name.startswith(MCH_PREFIX): + return name[len(MCH_PREFIX):] + else: + return name + def org(name): """ Prepends the ORG_PREFIX to a name if it doesn't already have it, and returns it. @@ -160,9 +177,18 @@ def upgradeMetarigTypes(metarig, revert=False): rig_defs = outdated_types for bone in metarig.pose.bones: - rg_type = bone.rigify_type - if rg_type in rig_defs: - bone.rigify_type = rig_defs[rg_type] + rig_type = bone.rigify_type + if rig_type in rig_defs: + bone.rigify_type = rig_defs[rig_type] + if 'leg' in rig_type: + bone.rigfy_parameters.limb_type = 'leg' + if 'arm' in rig_type: + bone.rigfy_parameters.limb_type = 'arm' + if 'paw' in rig_type: + bone.rigfy_parameters.limb_type = 'paw' + if rig_type == "basic.copy": + bone.rigify_parameters.make_widget = False + #======================= @@ -1171,3 +1197,68 @@ def gamma_correct(color): for i, component in enumerate(color): corrected_color[i] = linsrgb_to_srgb(color[i]) return corrected_color + + +#============================================= +# Keyframing functions +#============================================= + + +def get_keyed_frames(rig): + frames = [] + if rig.animation_data: + if rig.animation_data.action: + fcus = rig.animation_data.action.fcurves + for fc in fcus: + for kp in fc.keyframe_points: + if kp.co[0] not in frames: + frames.append(kp.co[0]) + + frames.sort() + + return frames + + +def bones_in_frame(f, rig, *args): + """ + True if one of the bones listed in args is animated at frame f + :param f: the frame + :param rig: the rig + :param args: bone names + :return: + """ + + if rig.animation_data and rig.animation_data.action: + fcus = rig.animation_data.action.fcurves + else: + return False + + for fc in fcus: + animated_frames = [kp.co[0] for kp in fc.keyframe_points] + for bone in args: + if bone in fc.data_path.split('"') and f in animated_frames: + return True + + return False + + +def overwrite_prop_animation(rig, bone, prop_name, value, frames): + act = rig.animation_data.action + if not act: + return + + bone_name = bone.name + curve = None + + for fcu in act.fcurves: + words = fcu.data_path.split('"') + if words[0] == "pose.bones[" and words[1] == bone_name and words[-2] == prop_name: + curve = fcu + break + + if not curve: + return + + for kp in curve.keyframe_points: + if kp.co[0] in frames: + kp.co[1] = value |