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);
|
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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user