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: 876cfc837e
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.
This commit is contained in:
Sybren A. Stüvel
2023-09-25 14:37:22 +02:00
parent caf46c9fbb
commit eab95fa2aa
5 changed files with 27 additions and 2 deletions
+12 -1
View File
@@ -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;
}
@@ -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)
@@ -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;
}
@@ -887,6 +887,13 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
/* Pose Channel */
bPoseChannel *pchan = static_cast<bPoseChannel *>(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<bConstraint *>(pchan->constraints.first);
has_parent = (pchan->parent != nullptr);
}
@@ -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 {