New driver option for the poor suffering riggers:
"Rotation Difference" This option, for Bones, allows the angle between two Bones to be the driver for another Ipo channel. This angle now is hardcoded based on the Bone-space orientation (without parenting rotation). Thanks to nathan for poking and test!
This commit is contained in:
@@ -751,6 +751,46 @@ void berekenx(float *f, float *o, int b)
|
||||
}
|
||||
}
|
||||
|
||||
#define TFM_WITHOUT_BONE 1
|
||||
|
||||
static void posechannel_get_local_transform(bPoseChannel *pchan, float *quat, float *eul, float *size, int flag)
|
||||
{
|
||||
float pose_mat[3][3];
|
||||
float diff_mat[3][3], ipar_mat[3][3];
|
||||
|
||||
/* we need the local transform = current transform - (parent transform + bone transform) */
|
||||
|
||||
Mat3CpyMat4(pose_mat, pchan->pose_mat);
|
||||
|
||||
if (pchan->parent) {
|
||||
|
||||
if(flag & TFM_WITHOUT_BONE) {
|
||||
float par_mat[3][3];
|
||||
Mat3CpyMat4(par_mat, pchan->parent->pose_mat);
|
||||
Mat3MulMat3(diff_mat, par_mat, pchan->bone->bone_mat);
|
||||
}
|
||||
else
|
||||
Mat3CpyMat4(diff_mat, pchan->parent->pose_mat);
|
||||
|
||||
Mat3Inv(ipar_mat, diff_mat);
|
||||
}
|
||||
else {
|
||||
if(flag & TFM_WITHOUT_BONE)
|
||||
Mat3Inv(ipar_mat, pchan->bone->bone_mat);
|
||||
else
|
||||
Mat3One(ipar_mat);
|
||||
}
|
||||
|
||||
Mat3MulMat3(diff_mat, ipar_mat, pose_mat);
|
||||
|
||||
if(quat)
|
||||
Mat3ToQuat(diff_mat, quat);
|
||||
if(eul)
|
||||
Mat3ToEul(diff_mat, eul);
|
||||
if(size)
|
||||
Mat3ToSize(diff_mat, size);
|
||||
}
|
||||
|
||||
/* has to return a float value */
|
||||
static float eval_driver(IpoDriver *driver, float ipotime)
|
||||
{
|
||||
@@ -802,48 +842,49 @@ static float eval_driver(IpoDriver *driver, float ipotime)
|
||||
else { /* ID_AR */
|
||||
bPoseChannel *pchan= get_pose_channel(ob->pose, driver->name);
|
||||
if(pchan && pchan->bone) {
|
||||
float pose_mat[3][3];
|
||||
float diff_mat[3][3], par_mat[3][3], ipar_mat[3][3];
|
||||
float eul[3], size[3];
|
||||
|
||||
/* we need the local transform = current transform - (parent transform + bone transform) */
|
||||
|
||||
Mat3CpyMat4(pose_mat, pchan->pose_mat);
|
||||
|
||||
if (pchan->parent) {
|
||||
Mat3CpyMat4(par_mat, pchan->parent->pose_mat);
|
||||
Mat3MulMat3(diff_mat, par_mat, pchan->bone->bone_mat);
|
||||
|
||||
Mat3Inv(ipar_mat, diff_mat);
|
||||
/* rotation difference is not a simple driver (i.e. value drives value), but the angle between 2 bones is driving stuff... which is useful */
|
||||
if(driver->adrcode==OB_ROT_DIFF) {
|
||||
bPoseChannel *pchan2= get_pose_channel(ob->pose, driver->name+DRIVER_NAME_OFFS);
|
||||
if(pchan2 && pchan2->bone) {
|
||||
float q1[4], q2[4], quat[4], angle;
|
||||
|
||||
posechannel_get_local_transform(pchan , q1, NULL, NULL, 0);
|
||||
posechannel_get_local_transform(pchan2, q2, NULL, NULL, 0);
|
||||
|
||||
QuatInv(q1);
|
||||
QuatMul(quat, q1, q2);
|
||||
angle = 2.0f * (saacos(quat[0]));
|
||||
angle= ABS(angle);
|
||||
|
||||
return angle>M_PI?2.0f*M_PI-angle:angle;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Mat3Inv(ipar_mat, pchan->bone->bone_mat);
|
||||
}
|
||||
|
||||
Mat3MulMat3(diff_mat, ipar_mat, pose_mat);
|
||||
|
||||
Mat3ToEul(diff_mat, eul);
|
||||
Mat3ToSize(diff_mat, size);
|
||||
float eul[3], size[3];
|
||||
|
||||
posechannel_get_local_transform(pchan, NULL, eul, size, TFM_WITHOUT_BONE);
|
||||
|
||||
switch(driver->adrcode) {
|
||||
case OB_LOC_X:
|
||||
return pchan->loc[0];
|
||||
case OB_LOC_Y:
|
||||
return pchan->loc[1];
|
||||
case OB_LOC_Z:
|
||||
return pchan->loc[2];
|
||||
case OB_ROT_X:
|
||||
return eul[0]/(M_PI_2/9.0);
|
||||
case OB_ROT_Y:
|
||||
return eul[1]/(M_PI_2/9.0);
|
||||
case OB_ROT_Z:
|
||||
return eul[2]/(M_PI_2/9.0);
|
||||
case OB_SIZE_X:
|
||||
return size[0];
|
||||
case OB_SIZE_Y:
|
||||
return size[1];
|
||||
case OB_SIZE_Z:
|
||||
return size[2];
|
||||
switch(driver->adrcode) {
|
||||
case OB_LOC_X:
|
||||
return pchan->loc[0];
|
||||
case OB_LOC_Y:
|
||||
return pchan->loc[1];
|
||||
case OB_LOC_Z:
|
||||
return pchan->loc[2];
|
||||
case OB_ROT_X:
|
||||
return eul[0]/(M_PI_2/9.0);
|
||||
case OB_ROT_Y:
|
||||
return eul[1]/(M_PI_2/9.0);
|
||||
case OB_ROT_Z:
|
||||
return eul[2]/(M_PI_2/9.0);
|
||||
case OB_SIZE_X:
|
||||
return size[0];
|
||||
case OB_SIZE_Y:
|
||||
return size[1];
|
||||
case OB_SIZE_Z:
|
||||
return size[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,9 +193,12 @@ typedef struct Curve {
|
||||
typedef struct IpoDriver {
|
||||
struct Object *ob;
|
||||
short blocktype, adrcode, type, flag;
|
||||
char name[128]; /* bone or constraint(?), or python expression here */
|
||||
char name[128]; /* bone or constraint(?), or python expression here */
|
||||
} IpoDriver;
|
||||
|
||||
/* temp? we store more bone names in 1 driver... */
|
||||
#define DRIVER_NAME_OFFS 32
|
||||
|
||||
typedef struct IpoCurve {
|
||||
struct IpoCurve *next, *prev;
|
||||
|
||||
|
||||
@@ -108,6 +108,8 @@ typedef short IPO_Channel;
|
||||
#define OB_PD_RDAMP 28
|
||||
#define OB_PD_PERM 29
|
||||
|
||||
/* exception: driver channel, for bone driver only */
|
||||
#define OB_ROT_DIFF 100
|
||||
|
||||
|
||||
/* ******************** */
|
||||
|
||||
@@ -2031,6 +2031,7 @@ static char *ipodriver_channelselect_pup(void)
|
||||
tmp+= sprintf(tmp, "|Scale X %%x%d", OB_SIZE_X);
|
||||
tmp+= sprintf(tmp, "|Scale Y %%x%d", OB_SIZE_Y);
|
||||
tmp+= sprintf(tmp, "|Scale Z %%x%d", OB_SIZE_Z);
|
||||
tmp+= sprintf(tmp, "|Rotation Differance %%x%d", OB_ROT_DIFF);
|
||||
|
||||
return (string);
|
||||
}
|
||||
@@ -2081,6 +2082,10 @@ static void ipo_panel_properties(short cntrl) // IPO_HANDLER_PROPERTIES
|
||||
if(driver->ob->type==OB_ARMATURE && driver->blocktype==ID_AR) {
|
||||
icon = ICON_POSE_DEHLT;
|
||||
uiDefBut(block, TEX, B_IPO_REDR, "BO:", 10,220,150,20, driver->name, 0, 31, 0, 0, "Bone name");
|
||||
|
||||
if(driver->adrcode==OB_ROT_DIFF)
|
||||
uiDefBut(block, TEX, B_IPO_REDR, "BO:", 10,200,150,20, driver->name+DRIVER_NAME_OFFS, 0, 31, 0, 0, "Bone name for angular reference");
|
||||
|
||||
}
|
||||
else driver->blocktype= ID_OB; /* safety when switching object button */
|
||||
|
||||
@@ -2106,7 +2111,7 @@ static void ipo_panel_properties(short cntrl) // IPO_HANDLER_PROPERTIES
|
||||
/* note ranges for buttons below are idiot... we need 2 ranges, one for sliding scale, one for real clip */
|
||||
if(G.sipo->ipo && G.sipo->ipo->curve.first && totipo_curve) {
|
||||
extern int totipo_vertsel; // editipo.c
|
||||
uiDefBut(block, LABEL, 0, "Visible curves", 10, 200, 150, 19, NULL, 1.0, 0.0, 0, 0, "");
|
||||
uiDefBut(block, LABEL, 0, "Visible curves", 160, 200, 150, 19, NULL, 1.0, 0.0, 0, 0, "");
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButF(block, NUM, B_MUL_IPO, "Xmin:", 10, 180, 150, 19, &G.sipo->tot.xmin, G.sipo->tot.xmin-1000.0, MAXFRAMEF, 100, 0, "");
|
||||
|
||||
Reference in New Issue
Block a user