[Bf-committers] 'Why armatures are so slow' Report

Chris Want bf-committers@blender.org
Sat, 05 Jul 2003 09:27:33 -0600

This is a just a little bit of a brain dump(tm) to share my findings
on the causes for slowness in the armature system.

The main finding is that there is too much recalculation of poses
and deformation/displist's at unnecessary times. It appears that
the NaN programmers started working on a pose/constraint caching
feature to alleiviate this, but it was not finished. Finishing this
work and expanding on it will lead to a vast increase in the response
time while animating characters.

Anyways, here are some important parts of the code that influence the
interactive speed:

*** source/blender/blenkernel/intern/armature.c ********************

- void where_is_bone1_time (Object *ob, Bone *bone, float ctime)

   This function figures out where a bone is based on a pose
   and constraints. The important speed up to note is that it
   does very little work if (chan->flag & PCHAN_DONE) in which
   case it just uses a cached matrix, which generally would be
   the way to go if the armature isn't being modified (either
   explicitely or implicitely via a constraint).

*** source/blender/src/drawview.c **********************************

- void drawview3d(void)

   This function draws the scene you see in the 3D window
   during every redraw. The big bottle neck here is this
   little gem:

	/* Clear the constraint "done" flags */
	for (base = G.scene->base.first; base; base=base->next){

   Remember the pose caching I talked about earlier? This function
   makes it recalculate the matrix in the cache. Since this is
   done every redraw things get sloooooooowhoa!

*** source/blender/src/editarmature.c *****************************

- void draw_armature(Object *ob)

   This function draws the armature. The source of slowness
   here is this stuff:

#if 1   /* Activate if there are problems with action lag */
                 apply_pose_armature(arm, ob->pose, 0);
                 where_is_armature (ob);

   Remember where_is_bone1_time, which would recalculate poses if
   they weren't cached? Well, that gets called for each bone through
   the where_is_armature function.

*** source/blender/src/drawobject.c ********************************

- void draw_object(Base *base)

   OK enough about armatures ... what about those objects that are
   deformed by armatures? Well, they get recalculated every redraw

#if 1
#ifdef __NLA
                         /* Force a refresh of the display list if the 
parent is an armature */
                         if (ob->parent && ob->parent->type==OB_ARMATURE 
&& ob->partype==PARSKEL){
#if 0                   /* Turn this on if there are problems with 
deformation lag */
                                 where_is_armature (ob->parent);
                                 if (ob != G.obedit)
                                         makeDispList (ob);

   (man I hate comments/indenting that spans beyond 80 characters ... but
   that's another story).


So what to do?

Unfortunately, it turns out that the naive disabling of any of the bits
of code above leads to a character that does not update/pose correctly.

The 2 most important things to do to improve the system to prevent
armature slowness are thus:

1) figure out when is the best time to recalculate a pose. This would

- Frame changed
- Enter pose mode
- Exit pose mode
- In the while loop in transform, i.e., 'g', 's', 'r' in pose mode... 
and also
   after you press esc in there.
- The target of a constraint on the armature has changed
- any others? (I noticed intrr added some code to clear constraints on
   'set scenes' so some care will be needed).

2) figure out when the best time to recalculate the deformation of a
child mesh of an armature. This would basically include all of the
events listed above in 1), but with the added consideration that it
must be in very good sync with the pose calculation to avoid lags.

Anyways, through experimentation I have on my local source tree a system
which has most of this stuff sorted out, with excellent interaction
times, but occasionally gets a little out of sync between pose
calculation, deformation calculation, and redraws. The interaction time
while transform()-ing in posemode isn't great because I have it
recalculating the whole armature as it goes through each cycle of the
event loop, but that can be improved by making it only recalculate the
bones that need it, and also by only recalculating when the mouse
position changes.

I will continue to experiment ...


P.S. On an only partially related note, it might be good to replace
some code in drawview3d that is flagged as /* SILLY CODE!!!! */
with a non-silly alternative... if the code is silly it means it's
broken or poorly understood and it should be re-evaluated.