# The conversion of roll to matrix breaks in some cases #82455

Closed
opened 2020-11-06 10:36:58 +01:00 by Gaia Clary · 10 comments
Member

I refer to this function: source/blender/blenkernel/intern/armature.c :: vec_roll_to_mat3_normalized()

The conversion of roll to matrix breaks when a bone has very small values in x and z. In that case we get a division by very small numbers which can cause a broken bone roll matrix.

details:

``````due to float precision errors, we can have nor = (0.0, 0.99999994, 0.0)...
``````

I have found other situations where nor == (x, 0.99999994, z) with x and/or z very close to 0, but not exactly 0. However the test (nor- [x] || nor- [x]) can be true for tiny numbers. So further down in the function we see:

``````/* If nor is too close to -Y, apply the special case. */
theta = nor[0] * nor[0] + nor[2] * nor[2];
``````

So when x and/or z are tiny numbers, then theta becomes tiny as well. And since we only check for (x or z != 0):

`if (theta > THETA_SAFE || ((nor- [x] || nor- [x]) && theta > THETA_CRITICAL)) ...`

You can see that theta can potentially drop below the THETA_THRESHOLD_NEGY_CLOSE if both nor- [x] and nor- [x] are very close to 0. And this finally leads to potentially very huge numbers for example here (division by almost zero):

``````theta = nor[0] * nor[0] + nor[2] * nor[2];
bMatrix[0][0] = (nor[0] + nor[2]) * (nor[0] - nor[2]) / -theta;
``````

Because of this i believe it is better to not only check (nor- [x] or nor- [x] != 0) but also to make sure that (nor- [x] * nor- [x] + nor- [x] * nor- [x]) is above THETA_THRESHOLD_NEGY_CLOSE.

Below is a python script that generates a rig that suffers from this bug. Run the script, then switch from edit mode to pose mode and see how "bad bone" disappears. Because its pose bone matrix is totally broken. The problem originates in the super small bone roll values which finally lead to the bug:

``````import bpy

bone_data = [
["good bone", (0.0, 0.0, 1.2038891315460205), (0.0, 0.01536799967288971, 1.3546786308288574), -4.1202467175263267e-16],
["bad bone", (0.0, 0.01536799967288971, 1.3546786308288574), (0.0, 0.0, 1.2038891315460205), -1.570796257510665e-07],
]

def make_armature(ctx, name):
data = bpy.data.armatures.new(name)
obj  = bpy.data.objects.new(name, data)
ctx.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode='EDIT')
parent = None
for bname, head, tail, roll in bone_data:
bone = obj.data.edit_bones.new(bname)
if parent:
bone.parent = parent
parent=bone
bone.tail=tail
bone.roll = roll
return obj

armobj=make_armature(bpy.context, "armature")
``````

This is a follow up task of the refactoring handled in https://developer.blender.org/D9410

I refer to this function: source/blender/blenkernel/intern/armature.c :: vec_roll_to_mat3_normalized() The conversion of roll to matrix breaks when a bone has very small values in x and z. In that case we get a division by very small numbers which can cause a broken bone roll matrix. details: As already mentioned in the comments: ``` due to float precision errors, we can have nor = (0.0, 0.99999994, 0.0)... ``` I have found other situations where nor == (x, 0.99999994, z) with x and/or z very close to 0, but not exactly 0. However the test (nor- [x] || nor- [x]) can be true for tiny numbers. So further down in the function we see: ``` /* If nor is too close to -Y, apply the special case. */ theta = nor[0] * nor[0] + nor[2] * nor[2]; ``` So when x and/or z are tiny numbers, then theta becomes tiny as well. And since we only check for (x or z != 0): ```if (theta > THETA_SAFE || ((nor- [x] || nor- [x]) && theta > THETA_CRITICAL)) ...``` You can see that theta can potentially drop below the THETA_THRESHOLD_NEGY_CLOSE if both nor- [x] and nor- [x] are very close to 0. And this finally leads to potentially very huge numbers for example here (division by almost zero): ``` theta = nor[0] * nor[0] + nor[2] * nor[2]; bMatrix[0][0] = (nor[0] + nor[2]) * (nor[0] - nor[2]) / -theta; ``` Because of this i believe it is better to not only check (nor- [x] or nor- [x] != 0) but also to make sure that (nor- [x] * nor- [x] + nor- [x] * nor- [x]) is above THETA_THRESHOLD_NEGY_CLOSE. Below is a python script that generates a rig that suffers from this bug. Run the script, then switch from edit mode to pose mode and see how "bad bone" disappears. Because its pose bone matrix is totally broken. The problem originates in the super small bone roll values which finally lead to the bug: ``` import bpy bone_data = [ ["good bone", (0.0, 0.0, 1.2038891315460205), (0.0, 0.01536799967288971, 1.3546786308288574), -4.1202467175263267e-16], ["bad bone", (0.0, 0.01536799967288971, 1.3546786308288574), (0.0, 0.0, 1.2038891315460205), -1.570796257510665e-07], ] def make_armature(ctx, name): data = bpy.data.armatures.new(name) obj = bpy.data.objects.new(name, data) ctx.collection.objects.link(obj) ctx.view_layer.objects.active = obj bpy.ops.object.mode_set(mode='EDIT') parent = None for bname, head, tail, roll in bone_data: bone = obj.data.edit_bones.new(bname) if parent: bone.parent = parent parent=bone bone.head=head bone.tail=tail bone.roll = roll return obj armobj=make_armature(bpy.context, "armature") ``` This is a follow up task of the refactoring handled in https://developer.blender.org/D9410
self-assigned this 2020-11-06 10:36:58 +01:00
Author
Member

Changed status from 'Needs Triage' to: 'Confirmed'

Changed status from 'Needs Triage' to: 'Confirmed'
Author
Member

#88581 was marked as duplicate of this issue

#88581 was marked as duplicate of this issue

This may be set for Blender developers!

This would be due to the source code!

This may be set for Blender developers! This would be due to the source code!
Member

@schampions Welcome to developer.blender.org -- here, everything is for Blender developers. Useful feedback is appreciated, but do know that this is not just a forum. It's the central hub for Blender development.

@schampions Welcome to developer.blender.org -- here, everything is for Blender developers. Useful feedback is appreciated, but do know that this is not just a forum. It's the central hub for Blender development.

This issue was referenced by `df445cc571`

This issue was referenced by df445cc571bd1cf7fab4c5c8474f5e185a757fe2

This issue was referenced by `16eafdadf6`

This issue was referenced by 16eafdadf6040fb84bacf657ac0bf16a78e1057e
Member
Added subscribers: @scurest, @Azrael69, @lichtwerk, @JulienDuroure
Member

Changed status from 'Confirmed' to: 'Resolved'

Changed status from 'Confirmed' to: 'Resolved'
No Milestone
No project
No Assignees
6 Participants