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,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 */
|
||||
|
|
Loading…
Reference in New Issue