Armature speed ups, Part III

----------------------------

Another (major) armature speed up for bones with many constraints.

When tranform()-ing, figure out which bones need to be recalculated
beforehand and only update those bones.
This commit is contained in:
Chris Want
2004-01-03 03:53:18 +00:00
parent de21846e69
commit d311e96174
6 changed files with 292 additions and 10 deletions

View File

@@ -297,11 +297,6 @@ void where_is_bone1_time (Object *ob, Bone *bone, float ctime)
where_is_bone_time (ob, bone->parent, ctime); 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 #endif
if (arm){ if (arm){
@@ -312,6 +307,13 @@ void where_is_bone1_time (Object *ob, Bone *bone, float ctime)
} }
} }
/* If the bone has been flagged as 'no calc', let's not
* bother calculating it.
*/
if (bone->flag & BONE_NOCALC) {
return;
}
if (bone->flag & BONE_IK_TOPARENT){ if (bone->flag & BONE_IK_TOPARENT){
bone->loc[0]=bone->loc[1]=bone->loc[2]=0.0F; bone->loc[0]=bone->loc[1]=bone->loc[2]=0.0F;
} }
@@ -839,8 +841,10 @@ static void apply_pose_bonechildren (Bone* bone, bPose* pose, int doit)
// Ensure there is a channel for this bone // Ensure there is a channel for this bone
chan = verify_pose_channel (pose, bone->name); chan = verify_pose_channel (pose, bone->name);
if (chan) { /* Only do this crazy stuff if the no calc flag
// Search the pose for a channel with the same name * is cleared for this bone.
*/
if (chan && (~bone->flag & BONE_NOCALC)) {
if (chan->flag & POSE_LOC) if (chan->flag & POSE_LOC)
memcpy (bone->loc, chan->loc, sizeof (bone->loc)); memcpy (bone->loc, chan->loc, sizeof (bone->loc));
if (chan->flag & POSE_SIZE) if (chan->flag & POSE_SIZE)

View File

@@ -56,6 +56,9 @@ struct ListBase *get_constraint_client_channels (int forcevalid);
struct ListBase *get_constraint_client(char *name, short *clienttype, void** clientdata); struct ListBase *get_constraint_client(char *name, short *clienttype, void** clientdata);
int test_constraints (struct Object *owner, const char *substring, int disable); int test_constraints (struct Object *owner, const char *substring, int disable);
void test_scene_constraints (void); void test_scene_constraints (void);
char *get_con_subtarget_name(struct bConstraint *constraint,
struct Object *target);
struct Object *get_con_target(struct bConstraint *constraint); struct Object *get_con_target(struct bConstraint *constraint);
#endif #endif

View File

@@ -110,7 +110,11 @@ enum {
BONE_DONE = 0x00000080, /* For detecting cyclic dependancies */ BONE_DONE = 0x00000080, /* For detecting cyclic dependancies */
BONE_ISEMPTY = 0x00000100, BONE_ISEMPTY = 0x00000100,
BONE_ISMUSCLE = 0x00000200 BONE_ISMUSCLE = 0x00000200,
BONE_NOCALC = 0x00000400 /* Don't calculate bone
* transformation, when flagged
* (note: this is a temporary flag)
*/
}; };
enum { enum {
@@ -122,7 +126,8 @@ enum {
BONE_QUATROTBIT, BONE_QUATROTBIT,
BONE_HIDDENBIT, BONE_HIDDENBIT,
BONE_ISEMPTYBIT, BONE_ISEMPTYBIT,
BONE_ISMUSCLEBIT BONE_ISMUSCLEBIT,
BONE_NOCALCBIT
}; };
enum { enum {

View File

@@ -1318,16 +1318,25 @@ static void validate_editbonebutton_cb(void *bonev, void *arg2_unused)
validate_editbonebutton(curBone); validate_editbonebutton(curBone);
} }
static void armature_rest_pos_func(void *notused1, void *notused2) {
clear_object_constraint_status(OBACT);
make_displists_by_armature(OBACT);
}
static void editing_panel_armature_type(Object *ob, bArmature *arm) static void editing_panel_armature_type(Object *ob, bArmature *arm)
{ {
uiBlock *block; uiBlock *block;
uiBut *but;
int bx=148, by=100; int bx=148, by=100;
block= uiNewBlock(&curarea->uiblocks, "editing_panel_armature_type", UI_EMBOSS, UI_HELV, curarea->win); block= uiNewBlock(&curarea->uiblocks, "editing_panel_armature_type", UI_EMBOSS, UI_HELV, curarea->win);
if(uiNewPanel(curarea, block, "Armature", "Editing", 320, 0, 318, 204)==0) return; if(uiNewPanel(curarea, block, "Armature", "Editing", 320, 0, 318, 204)==0) return;
uiDefButI(block, TOG|BIT|ARM_RESTPOSBIT,REDRAWVIEW3D, "Rest Pos", bx,by,97,20, &arm->flag, 0, 0, 0, 0, "Disable all animation for this object"); but = uiDefButI(block, TOG|BIT|ARM_RESTPOSBIT,REDRAWVIEW3D,
"Rest Pos", bx,by,97,20, &arm->flag, 0, 0, 0, 0,
"Disable all animation for this object");
uiButSetFunc(but, armature_rest_pos_func, NULL, NULL);
uiBlockBeginAlign(block); uiBlockBeginAlign(block);
uiDefButI(block, TOG|BIT|ARM_DRAWAXESBIT,REDRAWVIEW3D, "Draw Axes", bx,by-46,97,20, &arm->flag, 0, 0, 0, 0, "Draw bone axes"); uiDefButI(block, TOG|BIT|ARM_DRAWAXESBIT,REDRAWVIEW3D, "Draw Axes", bx,by-46,97,20, &arm->flag, 0, 0, 0, 0, "Draw bone axes");
uiDefButI(block, TOG|BIT|ARM_DRAWNAMESBIT,REDRAWVIEW3D, "Draw Names", bx,by-69,97,20, &arm->flag, 0, 0, 0, 0, "Draw bone names"); uiDefButI(block, TOG|BIT|ARM_DRAWNAMESBIT,REDRAWVIEW3D, "Draw Names", bx,by-69,97,20, &arm->flag, 0, 0, 0, 0, "Draw bone names");

View File

@@ -774,6 +774,66 @@ void add_influence_key_to_constraint (bConstraint *con){
printf("doesn't do anything yet\n"); printf("doesn't do anything yet\n");
} }
char *get_con_subtarget_name(bConstraint *constraint, Object *target)
{
/*
* If the target for this constraint is target, return a pointer
* to the name for this constraints subtarget ... NULL otherwise
*/
switch (constraint->type) {
case CONSTRAINT_TYPE_ACTION:
{
bActionConstraint *data = constraint->data;
if (data->tar==target) return data->subtarget;
}
break;
case CONSTRAINT_TYPE_LOCLIKE:
{
bLocateLikeConstraint *data = constraint->data;
if (data->tar==target) return data->subtarget;
}
break;
case CONSTRAINT_TYPE_ROTLIKE:
{
bRotateLikeConstraint *data = constraint->data;
if (data->tar==target) return data->subtarget;
}
break;
case CONSTRAINT_TYPE_KINEMATIC:
{
bKinematicConstraint *data = constraint->data;
if (data->tar==target) return data->subtarget;
}
break;
case CONSTRAINT_TYPE_TRACKTO:
{
bTrackToConstraint *data = constraint->data;
if (data->tar==target) return data->subtarget;
}
break;
case CONSTRAINT_TYPE_LOCKTRACK:
{
bLockTrackConstraint *data = constraint->data;
if (data->tar==target) return data->subtarget;
}
break;
case CONSTRAINT_TYPE_FOLLOWPATH:
/* wonder if this is relevent, since this constraint
* cannot have a subtarget - theeth
*/
{
/*
* bFollowPathConstraint *data = constraint->data;
*/
return NULL;
}
break;
}
return NULL;
}
Object *get_con_target(bConstraint *constraint) Object *get_con_target(bConstraint *constraint)
{ {
/* /*

View File

@@ -2669,6 +2669,199 @@ static int pose_do_update_flag(Object *ob) {
return do_update; return do_update;
} }
int clear_bone_nocalc(Object *ob, Bone *bone, void *ptr) {
/* When we aren't transform()-ing, we'll want to turn off
* the no calc flag for bone bone in case the frame changes,
* or something
*/
bone->flag &= ~BONE_NOCALC;
return 0;
}
static void clear_bone_nocalc_ob(Object *ob) {
/* Let's clear no calc for all of the bones in the whole darn armature
*/
bArmature *arm;
arm = get_armature(ob);
if (arm) {
bone_looper(ob, arm->bonebase.first, NULL,
clear_bone_nocalc);
}
}
int set_bone_nocalc(Object *ob, Bone *bone, void *ptr) {
/* Calculating bone transformation makes thins slow ...
* lets set the no calc flag for a bone by default
*/
bone->flag |= BONE_NOCALC;
return 0;
}
int selected_bone_docalc(Object *ob, Bone *bone, void *ptr) {
/* Let's clear the no calc flag for selected bones.
* This function always returns 1 for non-no calc bones
* (a.k.a., the 'do calc' bones) so that the bone_looper
* will count these
*/
if (bone->flag & BONE_NOCALC) {
if ( (bone->flag & BONE_SELECTED) ) {
bone->flag &= ~BONE_NOCALC;
return 1;
}
}
else {
return 1;
}
return 0;
}
static int is_ik_root_docalc(Bone *bone) {
Bone *rootBone;
/* The parents */
for (rootBone = bone; rootBone; rootBone=rootBone->parent) {
if (!rootBone->parent)
break;
else if (!(rootBone->flag & BONE_IK_TOPARENT))
break;
}
if (~rootBone->flag & BONE_NOCALC)
return 1;
return 0;
}
static void ik_chain_docalc(Bone *bone) {
/* Let's clear the no calc flag for an entire IK chain
*/
Bone *curBone;
/* This bone */
bone->flag &= ~BONE_NOCALC;
/* The parents */
for (curBone = bone; curBone; curBone=curBone->parent) {
if (!curBone->parent)
break;
else if (!(curBone->flag & BONE_IK_TOPARENT))
break;
curBone->parent->flag &= ~BONE_NOCALC;
}
/* The children */
for (curBone = bone->childbase.first; curBone; curBone=curBone->next){
if (curBone->flag & BONE_IK_TOPARENT) {
curBone->flag &= ~BONE_NOCALC;
}
}
}
static void figure_bone_nocalc_constraint(Bone *conbone, bConstraint *con,
Object *ob, bArmature *arm) {
/* If this bone has a constraint with a subtarget that has
* the nocalc flag cleared, then we better clear the no calc flag
* on this bone too (and the whole IK chain if this is an IK
* constraint).
*
* Conversly, if this bone has an IK constraint and the root of
* the chain has the no calc flag cleared, we had best clear that
* flag for the whole chain.
*/
Bone *subtarbone;
char *subtar;
subtar = get_con_subtarget_name(con, ob);
if (subtar) {
if ( (subtarbone = get_named_bone(arm, subtar)) ) {
if (~subtarbone->flag & BONE_NOCALC) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC)
ik_chain_docalc(conbone);
else
conbone->flag &= ~BONE_NOCALC;
}
else {
if (is_ik_root_docalc(conbone)) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC)
ik_chain_docalc(conbone);
else
conbone->flag &= ~BONE_NOCALC;
}
}
}
}
else {
/* no subtarget ... target is regular object */
if (is_ik_root_docalc(conbone)) {
if (con->type == CONSTRAINT_TYPE_KINEMATIC)
ik_chain_docalc(conbone);
else
conbone->flag &= ~BONE_NOCALC;
}
}
}
static void figure_bone_nocalc(Object *ob) {
/* Let's figure out which bones need to be recalculated,
* and which don't. Calculations are based on which bones
* are selected, and the constraints that love them.
*/
bArmature *arm;
bPoseChannel *chan;
bConstraint *con;
Bone *conbone;
int numbones, oldnumbones, iterations;
arm = get_armature(ob);
if (!arm) return;
if (arm->flag & ARM_RESTPOS) return;
/* Set no calc for all bones
*/
bone_looper(ob, arm->bonebase.first, NULL,
set_bone_nocalc);
oldnumbones = -1;
numbones = 0;
iterations = 0;
/* O.K., lets loop until we don't clear any more no calc bones
*/
while (oldnumbones != numbones) {
/* I wonder if this will ever get executed? */
if ( (++iterations) == 1000) {
printf("figurin' nocalc is talking too long\n");
break;
}
oldnumbones = numbones;
/* clear no calc for selected bones and count */
numbones = bone_looper(ob, arm->bonebase.first, NULL,
selected_bone_docalc);
if (ob->pose) {
for (chan = ob->pose->chanbase.first; chan; chan=chan->next){
conbone = get_named_bone(arm, chan->name);
if (conbone) {
for (con = chan->constraints.first; con; con=con->next) {
figure_bone_nocalc_constraint(conbone, con, ob, arm);
}
}
}
}
}
}
/*** POSE FIGURIN' -- END ***/ /*** POSE FIGURIN' -- END ***/
@@ -3430,6 +3623,12 @@ void special_aftertrans_update(char mode, int flip, short canceled, int keyflags
bPose *pose; bPose *pose;
bPoseChannel *pchan; bPoseChannel *pchan;
/* we had better clear the no calc flags on the bones
* ... else things won't look too good when changing
* frames, etc.
*/
clear_bone_nocalc_ob(G.obpose);
if (U.uiflag & KEYINSERTACT && !canceled){ if (U.uiflag & KEYINSERTACT && !canceled){
act=G.obpose->action; act=G.obpose->action;
pose=G.obpose->pose; pose=G.obpose->pose;
@@ -4144,6 +4343,8 @@ void transform(int mode)
switch (G.obpose->type) { switch (G.obpose->type) {
case OB_ARMATURE: case OB_ARMATURE:
/* figure out which bones need calculating */
figure_bone_nocalc(G.obpose);
make_trans_bones(mode); make_trans_bones(mode);
break; break;
} }