[Bf-extensions-cvs] [4625dfb9] master: Rigify: make the generic FK to IK snap operator even more generic.

Alexander Gavrilov noreply at git.blender.org
Wed Oct 23 12:28:30 CEST 2019


Commit: 4625dfb9e74a317c072389357cda89d2a0605d7e
Author: Alexander Gavrilov
Date:   Tue Oct 22 13:50:15 2019 +0300
Branches: master
https://developer.blender.org/rBA4625dfb9e74a317c072389357cda89d2a0605d7e

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.

===================================================================

M	rigify/rig_ui_template.py
M	rigify/rigs/limbs/limb_rigs.py
M	rigify/utils/animation.py
M	rigify/utils/switch_parent.py

===================================================================

diff --git a/rigify/rig_ui_template.py b/rigify/rig_ui_template.py
index 888f6871..bb5a9cbd 100644
--- a/rigify/rig_ui_template.py
+++ b/rigify/rig_ui_template.py
@@ -36,6 +36,7 @@ UI_IMPORTS = [
     'import math',
     'import json',
     'import collections',
+    'import traceback',
     'from math import pi',
     'from bpy.props import StringProperty',
     'from mathutils import Euler, Matrix, Quaternion, Vector',
diff --git a/rigify/rigs/limbs/limb_rigs.py b/rigify/rigs/limbs/limb_rigs.py
index 493ba33a..86fc6be4 100644
--- a/rigify/rigs/limbs/limb_rigs.py
+++ b/rigify/rigs/limbs/limb_rigs.py
@@ -869,8 +869,6 @@ class RigifyLimbIk2FkBase:
     ctrl_bones:   StringProperty(name="IK Controls")
     extra_ctrls:  StringProperty(name="Extra IK Controls")
 
-    keyflags = None
-
     def init_execute(self, context):
         if self.fk_bones:
             self.fk_bone_list = json.loads(self.fk_bones)
@@ -947,13 +945,11 @@ class RigifyLimbIk2FkBase:
 class POSE_OT_rigify_limb_ik2fk(RigifyLimbIk2FkBase, RigifySingleUpdateMixin, bpy.types.Operator):
     bl_idname = "pose.rigify_limb_ik2fk_" + rig_id
     bl_label = "Snap IK->FK"
-    bl_options = {'UNDO', 'INTERNAL'}
     bl_description = "Snap the IK chain to FK result"
 
 class POSE_OT_rigify_limb_ik2fk_bake(RigifyLimbIk2FkBase, RigifyBakeKeyframesMixin, bpy.types.Operator):
     bl_idname = "pose.rigify_limb_ik2fk_bake_" + rig_id
     bl_label = "Apply Snap IK->FK To Keyframes"
-    bl_options = {'UNDO', 'INTERNAL'}
     bl_description = "Snap the IK chain keyframes to FK result"
 
     def execute_scan_curves(self, context, obj):
@@ -994,8 +990,6 @@ SCRIPT_UTILITIES_OP_TOGGLE_POLE = SCRIPT_UTILITIES_OP_SNAP_IK_FK + ['''
 class RigifyLimbTogglePoleBase(RigifyLimbIk2FkBase):
     use_pole: bpy.props.BoolProperty(name="Use Pole Vector")
 
-    keyflags_switch = None
-
     def save_frame_state(self, context, obj):
         return get_chain_transform_matrices(obj, self.ik_bone_list)
 
@@ -1033,13 +1027,11 @@ class RigifyLimbTogglePoleBase(RigifyLimbIk2FkBase):
 class POSE_OT_rigify_limb_toggle_pole(RigifyLimbTogglePoleBase, RigifySingleUpdateMixin, bpy.types.Operator):
     bl_idname = "pose.rigify_limb_toggle_pole_" + rig_id
     bl_label = "Toggle Pole"
-    bl_options = {'UNDO', 'INTERNAL'}
     bl_description = "Switch the IK chain between pole and rotation"
 
 class POSE_OT_rigify_limb_toggle_pole_bake(RigifyLimbTogglePoleBase, RigifyBakeKeyframesMixin, bpy.types.Operator):
     bl_idname = "pose.rigify_limb_toggle_pole_bake_" + rig_id
     bl_label = "Apply Toggle Pole To Keyframes"
-    bl_options = {'UNDO', 'INTERNAL'}
     bl_description = "Switch the IK chain between pole and rotation over a frame range"
 
     def execute_scan_curves(self, context, obj):
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:     

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list