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:
@@ -297,11 +297,6 @@ void where_is_bone1_time (Object *ob, Bone *bone, float 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
|
||||
|
||||
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){
|
||||
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
|
||||
chan = verify_pose_channel (pose, bone->name);
|
||||
|
||||
if (chan) {
|
||||
// Search the pose for a channel with the same name
|
||||
/* Only do this crazy stuff if the no calc flag
|
||||
* is cleared for this bone.
|
||||
*/
|
||||
if (chan && (~bone->flag & BONE_NOCALC)) {
|
||||
if (chan->flag & POSE_LOC)
|
||||
memcpy (bone->loc, chan->loc, sizeof (bone->loc));
|
||||
if (chan->flag & POSE_SIZE)
|
||||
|
||||
@@ -56,6 +56,9 @@ struct ListBase *get_constraint_client_channels (int forcevalid);
|
||||
struct ListBase *get_constraint_client(char *name, short *clienttype, void** clientdata);
|
||||
int test_constraints (struct Object *owner, const char *substring, int disable);
|
||||
void test_scene_constraints (void);
|
||||
|
||||
char *get_con_subtarget_name(struct bConstraint *constraint,
|
||||
struct Object *target);
|
||||
struct Object *get_con_target(struct bConstraint *constraint);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -110,7 +110,11 @@ enum {
|
||||
BONE_DONE = 0x00000080, /* For detecting cyclic dependancies */
|
||||
|
||||
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 {
|
||||
@@ -122,7 +126,8 @@ enum {
|
||||
BONE_QUATROTBIT,
|
||||
BONE_HIDDENBIT,
|
||||
BONE_ISEMPTYBIT,
|
||||
BONE_ISMUSCLEBIT
|
||||
BONE_ISMUSCLEBIT,
|
||||
BONE_NOCALCBIT
|
||||
};
|
||||
|
||||
enum {
|
||||
|
||||
@@ -1318,16 +1318,25 @@ static void validate_editbonebutton_cb(void *bonev, void *arg2_unused)
|
||||
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)
|
||||
{
|
||||
uiBlock *block;
|
||||
uiBut *but;
|
||||
int bx=148, by=100;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
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");
|
||||
|
||||
@@ -774,6 +774,66 @@ void add_influence_key_to_constraint (bConstraint *con){
|
||||
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)
|
||||
{
|
||||
/*
|
||||
|
||||
@@ -2669,6 +2669,199 @@ static int pose_do_update_flag(Object *ob) {
|
||||
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 ***/
|
||||
|
||||
|
||||
@@ -3430,6 +3623,12 @@ void special_aftertrans_update(char mode, int flip, short canceled, int keyflags
|
||||
bPose *pose;
|
||||
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){
|
||||
act=G.obpose->action;
|
||||
pose=G.obpose->pose;
|
||||
@@ -4144,6 +4343,8 @@ void transform(int mode)
|
||||
|
||||
switch (G.obpose->type) {
|
||||
case OB_ARMATURE:
|
||||
/* figure out which bones need calculating */
|
||||
figure_bone_nocalc(G.obpose);
|
||||
make_trans_bones(mode);
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user