Revision of NLA stride option.

Previously, using the "Stride Bone" tried to get that Bone motionless on
the path by correcting the internal time of the Action. This however caused
too many problems, especially with irregular walks.

The new system also tries to keep the Stride Bone motionless, but this by
moving the entire armature, and not changing the timing of the Action.
Give much nicer results. :)

To make editing Strides easier, I've added a new option in the NLA
panel to disable the path. This way you can quickly switch to editing the
action itself (keying the stride bone) and viewing the result.
This commit is contained in:
2005-11-15 22:39:20 +00:00
parent a8df218335
commit b474f95c84
6 changed files with 58 additions and 38 deletions

View File

@@ -133,7 +133,7 @@ struct bActionChannel *get_action_channel(struct bAction *act, const char *name
struct bActionChannel *verify_action_channel(struct bAction *act, const char *name);
/* exported for game engine */
void blend_poses(struct bPose *dst, const struct bPose *src, float srcweight, short mode);
void blend_poses(struct bPose *dst, struct bPose *src, float srcweight, short mode);
void extract_pose_from_pose(struct bPose *pose, const struct bPose *src);
/* map global time (frame nr) to strip converted time, doesn't clip */

View File

@@ -357,7 +357,7 @@ bActionChannel *verify_action_channel(bAction *act, const char *name)
/* Only allowed for Poses with identical channels */
void blend_poses(bPose *dst, const bPose *src, float srcweight, short mode)
void blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
{
bPoseChannel *dchan;
const bPoseChannel *schan;
@@ -407,6 +407,8 @@ void blend_poses(bPose *dst, const bPose *src, float srcweight, short mode)
dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight;
}
}
VecLerpf(dst->stride_offset, dst->stride_offset, src->stride_offset, srcweight);
}
@@ -504,6 +506,10 @@ static void rest_pose(bPose *pose)
if (!pose)
return;
pose->stride_offset[0]= 0.0f;
pose->stride_offset[1]= 0.0f;
pose->stride_offset[2]= 0.0f;
for (pchan=pose->chanbase.first; pchan; pchan=pchan->next){
for (i=0; i<3; i++){
pchan->loc[i]=0.0;
@@ -715,9 +721,12 @@ static float nla_time(float cfra, float unit)
return cfra;
}
static float stridechannel_frame(bAction *act, int stride_axis, char *name, float pdist)
static float stridechannel_frame(Object *ob, bActionStrip *strip, Path *path, float pathdist, float *stride_offset)
{
bAction *act= strip->act;
char *name= strip->stridechannel;
bActionChannel *achan= get_action_channel(act, name);
int stride_axis= strip->stride_axis;
if(achan && achan->ipo) {
IpoCurve *icu= NULL;
@@ -745,29 +754,23 @@ static float stridechannel_frame(bAction *act, int stride_axis, char *name, floa
if(foundvert && miny!=maxy) {
float stridelen= fabs(maxy-miny), striptime;
float actiondist, step= 0.5, error, threshold=0.00001f*stridelen;
int max= 20;
float actiondist, pdist;
float vec1[4], vec2[4], dir[3];
/* amount path moves object */
pdist = (float)fmod (pdist, stridelen);
pdist = (float)fmod (pathdist, stridelen);
striptime= pdist/stridelen;
/* wanted; the (0-1) factor that cancels out this distance, do simple newton-raphson */
striptime= step;
do {
/* amount stride bone moves */
actiondist= eval_icu(icu, minx + striptime*(maxx-minx)) - miny;
error= pdist - fabs(actiondist);
step*=0.5f;
if(error > 0.0)
striptime += step;
else
striptime -= step;
max--;
}
while( fabs(error) > threshold && max>0);
pdist = pdist - fabs(actiondist);
/* now we need to go pdist further (or less) on cu path */
where_on_path(ob, (pathdist)/path->totdist, vec1, dir); /* vec needs size 4 */
where_on_path(ob, (pathdist+pdist)/path->totdist, vec2, dir); /* vec needs size 4 */
VecSubf(stride_offset, vec1, vec2);
Mat4Mul3Vecfl(ob->obmat, stride_offset);
return striptime;
}
}
@@ -811,7 +814,7 @@ static void do_nla(Object *ob, int blocktype)
rest_pose(tpose);
/* Handle path */
if (strip->flag & ACTSTRIP_USESTRIDE){
if ((strip->flag & ACTSTRIP_USESTRIDE) && (blocktype==ID_AR) && (ob->ipoflag & OB_DISABLE_PATH)==0){
if (ob->parent && ob->parent->type==OB_CURVE){
Curve *cu = ob->parent->data;
float ctime, pdist;
@@ -830,8 +833,9 @@ static void do_nla(Object *ob, int blocktype)
}
pdist = ctime*cu->path->totdist;
if(strip->stridechannel[0])
striptime= stridechannel_frame(strip->act, strip->stride_axis, strip->stridechannel, pdist);
if(tpose && strip->stridechannel[0]) {
striptime= stridechannel_frame(ob->parent, strip, cu->path, pdist, tpose->stride_offset);
}
else {
if (strip->stridelen) {
striptime = pdist / strip->stridelen;
@@ -844,8 +848,9 @@ static void do_nla(Object *ob, int blocktype)
frametime = (striptime * actlength) + strip->actstart;
frametime= bsystem_time(ob, 0, frametime, 0.0);
if(blocktype==ID_AR)
if(blocktype==ID_AR) {
extract_pose_from_action (tpose, strip->act, frametime);
}
else if(blocktype==ID_OB) {
extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime);
if(key)
@@ -921,7 +926,12 @@ static void do_nla(Object *ob, int blocktype)
if(blocktype==ID_OB) {
execute_ipochannels(&chanbase);
}
else if(blocktype==ID_AR) {
/* apply stride offset to object */
VecAddf(ob->obmat[3], ob->obmat[3], ob->pose->stride_offset);
}
/* free */
if (tpose){
free_pose_channels(tpose);
MEM_freeN(tpose);
@@ -929,7 +939,6 @@ static void do_nla(Object *ob, int blocktype)
if(chanbase.first)
BLI_freelistN(&chanbase);
}
void do_all_pose_actions(Object *ob)

View File

@@ -1075,8 +1075,12 @@ void ob_parcurve(Object *ob, Object *par, float mat[][4])
SWAP(float, timeoffs, ob->sf);
}
/* catch exceptions: feature for nla stride editing */
if(ob->ipoflag & OB_DISABLE_PATH) {
ctime= 0.0f;
}
/* catch exceptions: curve paths used as a duplicator */
if(enable_cu_speed) {
else if(enable_cu_speed) {
ctime= bsystem_time(ob, par, (float)G.scene->r.cfra, 0.0);
if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) {

View File

@@ -79,7 +79,8 @@ typedef struct bPoseChannel {
typedef struct bPose{
ListBase chanbase;
int flag, pad;
int flag;
float stride_offset[3];
} bPose;
typedef struct bActionChannel {

View File

@@ -282,6 +282,8 @@ extern Object workob;
/* get ipo from from action or not? */
#define OB_ACTION_OB 256
#define OB_ACTION_KEY 512
/* for stride edit */
#define OB_DISABLE_PATH 1024
/* (short) trackflag / upflag */
#define OB_POSX 0

View File

@@ -398,27 +398,30 @@ static void draw_nla_strips_keys(SpaceNla *snla)
#define B_NLA_LOCK 122
/* For now just returns the first selected strip */
bActionStrip *get_active_nlastrip(void)
bActionStrip *get_active_nlastrip(Object **obpp)
{
Base *base;
bActionStrip *strip;
for (base=G.scene->base.first; base; base=base->next){
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
if (strip->flag & ACTSTRIP_SELECT)
if (strip->flag & ACTSTRIP_SELECT) {
*obpp= base->object;
return strip;
}
}
}
return NULL;
}
void do_nlabuts(unsigned short event)
{
Object *ob;
bActionStrip *strip;
/* Determine if an nla strip has been selected */
strip = get_active_nlastrip();
strip = get_active_nlastrip(&ob);
if (!strip) return;
switch(event) {
@@ -427,8 +430,7 @@ void do_nlabuts(unsigned short event)
allqueue(REDRAWNLA, 0);
break;
case B_NLA_PANEL:
DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB|OB_RECALC_DATA);
DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
allqueue (REDRAWNLA, 0);
allqueue (REDRAWVIEW3D, 0);
break;
@@ -443,6 +445,7 @@ void do_nlabuts(unsigned short event)
static void nla_panel_properties(short cntrl) // NLA_HANDLER_PROPERTIES
{
Object *ob;
bActionStrip *strip;
uiBlock *block;
@@ -452,7 +455,7 @@ static void nla_panel_properties(short cntrl) // NLA_HANDLER_PROPERTIES
if(uiNewPanel(curarea, block, "Transform Properties", "NLA", 10, 230, 318, 204)==0) return;
/* Determine if an nla strip has been selected */
strip = get_active_nlastrip();
strip = get_active_nlastrip(&ob);
if (!strip) return;
/* first labels, for simpler align code :) */
@@ -488,8 +491,9 @@ static void nla_panel_properties(short cntrl) // NLA_HANDLER_PROPERTIES
uiDefButS(block, TOG, B_NLA_PANEL, "Add", 230,60,75,19, &strip->mode, 0, 0, 0, 0, "Toggles additive blending mode");
uiBlockBeginAlign(block);
uiDefButBitS(block, TOG, ACTSTRIP_USESTRIDE, B_NLA_PANEL, "Use Path", 10,20,100,19, &strip->flag, 0, 0, 0, 0, "Plays action based on path position & stride");
uiDefButF(block, NUM, B_NLA_PANEL, "Stride:", 110,20,200,19, &strip->stridelen, 0.0001, 1000.0, 100, 0, "Distance covered by one complete cycle of the action specified in the Action Range");
uiDefButBitS(block, TOG, ACTSTRIP_USESTRIDE, B_NLA_PANEL, "Stride Path", 10,20,100,19, &strip->flag, 0, 0, 0, 0, "Plays action based on path position & stride");
uiDefButBitS(block, TOG, OB_DISABLE_PATH, B_NLA_PANEL, "Disable Path", 110,20,100,19, &ob->ipoflag, 0, 0, 0, 0, "Plays action based on path position & stride");
uiDefButF(block, NUM, B_NLA_PANEL, "Stride:", 210,20,100,19, &strip->stridelen, 0.0001, 1000.0, 100, 0, "Distance covered by one complete cycle of the action specified in the Action Range");
uiDefButS(block, ROW, B_NLA_PANEL, "X", 10, 0, 33, 19, &strip->stride_axis, 1, 0, 0, 0, "Dominant axis for Stride Bone");
uiDefButS(block, ROW, B_NLA_PANEL, "Y", 43, 0, 33, 19, &strip->stride_axis, 1, 1, 0, 0, "Dominant axis for Stride Bone");