Fix #111553: Double IK constraint not working #113056

Merged
Christoph Lendenfeld merged 5 commits from ChrisLend/blender:fix_double_ik_constraint into blender-v4.0-release 2023-10-10 09:06:37 +02:00
1 changed files with 160 additions and 142 deletions

View File

@ -14,6 +14,7 @@
#include "BLI_math_rotation.h"
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
#include "BKE_armature.h"
#include "BKE_constraint.h"
@ -32,24 +33,15 @@
/* ********************** THE IK SOLVER ******************* */
/* allocates PoseTree, and links that to root bone/channel */
/* NOTE: detecting the IK chain is duplicate code...
* in drawarmature.c and in transform_conversions.c */
static void initialize_posetree(Object * /*ob*/, bPoseChannel *pchan_tip)
static void find_ik_constraints(ListBase *constraints,
blender::Vector<bConstraint *> &ik_constraints)
{
bPoseChannel *curchan, *pchan_root = nullptr, *chanlist[256], **oldchan;
PoseTree *tree;
PoseTarget *target;
bConstraint *con;
bKinematicConstraint *data;
int a, t, segcount = 0, size, newsize, *oldparent, parent;
/* find IK constraint, and validate it */
for (con = static_cast<bConstraint *>(pchan_tip->constraints.first); con; con = con->next) {
LISTBASE_FOREACH (bConstraint *, con, constraints) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
data = (bKinematicConstraint *)con->data;
bKinematicConstraint *data = (bKinematicConstraint *)con->data;
if (data->flag & CONSTRAINT_IK_AUTO) {
break;
ik_constraints.append(con);
continue;
}
if (data->tar == nullptr) {
continue;
@ -57,15 +49,32 @@ static void initialize_posetree(Object * /*ob*/, bPoseChannel *pchan_tip)
if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) {
continue;
}
if ((con->flag & CONSTRAINT_DISABLE) == 0) {
break;
if (con->flag & CONSTRAINT_DISABLE) {
continue;
}
ik_constraints.append(con);
}
}
}
if (con == nullptr) {
}
/* allocates PoseTree, and links that to root bone/channel */
/* NOTE: detecting the IK chain is duplicate code...
* in drawarmature.c and in transform_conversions.c */
static void initialize_posetree(Object * /*ob*/, bPoseChannel *pchan_tip)
{
blender::Vector<bConstraint *> ik_constraints;
find_ik_constraints(&pchan_tip->constraints, ik_constraints);
if (ik_constraints.size() == 0) {
return;
}
for (bConstraint *constraint : ik_constraints) {
bPoseChannel *curchan, *pchan_root = nullptr, *chanlist[256], **oldchan;
int segcount = 0;
PoseTarget *target;
PoseTree *tree;
bKinematicConstraint *data = (bKinematicConstraint *)constraint->data;
/* exclude tip from chain? */
if (!(data->flag & CONSTRAINT_IK_TIP)) {
pchan_tip = pchan_tip->parent;
@ -84,14 +93,14 @@ static void initialize_posetree(Object * /*ob*/, bPoseChannel *pchan_tip)
}
}
if (!segcount) {
return;
continue;
}
/* setup the chain data */
/* we make tree-IK, unless all existing targets are in this chain */
for (tree = static_cast<PoseTree *>(pchan_root->iktree.first); tree; tree = tree->next) {
for (target = static_cast<PoseTarget *>(tree->targets.first); target; target = target->next) {
for (target = static_cast<PoseTarget *>(tree->targets.first); target; target = target->next)
{
curchan = tree->pchan[target->tip];
if (curchan->flag & POSE_CHAIN) {
curchan->flag &= ~POSE_CHAIN;
@ -107,7 +116,7 @@ static void initialize_posetree(Object * /*ob*/, bPoseChannel *pchan_tip)
/* create a target */
target = static_cast<PoseTarget *>(MEM_callocN(sizeof(PoseTarget), "posetarget"));
target->con = con;
target->con = constraint;
pchan_tip->flag &= ~POSE_CHAIN;
if (tree == nullptr) {
@ -123,7 +132,7 @@ static void initialize_posetree(Object * /*ob*/, bPoseChannel *pchan_tip)
tree->pchan = static_cast<bPoseChannel **>(
MEM_callocN(segcount * sizeof(void *), "ik tree pchan"));
tree->parent = static_cast<int *>(MEM_callocN(segcount * sizeof(int), "ik tree parent"));
for (a = 0; a < segcount; a++) {
for (int a = 0; a < segcount; a++) {
tree->pchan[a] = chanlist[segcount - a - 1];
tree->parent[a] = a - 1;
}
@ -137,7 +146,8 @@ static void initialize_posetree(Object * /*ob*/, bPoseChannel *pchan_tip)
tree->stretch = tree->stretch && !(data->flag & CONSTRAINT_IK_STRETCH);
/* Skip common pose channels and add remaining. */
size = MIN2(segcount, tree->totchannel);
const int size = MIN2(segcount, tree->totchannel);
int a, t;
a = t = 0;
while (a < size && t < tree->totchannel) {
/* locate first matching channel */
@ -157,6 +167,7 @@ static void initialize_posetree(Object * /*ob*/, bPoseChannel *pchan_tip)
target->tip = tree->totchannel + segcount - 1;
if (segcount > 0) {
int parent;
for (parent = a - 1; parent < tree->totchannel; parent++) {
if (tree->pchan[parent] == chanlist[segcount - 1]->parent) {
break;
@ -169,9 +180,9 @@ static void initialize_posetree(Object * /*ob*/, bPoseChannel *pchan_tip)
}
/* resize array */
newsize = tree->totchannel + segcount;
const int newsize = tree->totchannel + segcount;
oldchan = tree->pchan;
oldparent = tree->parent;
int *oldparent = tree->parent;
tree->pchan = static_cast<bPoseChannel **>(
MEM_callocN(newsize * sizeof(void *), "ik tree pchan"));
@ -200,6 +211,13 @@ static void initialize_posetree(Object * /*ob*/, bPoseChannel *pchan_tip)
BLI_addtail(&tree->targets, target);
/* mark root channel having an IK tree */
pchan_root->flag |= POSE_IKTREE;
/* Per bone only one active IK constraint is supported. Inactive constraints still need to be
* added for the depsgraph to evaluate properly.*/
if (constraint->enforce != 0.0 && !(constraint->flag & CONSTRAINT_OFF)) {
break;
}
}
}
/* transform from bone(b) to bone(b+1), store in chan_mat */