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:
authorAlexander Gavrilov <angavrilov@gmail.com>2019-10-22 13:50:15 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2019-10-23 13:17:04 +0300
commit4625dfb9e74a317c072389357cda89d2a0605d7e (patch)
tree44d70be518ea93f159c48a5a3d92f30c6cee5336 /rigify/utils/animation.py
parent1d656f36618e5f2d5b1f7d0ff86e87ca6e705be4 (diff)
Rigify: make the generic FK to IK snap operator even more generic.
The operator itself simply snaps a chain of bones to a different chain, so nothing in it in fact is specific to IK or FK. To make this even more explicit, rename the operator and add some extra options to control the tooltip and which properties are changed. Also include some other minor enhancements in the script utilities.
Diffstat (limited to 'rigify/utils/animation.py')
-rw-r--r--rigify/utils/animation.py212
1 files changed, 141 insertions, 71 deletions
diff --git a/rigify/utils/animation.py b/rigify/utils/animation.py
index 62042923..1355a0b6 100644
--- a/rigify/utils/animation.py
+++ b/rigify/utils/animation.py
@@ -377,20 +377,24 @@ TRANSFORM_PROPS_ROTATION = frozenset(['rotation_euler', 'rotation_quaternion', '
TRANSFORM_PROPS_SCALE = frozenset(['scale'])
TRANSFORM_PROPS_ALL = frozenset(TRANSFORM_PROPS_LOCATION | TRANSFORM_PROPS_ROTATION | TRANSFORM_PROPS_SCALE)
-class ActionCurveTable(object):
+def transform_props_with_locks(lock_location, lock_rotation, lock_scale):
+ props = set()
+ if not lock_location:
+ props |= TRANSFORM_PROPS_LOCATION
+ if not lock_rotation:
+ props |= TRANSFORM_PROPS_ROTATION
+ if not lock_scale:
+ props |= TRANSFORM_PROPS_SCALE
+ return props
+
+class FCurveTable(object):
"Table for efficient lookup of FCurves by properties."
- def __init__(self, action):
- from collections import defaultdict
- self.action = find_action(action)
- self.curve_map = defaultdict(dict)
- self.index_action()
+ def __init__(self):
+ self.curve_map = collections.defaultdict(dict)
- def index_action(self):
- if not self.action:
- return
-
- for curve in self.action.fcurves:
+ def index_curves(self, curves):
+ for curve in curves:
index = curve.array_index
if index < 0:
index = 0
@@ -412,6 +416,24 @@ class ActionCurveTable(object):
def get_custom_prop_curves(self, ptr, prop):
return self.get_prop_curves(ptr, rna_idprop_quote_path(prop))
+
+class ActionCurveTable(FCurveTable):
+ "Table for efficient lookup of Action FCurves by properties."
+
+ def __init__(self, action):
+ super().__init__()
+ self.action = find_action(action)
+ if self.action:
+ self.index_curves(self.action.fcurves)
+
+class DriverCurveTable(FCurveTable):
+ "Table for efficient lookup of Driver FCurves by properties."
+
+ def __init__(self, object):
+ super().__init__()
+ self.anim_data = object.animation_data
+ if self.anim_data:
+ self.index_curves(self.anim_data.drivers)
''']
exec(SCRIPT_UTILITIES_CURVES[-1])
@@ -495,7 +517,23 @@ SCRIPT_UTILITIES_BAKE = SCRIPT_UTILITIES_KEYING + SCRIPT_UTILITIES_CURVES + ['''
# Keyframe baking operator framework ##
#######################################
-class RigifyBakeKeyframesMixin:
+class RigifyOperatorMixinBase:
+ bl_options = {'UNDO', 'INTERNAL'}
+
+ def init_invoke(self, context):
+ "Override to initialize the operator before invoke."
+
+ def init_execute(self, context):
+ "Override to initialize the operator before execute."
+
+ def before_save_state(self, context, rig):
+ "Override to prepare for saving state."
+
+ def after_save_state(self, context, rig):
+ "Override to undo before_save_state."
+
+
+class RigifyBakeKeyframesMixin(RigifyOperatorMixinBase):
"""Basic framework for an operator that updates a set of keyed frames."""
# Utilities
@@ -566,6 +604,7 @@ class RigifyBakeKeyframesMixin:
self.bake_state = dict()
self.keyflags = get_keying_flags(context)
+ self.keyflags_switch = None
if context.window_manager.rigify_transfer_use_all_keys:
self.bake_add_curve_frames(self.bake_curve_table.curve_map)
@@ -604,9 +643,15 @@ class RigifyBakeKeyframesMixin:
scene = context.scene
saved_state = self.bake_state
- for frame in self.bake_frames:
- scene.frame_set(frame)
- saved_state[frame] = self.save_frame_state(context, rig)
+ try:
+ self.before_save_state(context, rig)
+
+ for frame in self.bake_frames:
+ scene.frame_set(frame)
+ saved_state[frame] = self.save_frame_state(context, rig)
+
+ finally:
+ self.after_save_state(context, rig)
def bake_clean_curves_in_range(self, context, curves):
"Deletes all keys from the given curves in the bake range."
@@ -648,10 +693,6 @@ class RigifyBakeKeyframesMixin:
"Override to execute code one time before the bake apply frame scan."
pass
- def init_execute(self, context):
- "Override to initialize the operator."
- pass
-
def execute(self, context):
self.init_execute(context)
self.bake_init(context)
@@ -661,18 +702,20 @@ class RigifyBakeKeyframesMixin:
if self.report_bake_empty():
return {'CANCELLED'}
- self.bake_save_state(context)
+ try:
+ self.bake_save_state(context)
- range, range_raw = self.bake_clean_curves_in_range(context, curves)
+ range, range_raw = self.bake_clean_curves_in_range(context, curves)
- self.execute_before_apply(context, self.bake_rig, range, range_raw)
+ self.execute_before_apply(context, self.bake_rig, range, range_raw)
- self.bake_apply_state(context)
- return {'FINISHED'}
+ self.bake_apply_state(context)
- def init_invoke(self, context):
- "Override to initialize the operator."
- pass
+ except Exception as e:
+ traceback.print_exc()
+ self.report({'ERROR'}, 'Exception: ' + str(e))
+
+ return {'FINISHED'}
def invoke(self, context, event):
self.init_invoke(context)
@@ -683,22 +726,29 @@ class RigifyBakeKeyframesMixin:
return context.window_manager.invoke_confirm(self, event)
-class RigifySingleUpdateMixin:
+class RigifySingleUpdateMixin(RigifyOperatorMixinBase):
"""Basic framework for an operator that updates only the current frame."""
- def init_execute(self, context):
- pass
-
def execute(self, context):
self.init_execute(context)
obj = context.active_object
self.keyflags = get_autokey_flags(context, ignore_keyset=True)
self.keyflags_switch = add_flags_if_set(self.keyflags, {'INSERTKEY_AVAILABLE'})
- self.apply_frame_state(context, obj, self.save_frame_state(context, obj))
- return {'FINISHED'}
- def init_invoke(self, context):
- pass
+ try:
+ try:
+ self.before_save_state(context, obj)
+ state = self.save_frame_state(context, obj)
+ finally:
+ self.after_save_state(context, obj)
+
+ self.apply_frame_state(context, obj, state)
+
+ except Exception as e:
+ traceback.print_exc()
+ self.report({'ERROR'}, 'Exception: ' + str(e))
+
+ return {'FINISHED'}
def invoke(self, context, event):
self.init_invoke(context)
@@ -773,51 +823,59 @@ def add_clear_keyframes_button(panel, *, bones=[], label='', text=''):
# Generic Snap FK to IK operator ##
###################################
-SCRIPT_REGISTER_OP_SNAP_FK_IK = ['POSE_OT_rigify_generic_fk2ik', 'POSE_OT_rigify_generic_fk2ik_bake']
+SCRIPT_REGISTER_OP_SNAP = ['POSE_OT_rigify_generic_snap', 'POSE_OT_rigify_generic_snap_bake']
-SCRIPT_UTILITIES_OP_SNAP_FK_IK = ['''
-###########################
-## Generic Snap FK to IK ##
-###########################
+SCRIPT_UTILITIES_OP_SNAP = ['''
+#############################
+## Generic Snap (FK to IK) ##
+#############################
-class RigifyGenericFk2IkBase:
- fk_bones: StringProperty(name="FK Bone Chain")
- ik_bones: StringProperty(name="IK Result Bone Chain")
- ctrl_bones: StringProperty(name="IK Controls")
+class RigifyGenericSnapBase:
+ input_bones: StringProperty(name="Input Chain")
+ output_bones: StringProperty(name="Output Chain")
+ ctrl_bones: StringProperty(name="Input Controls")
+ tooltip: StringProperty(name="Tooltip", default="FK to IK")
+ locks: bpy.props.BoolVectorProperty(name="Locked", size=3, default=[False,False,False])
undo_copy_scale: bpy.props.BoolProperty(name="Undo Copy Scale", default=False)
- keyflags = None
-
def init_execute(self, context):
- self.fk_bone_list = json.loads(self.fk_bones)
- self.ik_bone_list = json.loads(self.ik_bones)
+ self.input_bone_list = json.loads(self.input_bones)
+ self.output_bone_list = json.loads(self.output_bones)
self.ctrl_bone_list = json.loads(self.ctrl_bones)
def save_frame_state(self, context, obj):
- return get_chain_transform_matrices(obj, self.ik_bone_list)
+ return get_chain_transform_matrices(obj, self.input_bone_list)
def apply_frame_state(self, context, obj, matrices):
set_chain_transforms_from_matrices(
- context, obj, self.fk_bone_list, matrices,
- undo_copy_scale=self.undo_copy_scale, keyflags=self.keyflags
+ context, obj, self.output_bone_list, matrices,
+ undo_copy_scale=self.undo_copy_scale, keyflags=self.keyflags,
+ no_loc=self.locks[0], no_rot=self.locks[1], no_scale=self.locks[2],
)
-class POSE_OT_rigify_generic_fk2ik(RigifyGenericFk2IkBase, RigifySingleUpdateMixin, bpy.types.Operator):
- bl_idname = "pose.rigify_generic_fk2ik_" + rig_id
- bl_label = "Snap FK->IK"
- bl_options = {'UNDO', 'INTERNAL'}
- bl_description = "Snap the FK chain to IK result"
+class POSE_OT_rigify_generic_snap(RigifyGenericSnapBase, RigifySingleUpdateMixin, bpy.types.Operator):
+ bl_idname = "pose.rigify_generic_snap_" + rig_id
+ bl_label = "Snap Bones"
+ bl_description = "Snap on the current frame"
-class POSE_OT_rigify_generic_fk2ik_bake(RigifyGenericFk2IkBase, RigifyBakeKeyframesMixin, bpy.types.Operator):
- bl_idname = "pose.rigify_generic_fk2ik_bake_" + rig_id
- bl_label = "Apply Snap FK->IK To Keyframes"
- bl_options = {'UNDO', 'INTERNAL'}
- bl_description = "Snap the FK chain keyframes to IK result"
+ @classmethod
+ def description(cls, context, props):
+ return "Snap " + props.tooltip + " on the current frame"
+
+class POSE_OT_rigify_generic_snap_bake(RigifyGenericSnapBase, RigifyBakeKeyframesMixin, bpy.types.Operator):
+ bl_idname = "pose.rigify_generic_snap_bake_" + rig_id
+ bl_label = "Apply Snap To Keyframes"
+ bl_description = "Apply snap to keyframes"
+
+ @classmethod
+ def description(cls, context, props):
+ return "Apply snap " + props.tooltip + " to keyframes"
def execute_scan_curves(self, context, obj):
+ props = transform_props_with_locks(*self.locks)
self.bake_add_bone_frames(self.ctrl_bone_list, TRANSFORM_PROPS_ALL)
- return self.bake_get_all_bone_curves(self.fk_bone_list, TRANSFORM_PROPS_ALL)
+ return self.bake_get_all_bone_curves(self.output_bone_list, props)
''']
def add_fk_ik_snap_buttons(panel, op_single, op_bake, *, label=None, rig_name='', properties=None, clear_bones=None, compact=None):
@@ -840,25 +898,37 @@ def add_fk_ik_snap_buttons(panel, op_single, op_bake, *, label=None, rig_name=''
row.operator(op_bake, text='Action', icon='ACTION_TWEAK', properties=properties)
add_clear_keyframes_button(row, bones=clear_bones, text='Clear')
-def add_generic_snap_fk_to_ik(panel, *, fk_bones=[], ik_bones=[], ik_ctrl_bones=[], label='FK->IK', rig_name='', undo_copy_scale=False, compact=None, clear=True):
+def add_generic_snap(panel, *, output_bones=[], input_bones=[], input_ctrl_bones=[], label='Snap', rig_name='', undo_copy_scale=False, compact=None, clear=True, locks=None, tooltip=None):
panel.use_bake_settings()
- panel.script.add_utilities(SCRIPT_UTILITIES_OP_SNAP_FK_IK)
- panel.script.register_classes(SCRIPT_REGISTER_OP_SNAP_FK_IK)
+ panel.script.add_utilities(SCRIPT_UTILITIES_OP_SNAP)
+ panel.script.register_classes(SCRIPT_REGISTER_OP_SNAP)
op_props = {
- 'fk_bones': json.dumps(fk_bones),
- 'ik_bones': json.dumps(ik_bones),
- 'ctrl_bones': json.dumps(ik_ctrl_bones),
- 'undo_copy_scale': undo_copy_scale,
+ 'output_bones': json.dumps(output_bones),
+ 'input_bones': json.dumps(input_bones),
+ 'ctrl_bones': json.dumps(input_ctrl_bones or input_bones),
}
- clear_bones = fk_bones if clear else None
+ if undo_copy_scale:
+ op_props['undo_copy_scale'] = undo_copy_scale
+ if locks is not None:
+ op_props['locks'] = tuple(locks[0:3])
+ if tooltip is not None:
+ op_props['tooltip'] = tooltip
+
+ clear_bones = output_bones if clear else None
add_fk_ik_snap_buttons(
- panel, 'pose.rigify_generic_fk2ik_{rig_id}', 'pose.rigify_generic_fk2ik_bake_{rig_id}',
+ panel, 'pose.rigify_generic_snap_{rig_id}', 'pose.rigify_generic_snap_bake_{rig_id}',
label=label, rig_name=rig_name, properties=op_props, clear_bones=clear_bones, compact=compact,
)
+def add_generic_snap_fk_to_ik(panel, *, fk_bones=[], ik_bones=[], ik_ctrl_bones=[], label='FK->IK', rig_name='', undo_copy_scale=False, compact=None, clear=True):
+ add_generic_snap(
+ panel, output_bones=fk_bones, input_bones=ik_bones, input_ctrl_bones=ik_ctrl_bones,
+ label=label, rig_name=rig_name, undo_copy_scale=undo_copy_scale, compact=compact, clear=clear
+ )
+
###############################
# Module register/unregister ##
###############################