Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucio Rossi <lucio.rossi75@gmail.com>2017-07-24 19:14:16 +0300
committerLucio Rossi <lucio.rossi75@gmail.com>2017-07-24 19:14:30 +0300
commit33b0e2e9025965133656dd85506bbef62ca3183d (patch)
tree52f2368a79623272cadf64a9c1ca3ac209176231
parent49230a4c122013bf851ab37b029e7d4f624d68ad (diff)
Rigify 0.5: new features, Animation Tools and Quat/Euler converter
small fixes & UI improvements
-rw-r--r--rigify/__init__.py7
-rw-r--r--rigify/generate.py11
-rw-r--r--rigify/metarigs/Animals/bird.py2
-rw-r--r--rigify/rigs/experimental/super_chain.py22
-rw-r--r--rigify/rigs/faces/super_face.py60
-rw-r--r--rigify/rigs/limbs/arm.py80
-rw-r--r--rigify/rigs/limbs/leg.py104
-rw-r--r--rigify/rigs/limbs/paw.py92
-rw-r--r--rigify/rigs/limbs/simple_tentacle.py32
-rw-r--r--rigify/rigs/limbs/super_limb.py33
-rw-r--r--rigify/rigs/limbs/super_palm.py2
-rw-r--r--rigify/rigs/limbs/ui.py10
-rw-r--r--rigify/rigs/misc/__init__.py0
-rw-r--r--rigify/rigs/misc/delta.py165
-rw-r--r--rigify/rigs/spines/super_spine.py28
-rw-r--r--rigify/rigs/utils.py21
-rw-r--r--rigify/rot_mode.py359
-rw-r--r--rigify/ui.py555
-rw-r--r--rigify/utils.py99
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