1452 lines
32 KiB
C
1452 lines
32 KiB
C
/**
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version. The Blender
|
|
* Foundation also sells licenses for use in proprietary software under
|
|
* the Blender License. See http://www.blender.org/BL/ for information
|
|
* about this.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "nla.h"
|
|
|
|
#include "BLI_arithb.h"
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_armature_types.h"
|
|
#include "DNA_action_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_view3d_types.h"
|
|
#include "DNA_constraint_types.h"
|
|
|
|
#include "BKE_displist.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_library.h"
|
|
#include "BKE_blender.h"
|
|
#include "BKE_armature.h"
|
|
#include "BKE_action.h"
|
|
#include "BKE_constraint.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_deform.h"
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BIF_editdeform.h"
|
|
|
|
#include "IK_solver.h"
|
|
|
|
/* Function prototypes */
|
|
|
|
static void apply_pose_bonechildren (Bone* bone, bPose* pose, int doit);
|
|
static float dist_to_bone (float vec[3], float b1[3], float b2[3]);
|
|
static Bone *get_named_bone_bonechildren (Bone *bone, const char *name);
|
|
static Bone *get_indexed_bone_bonechildren (Bone *bone, int *index);
|
|
/*void make_bone_parent_matrix (Bone* bone);*/
|
|
static void copy_bonechildren (Bone* newBone, Bone* oldBone);
|
|
static void calc_armature_deform_bonechildren (Bone *bone, float *vec, float *co, float *contrib, float obmat[][4]);
|
|
static int verify_boneptr_children (Bone *cBone, Bone *tBone);
|
|
static void where_is_bonelist_time (Object *ob, ListBase *base, float ctime);
|
|
static Bone *get_last_ik_bone (Bone *bone);
|
|
static void precalc_bonelist_posemats(ListBase *bonelist, float parlen);
|
|
|
|
/* Globals */
|
|
static float g_premat[4][4];
|
|
static float g_postmat[4][4];
|
|
static MDeformVert *g_dverts;
|
|
static ListBase *g_defbase;
|
|
static bArmature *g_defarm;
|
|
|
|
/* Functions */
|
|
|
|
float get_bone_length (Bone *bone)
|
|
{
|
|
float result[3];
|
|
|
|
VecSubf (result, bone->tail, bone->head);
|
|
return (float)sqrt(result[0]*result[0] + result[1]*result[1] + result[2]*result[2]);
|
|
|
|
}
|
|
|
|
void apply_bonemat(Bone *bone)
|
|
{
|
|
float mat[3][3], imat[3][3], tmat[3][3];
|
|
|
|
if(!bone)
|
|
return;
|
|
|
|
Mat3CpyMat4(mat, bone->obmat);
|
|
|
|
VECCOPY(bone->loc, bone->obmat[3]);
|
|
|
|
Mat3ToQuat(mat, bone->quat);
|
|
QuatToMat3(bone->quat, tmat);
|
|
|
|
Mat3Inv(imat, tmat);
|
|
|
|
Mat3MulMat3(tmat, imat, mat);
|
|
|
|
bone->size[0]= tmat[0][0];
|
|
bone->size[1]= tmat[1][1];
|
|
bone->size[2]= tmat[2][2];
|
|
|
|
}
|
|
|
|
void GB_build_mats (float parmat[][4], float obmat[][4], float premat[][4], float postmat[][4])
|
|
{
|
|
float obinv[4][4];
|
|
#if 0
|
|
Mat4Invert(obinv, obmat);
|
|
Mat4CpyMat4(premat, obmat);
|
|
Mat4MulMat4(postmat, parmat, obinv);
|
|
|
|
Mat4Invert (postmat, premat);
|
|
#else
|
|
Mat4Invert(obinv, obmat);
|
|
Mat4CpyMat4(premat, obmat);
|
|
Mat4MulMat4(postmat, parmat, obinv);
|
|
|
|
Mat4Invert (premat, postmat);
|
|
#endif
|
|
}
|
|
|
|
void GB_init_armature_deform(ListBase *defbase, float premat[][4], float postmat[][4])
|
|
{
|
|
g_defbase = defbase;
|
|
Mat4CpyMat4 (g_premat, premat);
|
|
Mat4CpyMat4 (g_postmat, postmat);
|
|
|
|
}
|
|
|
|
void GB_validate_defgroups (Mesh *mesh, ListBase *defbase)
|
|
{
|
|
/* Should only be called when the mesh or armature changes */
|
|
int j, i;
|
|
MDeformVert *dvert;
|
|
|
|
for (j=0; j<mesh->totvert; j++){
|
|
dvert = mesh->dvert+j;
|
|
for (i=0; i<dvert->totweight; i++)
|
|
dvert->dw[i].data = ((bDeformGroup*)BLI_findlink (defbase, dvert->dw[i].def_nr))->data;
|
|
}
|
|
}
|
|
|
|
void GB_calc_armature_deform (float *co, MDeformVert *dvert)
|
|
{
|
|
float vec[3]={0, 0, 0};
|
|
float contrib = 0;
|
|
int i;
|
|
Bone *bone;
|
|
|
|
Mat4MulVecfl(g_premat, co);
|
|
|
|
for (i=0; i<dvert->totweight; i++){
|
|
bone = dvert->dw[i].data;
|
|
if (bone) calc_bone_deform (bone, dvert->dw[i].weight, vec, co, &contrib);
|
|
}
|
|
|
|
if (contrib){
|
|
vec[0]/=contrib;
|
|
vec[1]/=contrib;
|
|
vec[2]/=contrib;
|
|
}
|
|
|
|
VecAddf (co, vec, co);
|
|
Mat4MulVecfl(g_postmat, co);
|
|
}
|
|
|
|
static Bone *get_last_ik_bone (Bone *bone)
|
|
{
|
|
Bone *curBone;
|
|
|
|
for (curBone = bone->childbase.first; curBone; curBone=curBone->next){
|
|
if (curBone->flag & BONE_IK_TOPARENT){
|
|
return get_last_ik_bone (curBone);
|
|
}
|
|
}
|
|
|
|
return bone;
|
|
}
|
|
|
|
#if 0
|
|
static Bone *get_first_ik_bone (Bone *bone)
|
|
{
|
|
Bone *curBone;
|
|
|
|
for (curBone = bone; curBone; curBone=curBone->parent){
|
|
if (!bone->parent)
|
|
return curBone;
|
|
if (!bone->flag & BONE_IK_TOPARENT)
|
|
return curBone;
|
|
}
|
|
|
|
return bone;
|
|
/* for (curBone = bone->childbase.first; curBone; curBone=curBone->next){
|
|
if (curBone->flag & BONE_IK_TOPARENT){
|
|
return get_last_ik_bone (curBone);
|
|
}
|
|
}
|
|
*/
|
|
return bone;
|
|
|
|
}
|
|
#endif
|
|
|
|
void where_is_bone(Object *ob, Bone *bone)
|
|
{
|
|
where_is_bone_time (ob, bone, G.scene->r.cfra);
|
|
}
|
|
|
|
void where_is_bone_time (Object *ob, Bone *bone, float ctime)
|
|
{
|
|
where_is_bone1_time (ob, get_last_ik_bone(bone), ctime);
|
|
}
|
|
|
|
void rebuild_bone_parent_matrix (Bone *bone)
|
|
{
|
|
if (!bone)
|
|
return;
|
|
|
|
if (bone->parent)
|
|
rebuild_bone_parent_matrix(bone->parent);
|
|
|
|
/* Get the parent inverse */
|
|
if (bone->parent)
|
|
Mat4MulMat4(bone->parmat, bone->parent->obmat, bone->parent->parmat);
|
|
else
|
|
Mat4One (bone->parmat);
|
|
|
|
}
|
|
void where_is_bone1_time (Object *ob, Bone *bone, float ctime)
|
|
/* Assumes the pose has already been retrieved from the action */
|
|
/* Also assumes where_is_object has been called for owner */
|
|
{
|
|
bPose *pose;
|
|
bPoseChannel *chan;
|
|
bArmature *arm;
|
|
float imat[4][4];
|
|
float totmat[4][4];
|
|
Object conOb;
|
|
|
|
pose = ob->pose;
|
|
if (!pose)
|
|
return;
|
|
|
|
arm = get_armature(ob);
|
|
|
|
/* Ensure there is achannel for this bone*/
|
|
verify_pose_channel (pose, bone->name);
|
|
|
|
/* Search the pose for a channel with the same name, and copy the
|
|
transformations from the channel into the bone */
|
|
for (chan=pose->chanbase.first; chan; chan=chan->next){
|
|
if (!strcmp (chan->name, bone->name)){
|
|
|
|
#if 1 /* If 1 attempt to use pose caching features */
|
|
/* Bail out if we've been recalced recently */
|
|
if (chan->flag & PCHAN_DONE){
|
|
Mat4CpyMat4 (bone->obmat, chan->obmat);
|
|
if (bone->parent){
|
|
if ((bone->flag & BONE_IK_TOPARENT))
|
|
where_is_bone1_time (ob, bone->parent, ctime);
|
|
else
|
|
where_is_bone_time (ob, bone->parent, ctime);
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
chan->flag |= PCHAN_DONE;
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if 1
|
|
/* Ensure parents have been evaluated */
|
|
if (bone->parent){
|
|
if ((bone->flag & BONE_IK_TOPARENT))
|
|
where_is_bone1_time (ob, bone->parent, ctime);
|
|
else
|
|
where_is_bone_time (ob, bone->parent, ctime);
|
|
}
|
|
|
|
/* Build the parent matrix : Depreciated */
|
|
// if (bone->parent)
|
|
// Mat4MulMat4(bone->parmat, bone->parent->obmat, bone->parent->parmat);
|
|
// else
|
|
// Mat4One (bone->parmat);
|
|
#endif
|
|
|
|
if (arm){
|
|
if ((arm->flag & ARM_RESTPOS) || ((G.obedit && (ob->data == G.obedit->data)))){
|
|
Mat4One (bone->obmat);
|
|
Mat4One (chan->obmat);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (bone->flag & BONE_IK_TOPARENT){
|
|
bone->loc[0]=bone->loc[1]=bone->loc[2]=0.0F;
|
|
}
|
|
bone_to_mat4(bone, bone->obmat);
|
|
|
|
/* Do constraints */
|
|
// clear_workob();
|
|
|
|
memset(&conOb, 0, sizeof(Object));
|
|
conOb.size[0]= conOb.size[1]= conOb.size[2]= 1.0;
|
|
|
|
/* Collect the constraints from the pose */
|
|
conOb.constraints.first = chan->constraints.first;
|
|
conOb.constraints.last = chan->constraints.last;
|
|
|
|
/* Totmat takes bone's obmat to worldspace */
|
|
|
|
{
|
|
float parmat[4][4];
|
|
float temp[4][4];
|
|
|
|
Mat4CpyMat4 (temp, bone->obmat);
|
|
Mat4One (bone->obmat);
|
|
get_objectspace_bone_matrix(bone, parmat, 1, 1);
|
|
Mat4CpyMat4 (bone->obmat, temp);
|
|
Mat4MulMat4 (totmat, parmat, ob->obmat);
|
|
}
|
|
|
|
/* Build a workob to pass the bone to the constraint solver */
|
|
conOb.data = ob->data;
|
|
conOb.type = ob->type;
|
|
conOb.parent = ob;
|
|
conOb.trackflag = ob->trackflag;
|
|
conOb.upflag = ob->upflag;
|
|
|
|
VECCOPY(conOb.size, bone->size);
|
|
|
|
Mat4MulMat4 (conOb.obmat, bone->obmat, totmat);
|
|
|
|
/* Solve */
|
|
solve_constraints (&conOb, TARGET_BONE, (void*)bone, ctime);
|
|
|
|
{
|
|
float parmat[4][4];
|
|
float temp[4][4];
|
|
|
|
Mat4CpyMat4 (temp, bone->obmat);
|
|
Mat4One (bone->obmat);
|
|
get_objectspace_bone_matrix(bone, parmat, 1, 1);
|
|
Mat4CpyMat4 (bone->obmat, temp);
|
|
Mat4MulMat4 (totmat, parmat, ob->obmat);
|
|
}
|
|
|
|
VECCOPY(bone->size, conOb.size);
|
|
|
|
/* Take out of worldspace */
|
|
Mat4Invert (imat, totmat);
|
|
Mat4MulMat4 (bone->obmat, conOb.obmat, imat);
|
|
Mat4CpyMat4 (chan->obmat, bone->obmat);
|
|
|
|
}
|
|
|
|
|
|
bArmature *get_armature(Object *ob)
|
|
{
|
|
if(ob==NULL) return NULL;
|
|
if(ob->type==OB_ARMATURE) return ob->data;
|
|
else return NULL;
|
|
}
|
|
|
|
void init_armature_deform(Object *parent, Object *ob)
|
|
{
|
|
bArmature *arm;
|
|
bDeformGroup *dg;
|
|
Bone *curBone;
|
|
MDeformVert *dvert;
|
|
int totverts;
|
|
float obinv[4][4];
|
|
int i, j;
|
|
|
|
arm = get_armature(parent);
|
|
if (!arm)
|
|
return;
|
|
|
|
if (ob)
|
|
where_is_object (ob);
|
|
|
|
#if 1
|
|
apply_pose_armature (arm, parent->pose, 1); /* Hopefully doit parameter can be set to 0 in future */
|
|
where_is_armature (parent);
|
|
#else
|
|
apply_pose_armature (arm, parent->pose, 0);
|
|
#endif
|
|
|
|
g_defbase = &ob->defbase;
|
|
g_defarm = arm;
|
|
|
|
Mat4Invert(obinv, ob->obmat);
|
|
Mat4CpyMat4(g_premat, ob->obmat);
|
|
Mat4MulMat4(g_postmat, parent->obmat, obinv);
|
|
|
|
Mat4Invert (g_premat, g_postmat);
|
|
|
|
/* Store the deformation verts */
|
|
if (ob->type==OB_MESH){
|
|
g_dverts = ((Mesh*)ob->data)->dvert;
|
|
totverts = ((Mesh*)ob->data)->totvert;
|
|
}
|
|
else{
|
|
g_dverts=NULL;
|
|
totverts=0;
|
|
}
|
|
|
|
/* Precalc bone defmats */
|
|
precalc_armature_posemats (arm);
|
|
|
|
for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
|
|
precalc_bone_defmat(curBone);
|
|
}
|
|
|
|
/* Validate bone data in bDeformGroups */
|
|
|
|
for (dg=g_defbase->first; dg; dg=dg->next)
|
|
dg->data = (void*)get_named_bone(arm, dg->name);
|
|
|
|
if (g_dverts){
|
|
for (j=0; j<totverts; j++){
|
|
dvert = g_dverts+j;
|
|
for (i=0; i<dvert->totweight; i++){
|
|
bDeformGroup *fg;
|
|
fg = BLI_findlink (g_defbase, dvert->dw[i].def_nr);
|
|
|
|
if (fg)
|
|
dvert->dw[i].data = fg->data;
|
|
else
|
|
dvert->dw[i].data = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void get_bone_root_pos (Bone* bone, float vec[3], int posed)
|
|
{
|
|
Bone *curBone;
|
|
float mat[4][4];
|
|
|
|
get_objectspace_bone_matrix(bone, mat, 1, posed);
|
|
VECCOPY (vec, mat[3]);
|
|
return;
|
|
|
|
rebuild_bone_parent_matrix(bone);
|
|
if (posed){
|
|
|
|
get_objectspace_bone_matrix(bone, mat, 1, posed);
|
|
VECCOPY (vec, mat[3]);
|
|
}
|
|
else {
|
|
vec[0]=vec[1]=vec[2]=0.0F;
|
|
for (curBone=bone; curBone; curBone=curBone->parent){
|
|
if (curBone==bone)
|
|
VecAddf (vec, vec, curBone->head);
|
|
else
|
|
VecAddf (vec, vec, curBone->tail);
|
|
}
|
|
}
|
|
}
|
|
|
|
void get_bone_tip_pos (Bone* bone, float vec[3], int posed)
|
|
{
|
|
Bone *curBone;
|
|
float mat[4][4], tmat[4][4], rmat[4][4], bmat[4][4], fmat[4][4];
|
|
|
|
get_objectspace_bone_matrix(bone, mat, 0, posed);
|
|
VECCOPY (vec, mat[3]);
|
|
return;
|
|
|
|
rebuild_bone_parent_matrix(bone);
|
|
if (posed){
|
|
|
|
Mat4One (mat);
|
|
|
|
for (curBone = bone; curBone; curBone=curBone->parent){
|
|
Mat4One (bmat);
|
|
/* [BMAT] This bone's offset */
|
|
VECCOPY (bmat[3], curBone->head);
|
|
if (curBone==bone){
|
|
Mat4One (tmat);
|
|
VecSubf (tmat[3], curBone->tail, curBone->head);
|
|
Mat4MulMat4 (bmat, tmat, curBone->obmat);
|
|
VecAddf (bmat[3], bmat[3], curBone->head);
|
|
}
|
|
else
|
|
VecAddf (bmat[3], bmat[3], curBone->obmat[3]); // Test
|
|
|
|
/* [RMAT] Parent's bone length = parent rotmat * bone length */
|
|
if (curBone->parent){
|
|
Mat4One (tmat);
|
|
VecSubf (tmat[3], curBone->parent->tail, curBone->parent->head);
|
|
Mat4MulMat4 (rmat, tmat, curBone->parent->obmat);
|
|
VecSubf (rmat[3], rmat[3], curBone->parent->obmat[3]);
|
|
}
|
|
else
|
|
Mat4One (rmat);
|
|
|
|
Mat4MulSerie (fmat, rmat, bmat, mat, 0, 0, 0, 0, 0);
|
|
Mat4CpyMat4 (mat, fmat);
|
|
}
|
|
|
|
VECCOPY (vec, mat[3]);
|
|
}
|
|
else{
|
|
vec[0]=vec[1]=vec[2]=0.0F;
|
|
for (curBone=bone; curBone; curBone=curBone->parent){
|
|
VecAddf (vec, vec, curBone->tail);
|
|
}
|
|
}
|
|
}
|
|
|
|
int verify_boneptr (bArmature *arm, Bone *bone)
|
|
{
|
|
/* Ensures that a given bone exists in an armature */
|
|
Bone *curBone;
|
|
|
|
if (!arm)
|
|
return 0;
|
|
|
|
for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
|
|
if (verify_boneptr_children (curBone, bone))
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int verify_boneptr_children (Bone *cBone, Bone *tBone)
|
|
{
|
|
Bone *curBone;
|
|
|
|
if (cBone == tBone)
|
|
return 1;
|
|
|
|
for (curBone=cBone->childbase.first; curBone; curBone=curBone->next){
|
|
if (verify_boneptr_children (curBone, tBone))
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static float dist_to_bone (float vec[3], float b1[3], float b2[3])
|
|
{
|
|
/* float dist=0; */
|
|
float bdelta[3];
|
|
float pdelta[3];
|
|
float hsqr, a, l;
|
|
|
|
VecSubf (bdelta, b2, b1);
|
|
l = Normalise (bdelta);
|
|
|
|
VecSubf (pdelta, vec, b1);
|
|
|
|
a = bdelta[0]*pdelta[0] + bdelta[1]*pdelta[1] + bdelta[2]*pdelta[2];
|
|
hsqr = ((pdelta[0]*pdelta[0]) + (pdelta[1]*pdelta[1]) + (pdelta[2]*pdelta[2]));
|
|
|
|
if (a < 0.0F){
|
|
//return 100000;
|
|
/* If we're past the end of the bone, do some weird field attenuation thing */
|
|
return ((b1[0]-vec[0])*(b1[0]-vec[0]) +(b1[1]-vec[1])*(b1[1]-vec[1]) +(b1[2]-vec[2])*(b1[2]-vec[2])) ;
|
|
}
|
|
else if (a > l){
|
|
//return 100000;
|
|
/* If we're past the end of the bone, do some weird field attenuation thing */
|
|
return ((b2[0]-vec[0])*(b2[0]-vec[0]) +(b2[1]-vec[1])*(b2[1]-vec[1]) +(b2[2]-vec[2])*(b2[2]-vec[2])) ;
|
|
}
|
|
else {
|
|
return (hsqr - (a*a));
|
|
}
|
|
|
|
|
|
}
|
|
|
|
static void calc_armature_deform_bonechildren (Bone *bone, float *vec, float *co, float *contrib, float obmat[][4])
|
|
{
|
|
Bone *curBone;
|
|
float root[3];
|
|
float tip[3];
|
|
float dist, fac, ifac;
|
|
float cop[3];
|
|
float bdsqr;
|
|
|
|
|
|
get_bone_root_pos (bone, root, 0);
|
|
get_bone_tip_pos (bone, tip, 0);
|
|
|
|
bdsqr = bone->dist*bone->dist;
|
|
VECCOPY (cop, co);
|
|
|
|
dist = dist_to_bone(cop, root, tip);
|
|
|
|
if ((dist) <= bdsqr){
|
|
fac = (dist)/bdsqr;
|
|
ifac = 1.0F-fac;
|
|
|
|
ifac*=bone->weight;
|
|
|
|
if (!vec)
|
|
(*contrib) +=ifac;
|
|
else{
|
|
ifac*=(1.0F/(*contrib));
|
|
|
|
VECCOPY (cop, co);
|
|
|
|
Mat4MulVecfl(bone->defmat, cop);
|
|
|
|
VecSubf (cop, cop, co); // Make this a delta from the base position
|
|
cop[0]*=ifac; cop[1]*=ifac; cop[2]*=ifac;
|
|
VecAddf (vec, vec, cop);
|
|
|
|
}
|
|
}
|
|
|
|
// calc_bone_deform (bone, bone->weight, vec, co, contrib, obmat);
|
|
for (curBone = bone->childbase.first; curBone; curBone=curBone->next)
|
|
calc_armature_deform_bonechildren (curBone, vec, co, contrib, obmat);
|
|
}
|
|
|
|
void precalc_bone_irestmat (Bone *bone)
|
|
{
|
|
float restmat[4][4];
|
|
|
|
get_objectspace_bone_matrix(bone, restmat, 1, 0);
|
|
Mat4Invert (bone->irestmat, restmat);
|
|
}
|
|
|
|
static void precalc_bonelist_posemats(ListBase *bonelist, float parlen)
|
|
{
|
|
Bone *curBone;
|
|
float length;
|
|
float T_parlen[4][4];
|
|
float T_root[4][4];
|
|
float M_obmat[4][4];
|
|
float R_bmat[4][4];
|
|
float M_accumulatedMatrix[4][4];
|
|
float delta[3];
|
|
|
|
for (curBone = bonelist->first; curBone; curBone=curBone->next){
|
|
|
|
/* Get the length translation (length along y axis) */
|
|
length = get_bone_length(curBone);
|
|
|
|
/* Get the bone's root offset (in the parent's coordinate system) */
|
|
Mat4One (T_root);
|
|
VECCOPY (T_root[3], curBone->head);
|
|
|
|
/* Compose the restmat */
|
|
VecSubf(delta, curBone->tail, curBone->head);
|
|
make_boneMatrixvr(R_bmat, delta, curBone->roll);
|
|
|
|
/* Retrieve the obmat (user transformation) */
|
|
Mat4CpyMat4 (M_obmat, curBone->obmat);
|
|
|
|
/* Compose the accumulated matrix (i.e. parent matrix * parent translation ) */
|
|
if (curBone->parent){
|
|
Mat4One (T_parlen);
|
|
T_parlen[3][1] = parlen;
|
|
Mat4MulMat4 (M_accumulatedMatrix, T_parlen, curBone->parent->posemat);
|
|
}
|
|
else
|
|
Mat4One (M_accumulatedMatrix);
|
|
|
|
/* Compose the matrix for this bone */
|
|
Mat4MulSerie (curBone->posemat, M_accumulatedMatrix, T_root, R_bmat, M_obmat, NULL, NULL, NULL, NULL);
|
|
|
|
precalc_bonelist_posemats(&curBone->childbase, length);
|
|
}
|
|
}
|
|
|
|
void precalc_armature_posemats (bArmature *arm)
|
|
{
|
|
precalc_bonelist_posemats(&arm->bonebase, 0.0);
|
|
}
|
|
|
|
void precalc_bone_defmat (Bone *bone)
|
|
{
|
|
Bone *curBone;
|
|
#if 0
|
|
float restmat[4][4];
|
|
float posemat[4][4];
|
|
float imat[4][4];
|
|
|
|
/* Store restmat and restmat inverse - Calculate once when leaving editmode */
|
|
/* Store all bones' posemats - Do when applied */
|
|
|
|
/* EXPENSIVE! Don't do this! */
|
|
get_objectspace_bone_matrix(bone, restmat, 1, 0);
|
|
get_objectspace_bone_matrix(bone, posemat, 1, 1);
|
|
Mat4Invert (imat, restmat);
|
|
Mat4MulMat4 (bone->defmat, imat, posemat);
|
|
/* /EXPENSIVE */
|
|
#else
|
|
Mat4MulMat4 (bone->defmat, bone->irestmat, bone->posemat);
|
|
#endif
|
|
for (curBone = bone->childbase.first; curBone; curBone=curBone->next){
|
|
precalc_bone_defmat(curBone);
|
|
}
|
|
}
|
|
|
|
void calc_bone_deform (Bone *bone, float weight, float *vec, float *co, float *contrib)
|
|
{
|
|
float cop[3];
|
|
|
|
if (!weight)
|
|
return;
|
|
|
|
VECCOPY (cop, co);
|
|
|
|
Mat4MulVecfl(bone->defmat, cop);
|
|
|
|
vec[0]+=(cop[0]-co[0])*weight;
|
|
vec[1]+=(cop[1]-co[1])*weight;
|
|
vec[2]+=(cop[2]-co[2])*weight;
|
|
|
|
(*contrib)+=weight;
|
|
}
|
|
|
|
void calc_armature_deform (Object *ob, float *co, int index)
|
|
{
|
|
bArmature *arm;
|
|
Bone *bone;
|
|
Bone *curBone;
|
|
float vec[3];
|
|
float contrib=0;
|
|
int i;
|
|
MDeformVert *dvert = g_dverts+index;
|
|
|
|
arm=g_defarm;
|
|
vec[0]=vec[1]=vec[2]=0;
|
|
|
|
/* Apply the object's matrix */
|
|
Mat4MulVecfl(g_premat, co);
|
|
|
|
if (g_dverts){
|
|
for (i=0; i<dvert->totweight; i++){
|
|
bone = dvert->dw[i].data;
|
|
if (bone) calc_bone_deform (bone, dvert->dw[i].weight, vec, co, &contrib);
|
|
}
|
|
|
|
if (contrib){
|
|
vec[0]/=contrib;
|
|
vec[1]/=contrib;
|
|
vec[2]/=contrib;
|
|
}
|
|
VecAddf (co, vec, co);
|
|
Mat4MulVecfl(g_postmat, co);
|
|
return;
|
|
}
|
|
|
|
|
|
// Count the number of interested bones
|
|
for (curBone = arm->bonebase.first; curBone; curBone=curBone->next)
|
|
calc_armature_deform_bonechildren (curBone, NULL, co, &contrib, ob->obmat);
|
|
|
|
// Do the deformation
|
|
for (curBone = arm->bonebase.first; curBone; curBone=curBone->next)
|
|
calc_armature_deform_bonechildren (curBone, vec, co, &contrib, ob->obmat);
|
|
|
|
VecAddf (co, vec, co);
|
|
Mat4MulVecfl(g_postmat, co);
|
|
}
|
|
|
|
void apply_pose_armature (bArmature* arm, bPose* pose, int doit)
|
|
{
|
|
Bone *curBone;
|
|
for (curBone = arm->bonebase.first; curBone; curBone=curBone->next){
|
|
apply_pose_bonechildren (curBone, pose, doit);
|
|
}
|
|
}
|
|
|
|
void where_is_armature (Object *ob)
|
|
{
|
|
where_is_object (ob);
|
|
where_is_armature_time(ob, (float)G.scene->r.cfra);
|
|
}
|
|
|
|
void where_is_armature_time (Object *ob, float ctime)
|
|
{
|
|
bArmature *arm;
|
|
|
|
arm = get_armature(ob);
|
|
if (!arm)
|
|
return;
|
|
|
|
where_is_bonelist_time (ob, &arm->bonebase, ctime);
|
|
|
|
}
|
|
|
|
static void where_is_bonelist_time (Object *ob, ListBase *base, float ctime)
|
|
{
|
|
Bone *curBone;
|
|
|
|
for (curBone=base->first; curBone; curBone=curBone->next){
|
|
if (!curBone->childbase.first)
|
|
where_is_bone1_time (ob, curBone, ctime);
|
|
|
|
where_is_bonelist_time(ob, &curBone->childbase, ctime);
|
|
}
|
|
}
|
|
static void apply_pose_bonechildren (Bone* bone, bPose* pose, int doit)
|
|
{
|
|
Bone *curBone;
|
|
bPoseChannel *chan;
|
|
|
|
if (!pose){
|
|
|
|
bone->dsize[0]=bone->dsize[1]=bone->dsize[2]=1.0F;
|
|
bone->size[0]=bone->size[1]=bone->size[2]=1.0F;
|
|
|
|
bone->dquat[0]=bone->dquat[1]=bone->dquat[2]=bone->dquat[3]=0;
|
|
bone->quat[0]=bone->quat[1]=bone->quat[2]=bone->quat[3]=0.0F;
|
|
|
|
bone->dloc[0]=bone->dloc[1]=bone->dloc[2]=0.0F;
|
|
bone->loc[0]=bone->loc[1]=bone->loc[2]=0.0F;
|
|
}
|
|
|
|
// Ensure there is achannel for this bone
|
|
verify_pose_channel (pose, bone->name);
|
|
|
|
// Search the pose for a channel with the same name
|
|
if (pose){
|
|
for (chan=pose->chanbase.first; chan; chan=chan->next){
|
|
if (!strcmp (chan->name, bone->name)){
|
|
if (chan->flag & POSE_LOC)
|
|
memcpy (bone->loc, chan->loc, sizeof (bone->loc));
|
|
if (chan->flag & POSE_SIZE)
|
|
memcpy (bone->size, chan->size, sizeof (bone->size));
|
|
if (chan->flag & POSE_ROT)
|
|
memcpy (bone->quat, chan->quat, sizeof (bone->quat));
|
|
|
|
if (doit){
|
|
bone_to_mat4(bone, bone->obmat);
|
|
}
|
|
else{
|
|
Mat4CpyMat4 (bone->obmat, chan->obmat);
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (curBone = bone->childbase.first; curBone; curBone=curBone->next){
|
|
apply_pose_bonechildren (curBone, pose, doit);
|
|
}
|
|
}
|
|
|
|
void make_boneMatrixvr (float outmatrix[][4],float delta[3], float roll)
|
|
/* Calculates the rest matrix of a bone based
|
|
On its vector and a roll around that vector */
|
|
{
|
|
float nor[3],axis[3],target[3]={0,1,0};
|
|
float theta;
|
|
float rMatrix[3][3], bMatrix[3][3], fMatrix[3][3];
|
|
|
|
VECCOPY (nor,delta);
|
|
Normalise (nor);
|
|
|
|
/* Find Axis & Amount for bone matrix*/
|
|
Crossf (axis,target,nor);
|
|
Normalise (axis);
|
|
theta=(float) acos (Inpf (target,nor));
|
|
|
|
/* Make Bone matrix*/
|
|
VecRotToMat3(axis, theta, bMatrix);
|
|
|
|
/* Make Roll matrix*/
|
|
VecRotToMat3(nor, roll, rMatrix);
|
|
|
|
/* Combine and output result*/
|
|
Mat3MulMat3 (fMatrix,rMatrix,bMatrix);
|
|
Mat4CpyMat3 (outmatrix,fMatrix);
|
|
}
|
|
|
|
void make_boneMatrix (float outmatrix[][4], Bone *bone)
|
|
/* Calculates the rest matrix of a bone based
|
|
On its vector and a roll around that vector */
|
|
{
|
|
float delta[3];
|
|
float parmat[4][4], imat[4][4], obmat[4][4];
|
|
|
|
if (bone->parent){
|
|
VecSubf (delta, bone->parent->tail, bone->parent->head);
|
|
make_boneMatrixvr(parmat, delta, bone->parent->roll);
|
|
}
|
|
else{
|
|
Mat4One (parmat);
|
|
}
|
|
|
|
Mat4Invert (imat, parmat);
|
|
|
|
VecSubf (delta, bone->tail, bone->head);
|
|
make_boneMatrixvr(obmat, delta, bone->roll);
|
|
|
|
Mat4MulMat4(outmatrix, obmat, imat);
|
|
|
|
}
|
|
|
|
|
|
bArmature *add_armature()
|
|
{
|
|
bArmature *arm;
|
|
|
|
arm= alloc_libblock (&G.main->armature, ID_AR, "Armature");
|
|
|
|
if(arm) {
|
|
|
|
|
|
}
|
|
return arm;
|
|
}
|
|
|
|
|
|
void free_boneChildren(Bone *bone)
|
|
{
|
|
Bone *child;
|
|
|
|
if (bone) {
|
|
|
|
child=bone->childbase.first;
|
|
if (child){
|
|
while (child){
|
|
free_boneChildren (child);
|
|
child=child->next;
|
|
}
|
|
BLI_freelistN (&bone->childbase);
|
|
}
|
|
}
|
|
}
|
|
|
|
void free_bones (bArmature *arm)
|
|
{
|
|
Bone *bone;
|
|
/* Free children (if any) */
|
|
bone= arm->bonebase.first;
|
|
if (bone) {
|
|
while (bone){
|
|
free_boneChildren (bone);
|
|
bone=bone->next;
|
|
}
|
|
}
|
|
|
|
|
|
BLI_freelistN(&arm->bonebase);
|
|
}
|
|
|
|
void free_armature(bArmature *arm)
|
|
{
|
|
if (arm) {
|
|
/* unlink_armature(arm);*/
|
|
free_bones(arm);
|
|
}
|
|
}
|
|
|
|
void make_local_armature(bArmature *arm)
|
|
{
|
|
int local=0, lib=0;
|
|
Object *ob;
|
|
bArmature *newArm;
|
|
|
|
if (arm->id.lib==0)
|
|
return;
|
|
if (arm->id.us==1) {
|
|
arm->id.lib= 0;
|
|
arm->id.flag= LIB_LOCAL;
|
|
new_id(0, (ID*)arm, 0);
|
|
return;
|
|
}
|
|
|
|
if(local && lib==0) {
|
|
arm->id.lib= 0;
|
|
arm->id.flag= LIB_LOCAL;
|
|
new_id(0, (ID *)arm, 0);
|
|
}
|
|
else if(local && lib) {
|
|
newArm= copy_armature(arm);
|
|
newArm->id.us= 0;
|
|
|
|
ob= G.main->object.first;
|
|
while(ob) {
|
|
if(ob->data==arm) {
|
|
|
|
if(ob->id.lib==0) {
|
|
ob->data= newArm;
|
|
newArm->id.us++;
|
|
arm->id.us--;
|
|
}
|
|
}
|
|
ob= ob->id.next;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void copy_bonechildren (Bone* newBone, Bone* oldBone)
|
|
{
|
|
Bone *curBone, *newChildBone;
|
|
|
|
/* Copy this bone's list*/
|
|
duplicatelist (&newBone->childbase, &oldBone->childbase);
|
|
|
|
/* For each child in the list, update it's children*/
|
|
newChildBone=newBone->childbase.first;
|
|
for (curBone=oldBone->childbase.first;curBone;curBone=curBone->next){
|
|
newChildBone->parent=newBone;
|
|
copy_bonechildren(newChildBone,curBone);
|
|
newChildBone=newChildBone->next;
|
|
}
|
|
}
|
|
|
|
bArmature *copy_armature(bArmature *arm)
|
|
{
|
|
bArmature *newArm;
|
|
Bone *oldBone, *newBone;
|
|
|
|
newArm= copy_libblock (arm);
|
|
duplicatelist(&newArm->bonebase, &arm->bonebase);
|
|
|
|
/* Duplicate the childrens' lists*/
|
|
newBone=newArm->bonebase.first;
|
|
for (oldBone=arm->bonebase.first;oldBone;oldBone=oldBone->next){
|
|
newBone->parent=NULL;
|
|
copy_bonechildren (newBone, oldBone);
|
|
newBone=newBone->next;
|
|
};
|
|
|
|
return newArm;
|
|
}
|
|
|
|
|
|
void bone_to_mat3(Bone *bone, float mat[][3]) /* no parent */
|
|
{
|
|
float smat[3][3];
|
|
float rmat[3][3];
|
|
/* float q1[4], vec[3];*/
|
|
|
|
/* size */
|
|
/* if(bone->ipo) {
|
|
vec[0]= bone->size[0]+bone->dsize[0];
|
|
vec[1]= bone->size[1]+bone->dsize[1];
|
|
vec[2]= bone->size[2]+bone->dsize[2];
|
|
SizeToMat3(vec, smat);
|
|
}
|
|
else
|
|
*/ {
|
|
SizeToMat3(bone->size, smat);
|
|
}
|
|
|
|
/* rot */
|
|
/*if(bone->flag & BONE_QUATROT) {
|
|
if(bone->ipo) {
|
|
QuatMul(q1, bone->quat, bone->dquat);
|
|
QuatToMat3(q1, rmat);
|
|
}
|
|
else
|
|
*/ {
|
|
NormalQuat(bone->quat);
|
|
QuatToMat3(bone->quat, rmat);
|
|
}
|
|
/* }
|
|
*/
|
|
Mat3MulMat3(mat, rmat, smat);
|
|
}
|
|
|
|
void bone_to_mat4(Bone *bone, float mat[][4])
|
|
{
|
|
float tmat[3][3];
|
|
|
|
bone_to_mat3(bone, tmat);
|
|
|
|
Mat4CpyMat3(mat, tmat);
|
|
|
|
VECCOPY(mat[3], bone->loc);
|
|
// VecAddf(mat[3], mat[3], bone->loc);
|
|
/* if(bone->ipo) {
|
|
mat[3][0]+= bone->dloc[0];
|
|
mat[3][1]+= bone->dloc[1];
|
|
mat[3][2]+= bone->dloc[2];
|
|
}
|
|
*/
|
|
}
|
|
|
|
Bone *get_indexed_bone (bArmature *arm, int index)
|
|
/*
|
|
Walk the list until the index is reached
|
|
*/
|
|
{
|
|
Bone *bone=NULL, *curBone;
|
|
int ref=index;
|
|
|
|
if (!arm)
|
|
return NULL;
|
|
|
|
for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
|
|
bone = get_indexed_bone_bonechildren (curBone, &ref);
|
|
if (bone)
|
|
return bone;
|
|
}
|
|
|
|
return bone;
|
|
}
|
|
|
|
Bone *get_named_bone (bArmature *arm, const char *name)
|
|
/*
|
|
Walk the list until the bone is found
|
|
*/
|
|
{
|
|
Bone *bone=NULL, *curBone;
|
|
|
|
if (!arm) return NULL;
|
|
|
|
for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
|
|
bone = get_named_bone_bonechildren (curBone, name);
|
|
if (bone)
|
|
return bone;
|
|
}
|
|
|
|
return bone;
|
|
}
|
|
|
|
static Bone *get_indexed_bone_bonechildren (Bone *bone, int *index)
|
|
{
|
|
Bone *curBone, *rbone;
|
|
|
|
if (!*index)
|
|
return bone;
|
|
|
|
(*index)--;
|
|
|
|
for (curBone=bone->childbase.first; curBone; curBone=curBone->next){
|
|
rbone=get_indexed_bone_bonechildren (curBone, index);
|
|
if (rbone)
|
|
return rbone;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static Bone *get_named_bone_bonechildren (Bone *bone, const char *name)
|
|
{
|
|
Bone *curBone, *rbone;
|
|
|
|
if (!strcmp (bone->name, name))
|
|
return bone;
|
|
|
|
for (curBone=bone->childbase.first; curBone; curBone=curBone->next){
|
|
rbone=get_named_bone_bonechildren (curBone, name);
|
|
if (rbone)
|
|
return rbone;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void make_displists_by_armature (Object *ob)
|
|
{
|
|
Base *base;
|
|
|
|
if (ob){
|
|
for (base= G.scene->base.first; base; base= base->next){
|
|
if ((ob==base->object->parent) && (base->lay & G.scene->lay))
|
|
if (base->object->partype==PARSKEL )
|
|
makeDispList(base->object);
|
|
}
|
|
}
|
|
}
|
|
|
|
void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int root, int posed)
|
|
/* Gets matrix that transforms the bone to object space */
|
|
/* This function is also used to compute the orientation of the bone for display */
|
|
{
|
|
Bone *curBone;
|
|
|
|
Bone *bonelist[256];
|
|
int bonecount=0, i;
|
|
|
|
Mat4One (M_accumulatedMatrix);
|
|
|
|
/* Build a list of bones from tip to root */
|
|
for (curBone=bone; curBone; curBone=curBone->parent){
|
|
bonelist[bonecount] = curBone;
|
|
bonecount++;
|
|
}
|
|
|
|
/* Count through the inverted list (i.e. iterate from root to tip)*/
|
|
for (i=0; i<bonecount; i++){
|
|
float T_root[4][4];
|
|
float T_len[4][4];
|
|
float R_bmat[4][4];
|
|
float M_obmat[4][4];
|
|
float M_boneMatrix[4][4];
|
|
float delta[3];
|
|
|
|
curBone = bonelist[bonecount-i-1];
|
|
|
|
/* Get the length translation (length along y axis) */
|
|
Mat4One (T_len);
|
|
T_len[3][1] = get_bone_length(curBone);
|
|
|
|
if ((curBone == bone) && (root))
|
|
Mat4One (T_len);
|
|
|
|
/* Get the bone's root offset (in the parent's coordinate system) */
|
|
Mat4One (T_root);
|
|
VECCOPY (T_root[3], curBone->head);
|
|
|
|
/* Compose the restmat */
|
|
VecSubf(delta, curBone->tail, curBone->head);
|
|
make_boneMatrixvr(R_bmat, delta, curBone->roll);
|
|
|
|
|
|
/* Retrieve the obmat (user transformation) */
|
|
if (posed)
|
|
Mat4CpyMat4 (M_obmat, curBone->obmat);
|
|
else
|
|
Mat4One (M_obmat);
|
|
|
|
/* Compose the matrix for this bone */
|
|
#if 0
|
|
Mat4MulSerie (M_boneMatrix, M_accumulatedMatrix, T_root, M_obmat, R_bmat, T_len, NULL, NULL, NULL);
|
|
#else
|
|
Mat4MulSerie (M_boneMatrix, M_accumulatedMatrix, T_root, R_bmat, M_obmat, T_len, NULL, NULL, NULL);
|
|
#endif
|
|
Mat4CpyMat4 (M_accumulatedMatrix, M_boneMatrix);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void solve_posechain (PoseChain *chain)
|
|
{
|
|
float goal[3];
|
|
int i;
|
|
Bone *curBone;
|
|
float M_obmat[4][4];
|
|
float M_basischange[4][4];
|
|
bPoseChannel *chan;
|
|
|
|
if (!chain->solver) return;
|
|
|
|
/**
|
|
* Transform the goal from worldspace
|
|
* to the coordinate system of the root
|
|
* of the chain. The matrix for this
|
|
* was computed when the chain was built
|
|
* in ik_chain_to_posechain
|
|
*/
|
|
|
|
VECCOPY (goal, chain->goal);
|
|
Mat4MulVecfl (chain->goalinv, goal);
|
|
|
|
/* Solve the chain */
|
|
|
|
IK_SolveChain(chain->solver,
|
|
goal,
|
|
chain->tolerance,
|
|
chain->iterations,
|
|
0.1f,
|
|
chain->solver->segments);
|
|
|
|
/* Copy the results back into the bones */
|
|
for (i = chain->solver->num_segments-1, curBone=chain->target->parent; i>=0; i--, curBone=curBone->parent){
|
|
|
|
/* Retrieve the delta rotation from the solver */
|
|
Mat4One(M_basischange);
|
|
Mat4CpyMat3(M_basischange, chain->solver->segments[i].basis_change);
|
|
|
|
|
|
/**
|
|
* Multiply the bone's usertransform by the
|
|
* basis change to get the new usertransform
|
|
*/
|
|
|
|
Mat4CpyMat4 (M_obmat, curBone->obmat);
|
|
Mat4MulMat4 (curBone->obmat, M_basischange, M_obmat);
|
|
|
|
/* Store the solve results on the childrens' channels */
|
|
for (chan = chain->pose->chanbase.first; chan; chan=chan->next){
|
|
if (!strcmp (chan->name, curBone->name)){
|
|
Mat4CpyMat4 (chan->obmat, curBone->obmat);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void free_posechain (PoseChain *chain)
|
|
{
|
|
if (chain->solver) {
|
|
MEM_freeN (chain->solver->segments);
|
|
chain->solver->segments = NULL;
|
|
IK_FreeChain(chain->solver);
|
|
}
|
|
MEM_freeN (chain);
|
|
}
|
|
|
|
PoseChain *ik_chain_to_posechain (Object *ob, Bone *bone)
|
|
{
|
|
IK_Segment_Extern *segs;
|
|
PoseChain *chain = NULL;
|
|
Bone *curBone, *rootBone;
|
|
int segcount, curseg, icurseg;
|
|
float imat[4][4];
|
|
Bone *bonelist[256];
|
|
float rootmat[4][4];
|
|
float bonespace[4][4];
|
|
|
|
/**
|
|
* Some interesting variables in this function:
|
|
*
|
|
* Bone->obmat Bone's user transformation;
|
|
* It is initialized in where_is_bone1_time
|
|
*
|
|
* rootmat Bone's coordinate system, computed by
|
|
* get_objectspace_bone_matrix. Takes all
|
|
* parents transformations into account.
|
|
*/
|
|
|
|
|
|
|
|
/* Ensure that all of the bone parent matrices are correct */
|
|
|
|
/* Find the chain's root & count the segments needed */
|
|
segcount = 0;
|
|
for (curBone = bone; curBone; curBone=curBone->parent){
|
|
rootBone = curBone;
|
|
if (curBone!=bone){
|
|
bonelist[segcount]=curBone;
|
|
segcount++;
|
|
}
|
|
if (!curBone->parent)
|
|
break;
|
|
else if (!(curBone->flag & BONE_IK_TOPARENT))
|
|
break;
|
|
}
|
|
|
|
if (!segcount)
|
|
return NULL;
|
|
|
|
|
|
/**
|
|
* Initialize a record to store information about the original bones
|
|
* This will be the return value for this function.
|
|
*/
|
|
|
|
chain = MEM_callocN(sizeof(PoseChain), "posechain");
|
|
chain->solver = IK_CreateChain();
|
|
chain->target = bone;
|
|
chain->root = rootBone;
|
|
chain->pose = ob->pose;
|
|
|
|
/* Allocate some IK segments */
|
|
segs = MEM_callocN (sizeof(IK_Segment_Extern)*segcount, "iksegments");
|
|
|
|
|
|
/**
|
|
* Remove the offset from the first bone in the chain and take the target to chainspace
|
|
*/
|
|
|
|
|
|
get_objectspace_bone_matrix(rootBone, bonespace, 1, 1);
|
|
Mat4One (rootmat);
|
|
VECCOPY (rootmat[3], bonespace[3]);
|
|
|
|
/* Take the target to bonespace */
|
|
Mat4MulMat4 (imat, rootmat, ob->obmat);
|
|
Mat4Invert (chain->goalinv, imat);
|
|
|
|
|
|
/**
|
|
* Build matrices from the root to the tip
|
|
* We count backwards through the bone list (which is sorted tip to root)
|
|
* and forwards through the ik_segment list
|
|
*/
|
|
|
|
for (curseg = segcount-1; curseg>=0; curseg--){
|
|
float M_basismat[4][4];
|
|
float R_parmat[4][4];
|
|
float iR_parmat[4][4];
|
|
float R_bonemat[4][4];
|
|
|
|
/* Retrieve the corresponding bone for this segment */
|
|
icurseg=segcount-curseg-1;
|
|
curBone = bonelist[curseg];
|
|
|
|
/* Get the basis matrix */
|
|
Mat4One (R_parmat);
|
|
get_objectspace_bone_matrix(curBone, R_bonemat, 1, 1);
|
|
R_bonemat[3][0]=R_bonemat[3][1]=R_bonemat[3][2]=0.0F;
|
|
|
|
if (curBone->parent && (curBone->flag & BONE_IK_TOPARENT)){
|
|
get_objectspace_bone_matrix(curBone->parent, R_parmat, 1, 1);
|
|
R_parmat[3][0]=R_parmat[3][1]=R_parmat[3][2]=0.0F;
|
|
}
|
|
|
|
Mat4Invert(iR_parmat, R_parmat);
|
|
Mat4MulMat4(M_basismat, R_bonemat, iR_parmat);
|
|
|
|
/* Copy the matrix into the basis and transpose */
|
|
Mat3CpyMat4(segs[icurseg].basis, M_basismat);
|
|
Mat3Transp(segs[icurseg].basis);
|
|
|
|
/* Fill out the IK segment */
|
|
segs[icurseg].length = get_bone_length(curBone);
|
|
|
|
};
|
|
|
|
IK_LoadChain(chain->solver, segs, segcount);
|
|
return chain;
|
|
}
|
|
|
|
|
|
|
|
void precalc_bonelist_irestmats (ListBase* bonelist)
|
|
{
|
|
Bone *curbone;
|
|
|
|
if (!bonelist)
|
|
return;
|
|
|
|
for (curbone = bonelist->first; curbone; curbone=curbone->next){
|
|
precalc_bone_irestmat(curbone);
|
|
precalc_bonelist_irestmats(&curbone->childbase);
|
|
}
|
|
}
|