Fix #111553: Double IK constraint not working #113056
|
@ -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,149 +49,175 @@ 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;
|
||||
}
|
||||
|
||||
/* exclude tip from chain? */
|
||||
if (!(data->flag & CONSTRAINT_IK_TIP)) {
|
||||
pchan_tip = pchan_tip->parent;
|
||||
}
|
||||
|
||||
/* Find the chain's root & count the segments needed */
|
||||
for (curchan = pchan_tip; curchan; curchan = curchan->parent) {
|
||||
pchan_root = curchan;
|
||||
|
||||
curchan->flag |= POSE_CHAIN; /* don't forget to clear this */
|
||||
chanlist[segcount] = curchan;
|
||||
segcount++;
|
||||
|
||||
if (segcount == data->rootbone || segcount > 255) {
|
||||
break; /* 255 is weak */
|
||||
}
|
||||
}
|
||||
if (!segcount) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
curchan = tree->pchan[target->tip];
|
||||
if (curchan->flag & POSE_CHAIN) {
|
||||
curchan->flag &= ~POSE_CHAIN;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* create a target */
|
||||
target = static_cast<PoseTarget *>(MEM_callocN(sizeof(PoseTarget), "posetarget"));
|
||||
target->con = con;
|
||||
pchan_tip->flag &= ~POSE_CHAIN;
|
||||
|
||||
if (tree == nullptr) {
|
||||
/* make new tree */
|
||||
tree = static_cast<PoseTree *>(MEM_callocN(sizeof(PoseTree), "posetree"));
|
||||
|
||||
tree->type = CONSTRAINT_TYPE_KINEMATIC;
|
||||
|
||||
tree->iterations = data->iterations;
|
||||
tree->totchannel = segcount;
|
||||
tree->stretch = (data->flag & CONSTRAINT_IK_STRETCH);
|
||||
|
||||
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++) {
|
||||
tree->pchan[a] = chanlist[segcount - a - 1];
|
||||
tree->parent[a] = a - 1;
|
||||
}
|
||||
target->tip = segcount - 1;
|
||||
|
||||
/* AND! link the tree to the root */
|
||||
BLI_addtail(&pchan_root->iktree, tree);
|
||||
}
|
||||
else {
|
||||
tree->iterations = MAX2(data->iterations, tree->iterations);
|
||||
tree->stretch = tree->stretch && !(data->flag & CONSTRAINT_IK_STRETCH);
|
||||
|
||||
/* Skip common pose channels and add remaining. */
|
||||
size = MIN2(segcount, tree->totchannel);
|
||||
a = t = 0;
|
||||
while (a < size && t < tree->totchannel) {
|
||||
/* locate first matching channel */
|
||||
for (; t < tree->totchannel && tree->pchan[t] != chanlist[segcount - a - 1]; t++) {
|
||||
/* pass */
|
||||
}
|
||||
if (t >= tree->totchannel) {
|
||||
break;
|
||||
}
|
||||
for (; a < size && t < tree->totchannel && tree->pchan[t] == chanlist[segcount - a - 1];
|
||||
a++, t++) {
|
||||
/* pass */
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
segcount = segcount - a;
|
||||
target->tip = tree->totchannel + segcount - 1;
|
||||
/* Find the chain's root & count the segments needed */
|
||||
for (curchan = pchan_tip; curchan; curchan = curchan->parent) {
|
||||
pchan_root = curchan;
|
||||
|
||||
if (segcount > 0) {
|
||||
for (parent = a - 1; parent < tree->totchannel; parent++) {
|
||||
if (tree->pchan[parent] == chanlist[segcount - 1]->parent) {
|
||||
curchan->flag |= POSE_CHAIN; /* don't forget to clear this */
|
||||
chanlist[segcount] = curchan;
|
||||
segcount++;
|
||||
|
||||
if (segcount == data->rootbone || segcount > 255) {
|
||||
break; /* 255 is weak */
|
||||
}
|
||||
}
|
||||
if (!segcount) {
|
||||
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)
|
||||
{
|
||||
curchan = tree->pchan[target->tip];
|
||||
if (curchan->flag & POSE_CHAIN) {
|
||||
curchan->flag &= ~POSE_CHAIN;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* shouldn't happen, but could with dependency cycles */
|
||||
if (parent == tree->totchannel) {
|
||||
parent = a - 1;
|
||||
if (target) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* resize array */
|
||||
newsize = tree->totchannel + segcount;
|
||||
oldchan = tree->pchan;
|
||||
oldparent = tree->parent;
|
||||
|
||||
tree->pchan = static_cast<bPoseChannel **>(
|
||||
MEM_callocN(newsize * sizeof(void *), "ik tree pchan"));
|
||||
tree->parent = static_cast<int *>(MEM_callocN(newsize * sizeof(int), "ik tree parent"));
|
||||
memcpy(tree->pchan, oldchan, sizeof(void *) * tree->totchannel);
|
||||
memcpy(tree->parent, oldparent, sizeof(int) * tree->totchannel);
|
||||
MEM_freeN(oldchan);
|
||||
MEM_freeN(oldparent);
|
||||
|
||||
/* add new pose channels at the end, in reverse order */
|
||||
for (a = 0; a < segcount; a++) {
|
||||
tree->pchan[tree->totchannel + a] = chanlist[segcount - a - 1];
|
||||
tree->parent[tree->totchannel + a] = tree->totchannel + a - 1;
|
||||
}
|
||||
tree->parent[tree->totchannel] = parent;
|
||||
|
||||
tree->totchannel = newsize;
|
||||
}
|
||||
|
||||
/* move tree to end of list, for correct evaluation order */
|
||||
BLI_remlink(&pchan_root->iktree, tree);
|
||||
BLI_addtail(&pchan_root->iktree, tree);
|
||||
}
|
||||
/* create a target */
|
||||
target = static_cast<PoseTarget *>(MEM_callocN(sizeof(PoseTarget), "posetarget"));
|
||||
target->con = constraint;
|
||||
pchan_tip->flag &= ~POSE_CHAIN;
|
||||
|
||||
/* add target to the tree */
|
||||
BLI_addtail(&tree->targets, target);
|
||||
/* mark root channel having an IK tree */
|
||||
pchan_root->flag |= POSE_IKTREE;
|
||||
if (tree == nullptr) {
|
||||
/* make new tree */
|
||||
tree = static_cast<PoseTree *>(MEM_callocN(sizeof(PoseTree), "posetree"));
|
||||
|
||||
tree->type = CONSTRAINT_TYPE_KINEMATIC;
|
||||
|
||||
tree->iterations = data->iterations;
|
||||
tree->totchannel = segcount;
|
||||
tree->stretch = (data->flag & CONSTRAINT_IK_STRETCH);
|
||||
|
||||
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 (int a = 0; a < segcount; a++) {
|
||||
tree->pchan[a] = chanlist[segcount - a - 1];
|
||||
tree->parent[a] = a - 1;
|
||||
}
|
||||
target->tip = segcount - 1;
|
||||
|
||||
/* AND! link the tree to the root */
|
||||
BLI_addtail(&pchan_root->iktree, tree);
|
||||
}
|
||||
else {
|
||||
tree->iterations = MAX2(data->iterations, tree->iterations);
|
||||
tree->stretch = tree->stretch && !(data->flag & CONSTRAINT_IK_STRETCH);
|
||||
|
||||
/* Skip common pose channels and add remaining. */
|
||||
const int size = MIN2(segcount, tree->totchannel);
|
||||
int a, t;
|
||||
a = t = 0;
|
||||
while (a < size && t < tree->totchannel) {
|
||||
/* locate first matching channel */
|
||||
for (; t < tree->totchannel && tree->pchan[t] != chanlist[segcount - a - 1]; t++) {
|
||||
/* pass */
|
||||
}
|
||||
if (t >= tree->totchannel) {
|
||||
break;
|
||||
}
|
||||
for (; a < size && t < tree->totchannel && tree->pchan[t] == chanlist[segcount - a - 1];
|
||||
a++, t++) {
|
||||
/* pass */
|
||||
}
|
||||
}
|
||||
|
||||
segcount = segcount - a;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* shouldn't happen, but could with dependency cycles */
|
||||
if (parent == tree->totchannel) {
|
||||
parent = a - 1;
|
||||
}
|
||||
|
||||
/* resize array */
|
||||
const int newsize = tree->totchannel + segcount;
|
||||
oldchan = tree->pchan;
|
||||
int *oldparent = tree->parent;
|
||||
|
||||
tree->pchan = static_cast<bPoseChannel **>(
|
||||
MEM_callocN(newsize * sizeof(void *), "ik tree pchan"));
|
||||
tree->parent = static_cast<int *>(MEM_callocN(newsize * sizeof(int), "ik tree parent"));
|
||||
memcpy(tree->pchan, oldchan, sizeof(void *) * tree->totchannel);
|
||||
memcpy(tree->parent, oldparent, sizeof(int) * tree->totchannel);
|
||||
MEM_freeN(oldchan);
|
||||
MEM_freeN(oldparent);
|
||||
|
||||
/* add new pose channels at the end, in reverse order */
|
||||
for (a = 0; a < segcount; a++) {
|
||||
tree->pchan[tree->totchannel + a] = chanlist[segcount - a - 1];
|
||||
tree->parent[tree->totchannel + a] = tree->totchannel + a - 1;
|
||||
}
|
||||
tree->parent[tree->totchannel] = parent;
|
||||
|
||||
tree->totchannel = newsize;
|
||||
}
|
||||
|
||||
/* move tree to end of list, for correct evaluation order */
|
||||
BLI_remlink(&pchan_root->iktree, tree);
|
||||
BLI_addtail(&pchan_root->iktree, tree);
|
||||
}
|
||||
|
||||
/* add target to the tree */
|
||||
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 */
|
||||
|
|
Loading…
Reference in New Issue