Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2019-04-17 07:17:24 +0300
committerCampbell Barton <ideasman42@gmail.com>2019-04-17 07:21:24 +0300
commite12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch)
tree8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/ikplugin/intern/iksolver_plugin.c
parentb3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff)
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/ikplugin/intern/iksolver_plugin.c')
-rw-r--r--source/blender/ikplugin/intern/iksolver_plugin.c1016
1 files changed, 520 insertions, 496 deletions
diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c
index ddb8b37afc2..5615cc4ea31 100644
--- a/source/blender/ikplugin/intern/iksolver_plugin.c
+++ b/source/blender/ikplugin/intern/iksolver_plugin.c
@@ -50,551 +50,575 @@
/* Note: detecting the IK chain is duplicate code... in drawarmature.c and in transform_conversions.c */
static void initialize_posetree(struct Object *UNUSED(ob), bPoseChannel *pchan_tip)
{
- bPoseChannel *curchan, *pchan_root = NULL, *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 = pchan_tip->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
- data = (bKinematicConstraint *)con->data;
- if (data->flag & CONSTRAINT_IK_AUTO) break;
- if (data->tar == NULL) continue;
- if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) continue;
- if ((con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) == 0 && (con->enforce != 0.0f)) break;
- }
- }
- if (con == NULL) 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 = pchan_root->iktree.first; tree; tree = tree->next) {
- for (target = 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 = MEM_callocN(sizeof(PoseTarget), "posetarget");
- target->con = con;
- pchan_tip->flag &= ~POSE_CHAIN;
-
- if (tree == NULL) {
- /* make new tree */
- tree = 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 = MEM_callocN(segcount * sizeof(void *), "ik tree pchan");
- tree->parent = 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++) ;
- if (t >= tree->totchannel)
- break;
- for (; a < size && t < tree->totchannel && tree->pchan[t] == chanlist[segcount - a - 1]; a++, t++) ;
- }
-
- segcount = segcount - a;
- target->tip = tree->totchannel + segcount - 1;
-
- if (segcount > 0) {
- 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 */
- newsize = tree->totchannel + segcount;
- oldchan = tree->pchan;
- oldparent = tree->parent;
-
- tree->pchan = MEM_callocN(newsize * sizeof(void *), "ik tree pchan");
- tree->parent = 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;
+ bPoseChannel *curchan, *pchan_root = NULL, *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 = pchan_tip->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ data = (bKinematicConstraint *)con->data;
+ if (data->flag & CONSTRAINT_IK_AUTO)
+ break;
+ if (data->tar == NULL)
+ continue;
+ if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0)
+ continue;
+ if ((con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) == 0 && (con->enforce != 0.0f))
+ break;
+ }
+ }
+ if (con == NULL)
+ 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 = pchan_root->iktree.first; tree; tree = tree->next) {
+ for (target = 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 = MEM_callocN(sizeof(PoseTarget), "posetarget");
+ target->con = con;
+ pchan_tip->flag &= ~POSE_CHAIN;
+
+ if (tree == NULL) {
+ /* make new tree */
+ tree = 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 = MEM_callocN(segcount * sizeof(void *), "ik tree pchan");
+ tree->parent = 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++)
+ ;
+ if (t >= tree->totchannel)
+ break;
+ for (; a < size && t < tree->totchannel && tree->pchan[t] == chanlist[segcount - a - 1];
+ a++, t++)
+ ;
+ }
+
+ segcount = segcount - a;
+ target->tip = tree->totchannel + segcount - 1;
+
+ if (segcount > 0) {
+ 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 */
+ newsize = tree->totchannel + segcount;
+ oldchan = tree->pchan;
+ oldparent = tree->parent;
+
+ tree->pchan = MEM_callocN(newsize * sizeof(void *), "ik tree pchan");
+ tree->parent = 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;
}
-
/* transform from bone(b) to bone(b+1), store in chan_mat */
static void make_dmats(bPoseChannel *pchan)
{
- if (pchan->parent) {
- float iR_parmat[4][4];
- invert_m4_m4(iR_parmat, pchan->parent->pose_mat);
- mul_m4_m4m4(pchan->chan_mat, iR_parmat, pchan->pose_mat); // delta mat
- }
- else {
- copy_m4_m4(pchan->chan_mat, pchan->pose_mat);
- }
+ if (pchan->parent) {
+ float iR_parmat[4][4];
+ invert_m4_m4(iR_parmat, pchan->parent->pose_mat);
+ mul_m4_m4m4(pchan->chan_mat, iR_parmat, pchan->pose_mat); // delta mat
+ }
+ else {
+ copy_m4_m4(pchan->chan_mat, pchan->pose_mat);
+ }
}
/* applies IK matrix to pchan, IK is done separated */
/* formula: pose_mat(b) = pose_mat(b-1) * diffmat(b-1, b) * ik_mat(b) */
/* to make this work, the diffmats have to be precalculated! Stored in chan_mat */
-static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[3][3]) // nr = to detect if this is first bone
+static void where_is_ik_bone(bPoseChannel *pchan,
+ float ik_mat[3][3]) // nr = to detect if this is first bone
{
- float vec[3], ikmat[4][4];
+ float vec[3], ikmat[4][4];
- copy_m4_m3(ikmat, ik_mat);
+ copy_m4_m3(ikmat, ik_mat);
- if (pchan->parent)
- mul_m4_m4m4(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat);
- else
- copy_m4_m4(pchan->pose_mat, pchan->chan_mat);
+ if (pchan->parent)
+ mul_m4_m4m4(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat);
+ else
+ copy_m4_m4(pchan->pose_mat, pchan->chan_mat);
#ifdef USE_NONUNIFORM_SCALE
- /* apply IK mat, but as if the bones have uniform scale since the IK solver
- * is not aware of non-uniform scale */
- float scale[3];
- mat4_to_size(scale, pchan->pose_mat);
- normalize_v3_length(pchan->pose_mat[0], scale[1]);
- normalize_v3_length(pchan->pose_mat[2], scale[1]);
+ /* apply IK mat, but as if the bones have uniform scale since the IK solver
+ * is not aware of non-uniform scale */
+ float scale[3];
+ mat4_to_size(scale, pchan->pose_mat);
+ normalize_v3_length(pchan->pose_mat[0], scale[1]);
+ normalize_v3_length(pchan->pose_mat[2], scale[1]);
#endif
- mul_m4_m4m4(pchan->pose_mat, pchan->pose_mat, ikmat);
+ mul_m4_m4m4(pchan->pose_mat, pchan->pose_mat, ikmat);
#ifdef USE_NONUNIFORM_SCALE
- float ik_scale[3];
- mat3_to_size(ik_scale, ik_mat);
- normalize_v3_length(pchan->pose_mat[0], scale[0] * ik_scale[0]);
- normalize_v3_length(pchan->pose_mat[2], scale[2] * ik_scale[2]);
+ float ik_scale[3];
+ mat3_to_size(ik_scale, ik_mat);
+ normalize_v3_length(pchan->pose_mat[0], scale[0] * ik_scale[0]);
+ normalize_v3_length(pchan->pose_mat[2], scale[2] * ik_scale[2]);
#endif
- /* calculate head */
- copy_v3_v3(pchan->pose_head, pchan->pose_mat[3]);
- /* calculate tail */
- copy_v3_v3(vec, pchan->pose_mat[1]);
- mul_v3_fl(vec, pchan->bone->length);
- add_v3_v3v3(pchan->pose_tail, pchan->pose_head, vec);
+ /* calculate head */
+ copy_v3_v3(pchan->pose_head, pchan->pose_mat[3]);
+ /* calculate tail */
+ copy_v3_v3(vec, pchan->pose_mat[1]);
+ mul_v3_fl(vec, pchan->bone->length);
+ add_v3_v3v3(pchan->pose_tail, pchan->pose_head, vec);
- pchan->flag |= POSE_DONE;
+ pchan->flag |= POSE_DONE;
}
-
/* called from within the core BKE_pose_where_is loop, all animsystems and constraints
* were executed & assigned. Now as last we do an IK pass */
-static void execute_posetree(struct Depsgraph *depsgraph, struct Scene *scene, Object *ob, PoseTree *tree)
+static void execute_posetree(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *ob,
+ PoseTree *tree)
{
- float R_parmat[3][3], identity[3][3];
- float iR_parmat[3][3];
- float R_bonemat[3][3];
- float goalrot[3][3], goalpos[3];
- float rootmat[4][4], imat[4][4];
- float goal[4][4], goalinv[4][4];
- float irest_basis[3][3], full_basis[3][3];
- float end_pose[4][4], world_pose[4][4];
- float basis[3][3], rest_basis[3][3], start[3], *ikstretch = NULL;
- float resultinf = 0.0f;
- int a, flag, hasstretch = 0, resultblend = 0;
- bPoseChannel *pchan;
- IK_Segment *seg, *parent, **iktree, *iktarget;
- IK_Solver *solver;
- PoseTarget *target;
- bKinematicConstraint *data, *poleangledata = NULL;
- Bone *bone;
-
- if (tree->totchannel == 0)
- return;
-
- iktree = MEM_mallocN(sizeof(void *) * tree->totchannel, "ik tree");
-
- for (a = 0; a < tree->totchannel; a++) {
- float length;
- pchan = tree->pchan[a];
- bone = pchan->bone;
-
- /* set DoF flag */
- flag = 0;
- if (!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP))
- flag |= IK_XDOF;
- if (!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP))
- flag |= IK_YDOF;
- if (!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP))
- flag |= IK_ZDOF;
-
- if (tree->stretch && (pchan->ikstretch > 0.0f)) {
- flag |= IK_TRANS_YDOF;
- hasstretch = 1;
- }
-
- seg = iktree[a] = IK_CreateSegment(flag);
-
- /* find parent */
- if (a == 0)
- parent = NULL;
- else
- parent = iktree[tree->parent[a]];
-
- IK_SetParent(seg, parent);
-
- /* get the matrix that transforms from prevbone into this bone */
- copy_m3_m4(R_bonemat, pchan->pose_mat);
-
- /* gather transformations for this IK segment */
-
- if (pchan->parent)
- copy_m3_m4(R_parmat, pchan->parent->pose_mat);
- else
- unit_m3(R_parmat);
-
- /* bone offset */
- if (pchan->parent && (a > 0))
- sub_v3_v3v3(start, pchan->pose_head, pchan->parent->pose_tail);
- else
- /* only root bone (a = 0) has no parent */
- start[0] = start[1] = start[2] = 0.0f;
-
- /* change length based on bone size */
- length = bone->length * len_v3(R_bonemat[1]);
-
- /* basis must be pure rotation */
- normalize_m3(R_bonemat);
- normalize_m3(R_parmat);
-
- /* compute rest basis and its inverse */
- copy_m3_m3(rest_basis, bone->bone_mat);
- transpose_m3_m3(irest_basis, bone->bone_mat);
-
- /* compute basis with rest_basis removed */
- invert_m3_m3(iR_parmat, R_parmat);
- mul_m3_m3m3(full_basis, iR_parmat, R_bonemat);
- mul_m3_m3m3(basis, irest_basis, full_basis);
-
- /* transform offset into local bone space */
- mul_m3_v3(iR_parmat, start);
-
- IK_SetTransform(seg, start, rest_basis, basis, length);
-
- if (pchan->ikflag & BONE_IK_XLIMIT)
- IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]);
- if (pchan->ikflag & BONE_IK_YLIMIT)
- IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]);
- if (pchan->ikflag & BONE_IK_ZLIMIT)
- IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]);
-
- IK_SetStiffness(seg, IK_X, pchan->stiffness[0]);
- IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]);
- IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]);
-
- if (tree->stretch && (pchan->ikstretch > 0.0f)) {
- const float ikstretch_sq = SQUARE(pchan->ikstretch);
- /* this function does its own clamping */
- IK_SetStiffness(seg, IK_TRANS_Y, 1.0f - ikstretch_sq);
- IK_SetLimit(seg, IK_TRANS_Y, IK_STRETCH_STIFF_MIN, IK_STRETCH_STIFF_MAX);
- }
- }
-
- solver = IK_CreateSolver(iktree[0]);
-
- /* set solver goals */
-
- /* first set the goal inverse transform, assuming the root of tree was done ok! */
- pchan = tree->pchan[0];
- if (pchan->parent) {
- /* transform goal by parent mat, so this rotation is not part of the
- * segment's basis. otherwise rotation limits do not work on the
- * local transform of the segment itself. */
- copy_m4_m4(rootmat, pchan->parent->pose_mat);
- /* However, we do not want to get (i.e. reverse) parent's scale, as it generates [#31008]
- * kind of nasty bugs... */
- normalize_m4(rootmat);
- }
- else
- unit_m4(rootmat);
- copy_v3_v3(rootmat[3], pchan->pose_head);
-
- mul_m4_m4m4(imat, ob->obmat, rootmat);
- invert_m4_m4(goalinv, imat);
-
- for (target = tree->targets.first; target; target = target->next) {
- float polepos[3];
- int poleconstrain = 0;
-
- data = (bKinematicConstraint *)target->con->data;
-
- /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though
- * strictly speaking, it is a posechannel)
- */
- BKE_constraint_target_matrix_get(depsgraph, scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
-
- /* and set and transform goal */
- mul_m4_m4m4(goal, goalinv, rootmat);
-
- copy_v3_v3(goalpos, goal[3]);
- copy_m3_m4(goalrot, goal);
- normalize_m3(goalrot);
-
- /* same for pole vector target */
- if (data->poletar) {
- BKE_constraint_target_matrix_get(depsgraph, scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
-
- if (data->flag & CONSTRAINT_IK_SETANGLE) {
- /* don't solve IK when we are setting the pole angle */
- break;
- }
- else {
- mul_m4_m4m4(goal, goalinv, rootmat);
- copy_v3_v3(polepos, goal[3]);
- poleconstrain = 1;
-
- /* for pole targets, we blend the result of the ik solver
- * instead of the target position, otherwise we can't get
- * a smooth transition */
- resultblend = 1;
- resultinf = target->con->enforce;
-
- if (data->flag & CONSTRAINT_IK_GETANGLE) {
- poleangledata = data;
- data->flag &= ~CONSTRAINT_IK_GETANGLE;
- }
- }
- }
-
- /* do we need blending? */
- if (!resultblend && target->con->enforce != 1.0f) {
- float q1[4], q2[4], q[4];
- float fac = target->con->enforce;
- float mfac = 1.0f - fac;
-
- pchan = tree->pchan[target->tip];
-
- /* end effector in world space */
- copy_m4_m4(end_pose, pchan->pose_mat);
- copy_v3_v3(end_pose[3], pchan->pose_tail);
- mul_m4_series(world_pose, goalinv, ob->obmat, end_pose);
-
- /* blend position */
- goalpos[0] = fac * goalpos[0] + mfac * world_pose[3][0];
- goalpos[1] = fac * goalpos[1] + mfac * world_pose[3][1];
- goalpos[2] = fac * goalpos[2] + mfac * world_pose[3][2];
-
- /* blend rotation */
- mat3_to_quat(q1, goalrot);
- mat4_to_quat(q2, world_pose);
- interp_qt_qtqt(q, q1, q2, mfac);
- quat_to_mat3(goalrot, q);
- }
-
- iktarget = iktree[target->tip];
-
- if ((data->flag & CONSTRAINT_IK_POS) && data->weight != 0.0f) {
- if (poleconstrain)
- IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos,
- polepos, data->poleangle, (poleangledata == data));
- IK_SolverAddGoal(solver, iktarget, goalpos, data->weight);
- }
- if ((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0f))
- if ((data->flag & CONSTRAINT_IK_AUTO) == 0)
- IK_SolverAddGoalOrientation(solver, iktarget, goalrot,
- data->orientweight);
- }
-
- /* solve */
- IK_Solve(solver, 0.0f, tree->iterations);
-
- if (poleangledata)
- poleangledata->poleangle = IK_SolverGetPoleAngle(solver);
-
- IK_FreeSolver(solver);
-
- /* gather basis changes */
- tree->basis_change = MEM_mallocN(sizeof(float[3][3]) * tree->totchannel, "ik basis change");
- if (hasstretch)
- ikstretch = MEM_mallocN(sizeof(float) * tree->totchannel, "ik stretch");
-
- for (a = 0; a < tree->totchannel; a++) {
- IK_GetBasisChange(iktree[a], tree->basis_change[a]);
-
- if (hasstretch) {
- /* have to compensate for scaling received from parent */
- float parentstretch, stretch;
-
- pchan = tree->pchan[a];
- parentstretch = (tree->parent[a] >= 0) ? ikstretch[tree->parent[a]] : 1.0f;
-
- if (tree->stretch && (pchan->ikstretch > 0.0f)) {
- float trans[3], length;
-
- IK_GetTranslationChange(iktree[a], trans);
- length = pchan->bone->length * len_v3(pchan->pose_mat[1]);
-
- ikstretch[a] = (length == 0.0f) ? 1.0f : (trans[1] + length) / length;
- }
- else
- ikstretch[a] = 1.0;
-
- stretch = (parentstretch == 0.0f) ? 1.0f : ikstretch[a] / parentstretch;
-
- mul_v3_fl(tree->basis_change[a][0], stretch);
- mul_v3_fl(tree->basis_change[a][1], stretch);
- mul_v3_fl(tree->basis_change[a][2], stretch);
- }
-
- if (resultblend && resultinf != 1.0f) {
- unit_m3(identity);
- blend_m3_m3m3(tree->basis_change[a], identity,
- tree->basis_change[a], resultinf);
- }
-
- IK_FreeSegment(iktree[a]);
- }
-
- MEM_freeN(iktree);
- if (ikstretch) MEM_freeN(ikstretch);
+ float R_parmat[3][3], identity[3][3];
+ float iR_parmat[3][3];
+ float R_bonemat[3][3];
+ float goalrot[3][3], goalpos[3];
+ float rootmat[4][4], imat[4][4];
+ float goal[4][4], goalinv[4][4];
+ float irest_basis[3][3], full_basis[3][3];
+ float end_pose[4][4], world_pose[4][4];
+ float basis[3][3], rest_basis[3][3], start[3], *ikstretch = NULL;
+ float resultinf = 0.0f;
+ int a, flag, hasstretch = 0, resultblend = 0;
+ bPoseChannel *pchan;
+ IK_Segment *seg, *parent, **iktree, *iktarget;
+ IK_Solver *solver;
+ PoseTarget *target;
+ bKinematicConstraint *data, *poleangledata = NULL;
+ Bone *bone;
+
+ if (tree->totchannel == 0)
+ return;
+
+ iktree = MEM_mallocN(sizeof(void *) * tree->totchannel, "ik tree");
+
+ for (a = 0; a < tree->totchannel; a++) {
+ float length;
+ pchan = tree->pchan[a];
+ bone = pchan->bone;
+
+ /* set DoF flag */
+ flag = 0;
+ if (!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP))
+ flag |= IK_XDOF;
+ if (!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP))
+ flag |= IK_YDOF;
+ if (!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP))
+ flag |= IK_ZDOF;
+
+ if (tree->stretch && (pchan->ikstretch > 0.0f)) {
+ flag |= IK_TRANS_YDOF;
+ hasstretch = 1;
+ }
+
+ seg = iktree[a] = IK_CreateSegment(flag);
+
+ /* find parent */
+ if (a == 0)
+ parent = NULL;
+ else
+ parent = iktree[tree->parent[a]];
+
+ IK_SetParent(seg, parent);
+
+ /* get the matrix that transforms from prevbone into this bone */
+ copy_m3_m4(R_bonemat, pchan->pose_mat);
+
+ /* gather transformations for this IK segment */
+
+ if (pchan->parent)
+ copy_m3_m4(R_parmat, pchan->parent->pose_mat);
+ else
+ unit_m3(R_parmat);
+
+ /* bone offset */
+ if (pchan->parent && (a > 0))
+ sub_v3_v3v3(start, pchan->pose_head, pchan->parent->pose_tail);
+ else
+ /* only root bone (a = 0) has no parent */
+ start[0] = start[1] = start[2] = 0.0f;
+
+ /* change length based on bone size */
+ length = bone->length * len_v3(R_bonemat[1]);
+
+ /* basis must be pure rotation */
+ normalize_m3(R_bonemat);
+ normalize_m3(R_parmat);
+
+ /* compute rest basis and its inverse */
+ copy_m3_m3(rest_basis, bone->bone_mat);
+ transpose_m3_m3(irest_basis, bone->bone_mat);
+
+ /* compute basis with rest_basis removed */
+ invert_m3_m3(iR_parmat, R_parmat);
+ mul_m3_m3m3(full_basis, iR_parmat, R_bonemat);
+ mul_m3_m3m3(basis, irest_basis, full_basis);
+
+ /* transform offset into local bone space */
+ mul_m3_v3(iR_parmat, start);
+
+ IK_SetTransform(seg, start, rest_basis, basis, length);
+
+ if (pchan->ikflag & BONE_IK_XLIMIT)
+ IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]);
+ if (pchan->ikflag & BONE_IK_YLIMIT)
+ IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]);
+ if (pchan->ikflag & BONE_IK_ZLIMIT)
+ IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]);
+
+ IK_SetStiffness(seg, IK_X, pchan->stiffness[0]);
+ IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]);
+ IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]);
+
+ if (tree->stretch && (pchan->ikstretch > 0.0f)) {
+ const float ikstretch_sq = SQUARE(pchan->ikstretch);
+ /* this function does its own clamping */
+ IK_SetStiffness(seg, IK_TRANS_Y, 1.0f - ikstretch_sq);
+ IK_SetLimit(seg, IK_TRANS_Y, IK_STRETCH_STIFF_MIN, IK_STRETCH_STIFF_MAX);
+ }
+ }
+
+ solver = IK_CreateSolver(iktree[0]);
+
+ /* set solver goals */
+
+ /* first set the goal inverse transform, assuming the root of tree was done ok! */
+ pchan = tree->pchan[0];
+ if (pchan->parent) {
+ /* transform goal by parent mat, so this rotation is not part of the
+ * segment's basis. otherwise rotation limits do not work on the
+ * local transform of the segment itself. */
+ copy_m4_m4(rootmat, pchan->parent->pose_mat);
+ /* However, we do not want to get (i.e. reverse) parent's scale, as it generates [#31008]
+ * kind of nasty bugs... */
+ normalize_m4(rootmat);
+ }
+ else
+ unit_m4(rootmat);
+ copy_v3_v3(rootmat[3], pchan->pose_head);
+
+ mul_m4_m4m4(imat, ob->obmat, rootmat);
+ invert_m4_m4(goalinv, imat);
+
+ for (target = tree->targets.first; target; target = target->next) {
+ float polepos[3];
+ int poleconstrain = 0;
+
+ data = (bKinematicConstraint *)target->con->data;
+
+ /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though
+ * strictly speaking, it is a posechannel)
+ */
+ BKE_constraint_target_matrix_get(
+ depsgraph, scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
+
+ /* and set and transform goal */
+ mul_m4_m4m4(goal, goalinv, rootmat);
+
+ copy_v3_v3(goalpos, goal[3]);
+ copy_m3_m4(goalrot, goal);
+ normalize_m3(goalrot);
+
+ /* same for pole vector target */
+ if (data->poletar) {
+ BKE_constraint_target_matrix_get(
+ depsgraph, scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
+
+ if (data->flag & CONSTRAINT_IK_SETANGLE) {
+ /* don't solve IK when we are setting the pole angle */
+ break;
+ }
+ else {
+ mul_m4_m4m4(goal, goalinv, rootmat);
+ copy_v3_v3(polepos, goal[3]);
+ poleconstrain = 1;
+
+ /* for pole targets, we blend the result of the ik solver
+ * instead of the target position, otherwise we can't get
+ * a smooth transition */
+ resultblend = 1;
+ resultinf = target->con->enforce;
+
+ if (data->flag & CONSTRAINT_IK_GETANGLE) {
+ poleangledata = data;
+ data->flag &= ~CONSTRAINT_IK_GETANGLE;
+ }
+ }
+ }
+
+ /* do we need blending? */
+ if (!resultblend && target->con->enforce != 1.0f) {
+ float q1[4], q2[4], q[4];
+ float fac = target->con->enforce;
+ float mfac = 1.0f - fac;
+
+ pchan = tree->pchan[target->tip];
+
+ /* end effector in world space */
+ copy_m4_m4(end_pose, pchan->pose_mat);
+ copy_v3_v3(end_pose[3], pchan->pose_tail);
+ mul_m4_series(world_pose, goalinv, ob->obmat, end_pose);
+
+ /* blend position */
+ goalpos[0] = fac * goalpos[0] + mfac * world_pose[3][0];
+ goalpos[1] = fac * goalpos[1] + mfac * world_pose[3][1];
+ goalpos[2] = fac * goalpos[2] + mfac * world_pose[3][2];
+
+ /* blend rotation */
+ mat3_to_quat(q1, goalrot);
+ mat4_to_quat(q2, world_pose);
+ interp_qt_qtqt(q, q1, q2, mfac);
+ quat_to_mat3(goalrot, q);
+ }
+
+ iktarget = iktree[target->tip];
+
+ if ((data->flag & CONSTRAINT_IK_POS) && data->weight != 0.0f) {
+ if (poleconstrain)
+ IK_SolverSetPoleVectorConstraint(
+ solver, iktarget, goalpos, polepos, data->poleangle, (poleangledata == data));
+ IK_SolverAddGoal(solver, iktarget, goalpos, data->weight);
+ }
+ if ((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0f))
+ if ((data->flag & CONSTRAINT_IK_AUTO) == 0)
+ IK_SolverAddGoalOrientation(solver, iktarget, goalrot, data->orientweight);
+ }
+
+ /* solve */
+ IK_Solve(solver, 0.0f, tree->iterations);
+
+ if (poleangledata)
+ poleangledata->poleangle = IK_SolverGetPoleAngle(solver);
+
+ IK_FreeSolver(solver);
+
+ /* gather basis changes */
+ tree->basis_change = MEM_mallocN(sizeof(float[3][3]) * tree->totchannel, "ik basis change");
+ if (hasstretch)
+ ikstretch = MEM_mallocN(sizeof(float) * tree->totchannel, "ik stretch");
+
+ for (a = 0; a < tree->totchannel; a++) {
+ IK_GetBasisChange(iktree[a], tree->basis_change[a]);
+
+ if (hasstretch) {
+ /* have to compensate for scaling received from parent */
+ float parentstretch, stretch;
+
+ pchan = tree->pchan[a];
+ parentstretch = (tree->parent[a] >= 0) ? ikstretch[tree->parent[a]] : 1.0f;
+
+ if (tree->stretch && (pchan->ikstretch > 0.0f)) {
+ float trans[3], length;
+
+ IK_GetTranslationChange(iktree[a], trans);
+ length = pchan->bone->length * len_v3(pchan->pose_mat[1]);
+
+ ikstretch[a] = (length == 0.0f) ? 1.0f : (trans[1] + length) / length;
+ }
+ else
+ ikstretch[a] = 1.0;
+
+ stretch = (parentstretch == 0.0f) ? 1.0f : ikstretch[a] / parentstretch;
+
+ mul_v3_fl(tree->basis_change[a][0], stretch);
+ mul_v3_fl(tree->basis_change[a][1], stretch);
+ mul_v3_fl(tree->basis_change[a][2], stretch);
+ }
+
+ if (resultblend && resultinf != 1.0f) {
+ unit_m3(identity);
+ blend_m3_m3m3(tree->basis_change[a], identity, tree->basis_change[a], resultinf);
+ }
+
+ IK_FreeSegment(iktree[a]);
+ }
+
+ MEM_freeN(iktree);
+ if (ikstretch)
+ MEM_freeN(ikstretch);
}
static void free_posetree(PoseTree *tree)
{
- BLI_freelistN(&tree->targets);
- if (tree->pchan) MEM_freeN(tree->pchan);
- if (tree->parent) MEM_freeN(tree->parent);
- if (tree->basis_change) MEM_freeN(tree->basis_change);
- MEM_freeN(tree);
+ BLI_freelistN(&tree->targets);
+ if (tree->pchan)
+ MEM_freeN(tree->pchan);
+ if (tree->parent)
+ MEM_freeN(tree->parent);
+ if (tree->basis_change)
+ MEM_freeN(tree->basis_change);
+ MEM_freeN(tree);
}
///----------------------------------------
/// Plugin API for legacy iksolver
-void iksolver_initialize_tree(struct Depsgraph *UNUSED(depsgraph), struct Scene *UNUSED(scene), struct Object *ob, float UNUSED(ctime))
+void iksolver_initialize_tree(struct Depsgraph *UNUSED(depsgraph),
+ struct Scene *UNUSED(scene),
+ struct Object *ob,
+ float UNUSED(ctime))
{
- bPoseChannel *pchan;
+ bPoseChannel *pchan;
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->constflag & PCHAN_HAS_IK) // flag is set on editing constraints
- initialize_posetree(ob, pchan); // will attach it to root!
- }
- ob->pose->flag &= ~POSE_WAS_REBUILT;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->constflag & PCHAN_HAS_IK) // flag is set on editing constraints
+ initialize_posetree(ob, pchan); // will attach it to root!
+ }
+ ob->pose->flag &= ~POSE_WAS_REBUILT;
}
-void iksolver_execute_tree(struct Depsgraph *depsgraph, struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+void iksolver_execute_tree(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan_root,
+ float ctime)
{
- while (pchan_root->iktree.first) {
- PoseTree *tree = pchan_root->iktree.first;
- int a;
-
- /* stop on the first tree that isn't a standard IK chain */
- if (tree->type != CONSTRAINT_TYPE_KINEMATIC)
- return;
-
- /* 4. walk over the tree for regular solving */
- for (a = 0; a < tree->totchannel; a++) {
- if (!(tree->pchan[a]->flag & POSE_DONE)) // successive trees can set the flag
- BKE_pose_where_is_bone(depsgraph, scene, ob, tree->pchan[a], ctime, 1);
- /* tell blender that this channel was controlled by IK, it's cleared on each BKE_pose_where_is() */
- tree->pchan[a]->flag |= POSE_CHAIN;
- }
-
- /* 5. execute the IK solver */
- execute_posetree(depsgraph, scene, ob, tree);
-
- /* 6. apply the differences to the channels,
- * we need to calculate the original differences first */
- for (a = 0; a < tree->totchannel; a++) {
- make_dmats(tree->pchan[a]);
- }
-
- for (a = 0; a < tree->totchannel; a++) {
- /* sets POSE_DONE */
- where_is_ik_bone(tree->pchan[a], tree->basis_change[a]);
- }
-
- /* 7. and free */
- BLI_remlink(&pchan_root->iktree, tree);
- free_posetree(tree);
- }
+ while (pchan_root->iktree.first) {
+ PoseTree *tree = pchan_root->iktree.first;
+ int a;
+
+ /* stop on the first tree that isn't a standard IK chain */
+ if (tree->type != CONSTRAINT_TYPE_KINEMATIC)
+ return;
+
+ /* 4. walk over the tree for regular solving */
+ for (a = 0; a < tree->totchannel; a++) {
+ if (!(tree->pchan[a]->flag & POSE_DONE)) // successive trees can set the flag
+ BKE_pose_where_is_bone(depsgraph, scene, ob, tree->pchan[a], ctime, 1);
+ /* tell blender that this channel was controlled by IK, it's cleared on each BKE_pose_where_is() */
+ tree->pchan[a]->flag |= POSE_CHAIN;
+ }
+
+ /* 5. execute the IK solver */
+ execute_posetree(depsgraph, scene, ob, tree);
+
+ /* 6. apply the differences to the channels,
+ * we need to calculate the original differences first */
+ for (a = 0; a < tree->totchannel; a++) {
+ make_dmats(tree->pchan[a]);
+ }
+
+ for (a = 0; a < tree->totchannel; a++) {
+ /* sets POSE_DONE */
+ where_is_ik_bone(tree->pchan[a], tree->basis_change[a]);
+ }
+
+ /* 7. and free */
+ BLI_remlink(&pchan_root->iktree, tree);
+ free_posetree(tree);
+ }
}
-void iksolver_release_tree(struct Scene *UNUSED(scene), struct Object *ob, float UNUSED(ctime))
+void iksolver_release_tree(struct Scene *UNUSED(scene), struct Object *ob, float UNUSED(ctime))
{
- iksolver_clear_data(ob->pose);
+ iksolver_clear_data(ob->pose);
}
void iksolver_clear_data(bPose *pose)
{
- for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->flag & POSE_IKTREE) == 0)
- continue;
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((pchan->flag & POSE_IKTREE) == 0)
+ continue;
- while (pchan->iktree.first) {
- PoseTree *tree = pchan->iktree.first;
+ while (pchan->iktree.first) {
+ PoseTree *tree = pchan->iktree.first;
- /* stop on the first tree that isn't a standard IK chain */
- if (tree->type != CONSTRAINT_TYPE_KINEMATIC)
- break;
+ /* stop on the first tree that isn't a standard IK chain */
+ if (tree->type != CONSTRAINT_TYPE_KINEMATIC)
+ break;
- BLI_remlink(&pchan->iktree, tree);
- free_posetree(tree);
- }
- }
+ BLI_remlink(&pchan->iktree, tree);
+ free_posetree(tree);
+ }
+ }
}