Page MenuHome

Fix to avoid moving bones by tabbing between pose- and editmode
Closed, ArchivedPublicPATCH

Description

Group: Unstable (example)

As i was build a rig, i noticed that the bones in edit-mode moved on their own while switching between bone editmode and something else (objectmode, posemode,...). After searching for the reason i found out that blender has two different representations for bones in editmode and posemode (structs: EditBone and Bone). Every time you switch between modes blender computes the representation again. Since there are a lot of floating point operations involved, the precession gets lost, resulting in bones that aren't at the locations anymore you put them.

If you use a more complex rig you will soon see the problem directly, as in this example i posted on blenderartist.org: http://blenderartists.org/forum/showthread.php?t=208460

The patch avoids this issue. It does not compute them again and again. Instead it stores the edit-mode locations and roll as extra variables (e_roll, e_head, e_tail) inside the "Bone struct". That way this values only get copied between EditBone and corresponding Bone structs. This ensures that bones keep their original locations in editmode, while EditBone can be used as before.

The current patch has one issue. It has no way to open existing files, in which the variables e_roll, e_head and e_tail aren't present. They will be initialized with 0. Making all imported bones useless. (party at ground 0,0,0)

Someone might help me to figure out how i can initialize the imported bones with the correct values, as they get read from the file and allocated. Any newly created file is unaffected, since all variables are stored correctly.

Inside the code that initializes the Bone struct should be a short check if e_roll, e_head and e_tail are 0. If so, compute them once, as it was done before every time switching between modes.

Event Timeline

The variables e_head and e_tail already exist as arm_head and arm_tail. When exiting edit mode it can be ensured that those are set to the exact editbone value. An arm_roll value could however be added.

That new value can be set in readfile.c, at the end of do_versions. Something like:

if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 1)) {
for(arm= main->armature.first; arm; arm= arm->id.next)
...
}

In BKE_blender.h, BLENDER_SUBVERSION would need to be incremented to 1.

Joshua maintains this area, so assigning bug to him in case he has another opinion on this.

Then this might be the issue. As i can see the value is copied from Bone.arm_head to EditBone.head but not the other way around. While converting from EditBone to Bone, the variable arm_head is not used, instead their is a

memcpy(newBone->head, eBone->head, sizeof(newBone->head));
memcpy(newBone->tail, eBone->tail, sizeof(newBone->tail));

inside function ED_armature_from_edit(). But for all not "basebones" it is ignored anyways and overwritten by:

/* Get the new head and tail */
sub_v3_v3v3(newBone->head, eBone->head, eBone->parent->tail);
sub_v3_v3v3(newBone->tail, eBone->tail, eBone->parent->tail);

mul_m3_v3(iM_parentRest, newBone->head);
mul_m3_v3(iM_parentRest, newBone->tail);

There is also the locale matrix variable "M_boneRest" that gets computed, but is never used for anything.

Looks to me like something was in development, but stopped half way before it was done.

OK. I was able to reconstruct the usage of the variables and wrote a new patch.

* Now i use arm_head and arm_tail for the original locations in armature space and they will be copied and not transformed (back and forth). The not needed transformation code was removed.
* I added arm_roll to "struct Bone", which otherwise is stored converted inside arm_mat, resulting in loss of precession.
* A fix for importing older file version is present to initialize arm_roll as correctly as it can get. (introducing fix_bone_roll_256() in fileread.c, that needs to work recursive)
* Subversion changed from 0 to 1
* Never used variable "M_boneRest" removed. (Gets computed but does no participate in anything else)
* Moved two memcopies to different location. Would be useless in most cases at current location.

Anything seams now fine, operational and should be downward/upward compatible. Give it a try ;-)

The forgotten patch for my last comment: patch3.txt (see attachments)

Found another part in the code - this time in where_is_bone() -, that did the same error: Computing arm_head and arm_tail from the arm_mat Matrix. There should be only one line of code that ever changes one of this variables. That is the construction of the Bone from the EditBone (a memcopy) inside ED_armature_from_edit().

So here is v4 of the patch.

I reviewed the patch and made two changes:
* Don't initialize roll in the version patch, this is in local space, not the same value (but maybe there was a reason to do this?).
* Compute arm_head and arm_tail in the 2.37 version patch, that was using where_is_armature_bone where the code was removed.

I'll test it on some more complex models here tomorrow probably, then if it's working ok I'll commit.

As far as i can remember, i had problems with loading older files (2.5.6 subversion 0) if i did not. The roll was present, but inside the properties menu (bone editmode) it was not updated. So i needed to deselect the active bone and select it again, to see the correct roll value inside the roll input widget. But if its working without overwriting roll, then it should be ok.

Committed to svn, thanks for the patch.

Brecht Van Lommel (brecht) changed the task status from Unknown Status to Unknown Status.Feb 5 2011, 2:22 PM