From eab95fa2aaa9d1b29b460ab5c52fe8daf1da2d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 25 Sep 2023 14:37:22 +0200 Subject: [PATCH] Anim: enable visual keying of IK-influenced bones Enable visual keying of bones that are influenced by an IK constraint. This wasn't possible before, as the visual keying system only checked constraints on the bone itself, and not whether the bone was part of an IK chain. This commit introduces a new `bPoseChannel::constflag` value `PCHAN_INFLUENCED_BY_IK` that is set whenever the pose bone is part of an IK chain. The `pchan->constflag` field is computed during depsgraph evaluation. If the depsgraph is active, it is now also written back to the original pchan, so that it can be used in the "should visual keying be used" function. Fixes: #76791 "Different results when keyframing visual transforms and applying transforms manually on IK constraint". Note that visually keying does *not* copy the visual pose to the current pose. Furthermore, when visually keying only part of the IK chain, the result of re-evaluating the IK constraint (for example by moving the scene forward and then backward by one frame) may still produce a different result, as the IK chain now has a different start orientation. Note that commit explicitly does not cover Spline IK constraints. They can introduce heavy shear, especially with the default settings, which cannot be represented by keys on loc/rot/scale. For historical reference: 876cfc837e2f065fa370940ca578983d84c48a11 introduces the 'use visual keying' preference option, where Blender automatically chooses whether or not to use visual keying. This is why there is a function at all that determines whether to use visual keying or not. --- source/blender/blenkernel/intern/action.cc | 13 ++++++++++++- source/blender/blenkernel/intern/armature_update.cc | 1 + .../draw/engines/overlay/overlay_armature.cc | 6 +++++- source/blender/editors/animation/keyframing.cc | 7 +++++++ source/blender/makesdna/DNA_action_types.h | 2 ++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/action.cc b/source/blender/blenkernel/intern/action.cc index c9003bf9fb1..51612a17572 100644 --- a/source/blender/blenkernel/intern/action.cc +++ b/source/blender/blenkernel/intern/action.cc @@ -1187,11 +1187,12 @@ void BKE_pose_update_constraint_flags(bPose *pose) pchan->constflag |= PCHAN_HAS_NO_TARGET; } + bPoseChannel *chain_tip = (data->flag & CONSTRAINT_IK_TIP) ? pchan : pchan->parent; + /* negative rootbone = recalc rootbone index. used in do_versions */ if (data->rootbone < 0) { data->rootbone = 0; - bPoseChannel *chain_tip = (data->flag & CONSTRAINT_IK_TIP) ? pchan : pchan->parent; bPoseChannel *parchan = chain_tip; while (parchan) { data->rootbone++; @@ -1201,6 +1202,16 @@ void BKE_pose_update_constraint_flags(bPose *pose) parchan = parchan->parent; } } + + /* Mark the pose bones in the IK chain as influenced by it. */ + { + bPoseChannel *chain_bone = chain_tip; + for (short index = 0; chain_bone && (data->rootbone == 0 || index < data->rootbone); + index++) { + chain_bone->constflag |= PCHAN_INFLUENCED_BY_IK; + chain_bone = chain_bone->parent; + } + } break; } diff --git a/source/blender/blenkernel/intern/armature_update.cc b/source/blender/blenkernel/intern/armature_update.cc index 161f6907ce5..29e3595d431 100644 --- a/source/blender/blenkernel/intern/armature_update.cc +++ b/source/blender/blenkernel/intern/armature_update.cc @@ -942,6 +942,7 @@ static void pose_channel_flush_to_orig_if_needed(Depsgraph *depsgraph, copy_v3_v3(pchan_orig->pose_head, pchan->pose_mat[3]); copy_m4_m4(pchan_orig->constinv, pchan->constinv); copy_v3_v3(pchan_orig->pose_tail, pchan->pose_tail); + pchan_orig->constflag = pchan->constflag; } void BKE_pose_bone_done(Depsgraph *depsgraph, Object *object, int pchan_index) diff --git a/source/blender/draw/engines/overlay/overlay_armature.cc b/source/blender/draw/engines/overlay/overlay_armature.cc index 176a655adfe..0e03c6eb769 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.cc +++ b/source/blender/draw/engines/overlay/overlay_armature.cc @@ -1201,7 +1201,11 @@ static void get_pchan_color_constraint(const ThemeWireColor *bcolor, float r_color[4]) { const ePchan_ConstFlag constflag = bone.constflag(); - if (constflag == 0 || (bcolor && (bcolor->flag & TH_WIRECOLOR_CONSTCOLS) == 0)) { + /* Not all flags should result in a different bone color. */ + const ePchan_ConstFlag flags_to_color = PCHAN_HAS_NO_TARGET | PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK | + PCHAN_HAS_CONST; + if ((constflag & flags_to_color) == 0 || + (bcolor && (bcolor->flag & TH_WIRECOLOR_CONSTCOLS) == 0)) { get_pchan_color_solid(bcolor, r_color); return; } diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index aa15c73dec0..f362e03162e 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -887,6 +887,13 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) /* Pose Channel */ bPoseChannel *pchan = static_cast(ptr->data); + if (pchan->constflag & (PCHAN_HAS_IK | PCHAN_INFLUENCED_BY_IK)) { + /* Spline IK cannot generally be keyed visually, because (at least with the default + * constraint settings) it requires non-uniform scaling that causes shearing in child bones, + * which cannot be represented by the bone's loc/rot/scale properties. */ + return true; + } + con = static_cast(pchan->constraints.first); has_parent = (pchan->parent != nullptr); } diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 0cf5cb5846b..7de6c3bfd71 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -395,7 +395,9 @@ typedef enum ePchan_ConstFlag { PCHAN_HAS_NO_TARGET = (1 << 3), /* Has (spline) IK constraint but no target is set. */ /* PCHAN_HAS_STRIDE = (1 << 4), */ /* UNUSED */ PCHAN_HAS_SPLINEIK = (1 << 5), /* Has Spline IK constraint. */ + PCHAN_INFLUENCED_BY_IK = (1 << 6), /* Is part of a (non-spline) IK chain. */ } ePchan_ConstFlag; +ENUM_OPERATORS(ePchan_ConstFlag, PCHAN_INFLUENCED_BY_IK); /* PoseChannel->ikflag */ typedef enum ePchan_IkFlag {