Skip to content

Commit

Permalink
fix(skinned_mesh): resolve issues with bone transformations (#217)
Browse files Browse the repository at this point in the history
Fixed bone transformation issues in skinned meshes, including location and orientation. Made adjustments to ensure transformations are correctly applied and multiplied.

fix: #213
  • Loading branch information
NMC-TBone authored Dec 1, 2024
1 parent 1ae054e commit 881ab5e
Showing 1 changed file with 20 additions and 11 deletions.
31 changes: 20 additions & 11 deletions addon/i3dio/node_classes/skinned_mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,36 @@ def __init__(self, id_: int, bone_object: bpy.types.Bone,

@property
def _transform_for_conversion(self) -> mathutils.Matrix:
conversion_matrix: mathutils.Matrix = self.i3d.conversion_matrix

if self.blender_object.parent is None:
# The bone is parented to the armature directly, and therefore should just use the matrix_local which is in
# relation to the armature anyway.
bone_transform = self.blender_object.matrix_local
bone_transform = conversion_matrix @ self.blender_object.matrix_local @ conversion_matrix.inverted()

# Blender bones are visually pointing along the Z-axis, but internally they use the Y-axis. This creates a
# discrepancy when converting to GE's expected orientation. To resolve this, apply a -90-degree rotation
# around the X-axis. The translation is extracted first to avoid altering the
# bone's position during rotation.
rot_fix = mathutils.Matrix.Rotation(math.radians(-90.0), 4, 'X')
translation = bone_transform.to_translation()
bone_transform = rot_fix @ bone_transform.to_3x3().to_4x4()
bone_transform.translation = translation

if self.i3d.settings['collapse_armatures']:
bone_transform = self.parent.blender_object.matrix_local @ bone_transform
# collapse_armatures deletes the armature object in the I3D,
# so we need to mutliply the armature matrix into the root bone
armature_obj = self.parent.blender_object
armature_matrix = conversion_matrix @ armature_obj.matrix_local @ conversion_matrix.inverted()

bone_transform = armature_matrix @ bone_transform
else:
# To find the transform of the bone, we take the inverse of its parents transform in armature space and
# To find the transform of child bone, we take the inverse of its parents transform in armature space and
# multiply that with the bones transform in armature space. The new 4x4 matrix gives the position and
# rotation in relation to the parent bone (of the head, that is)
bone_transform = self.blender_object.parent.matrix_local.inverted() @ self.blender_object.matrix_local

# Blender bones are visually pointing along the Z-axis, but internally they are using Y. To get around this
# discrepancy the local matrix has a 90 deg rotation around the X-axis. To make the bone have the expected
# orientation in GE, rotate it -90 deg on around X.
bone_transform = bone_transform @ mathutils.Matrix.Rotation(math.radians(-90.0), 4, 'X')

conversion_matrix = self.i3d.conversion_matrix @ bone_transform @ self.i3d.conversion_matrix.inverted()

return conversion_matrix
return bone_transform


class SkinnedMeshRootNode(TransformGroupNode):
Expand Down

0 comments on commit 881ab5e

Please sign in to comment.