FBX IO: fix handling or rigged meshes transformations.

We have to convert them to global space on export, and back into local space on import...

Issue raised by jrestemeier (Jens Restemeier) in D607, thanks!
This commit is contained in:
Bastien Montagne 2014-07-20 18:53:46 +02:00
parent 1ead56feb5
commit 905f58dedb
3 changed files with 22 additions and 3 deletions

View File

@ -1692,6 +1692,8 @@ def fbx_skeleton_from_armature(scene, settings, arm_obj, objects, data_meshes,
# We don't want a regular parent relationship for those in FBX...
arm_parents.add((arm_obj, ob_obj))
# Needed to handle matrices/spaces (since we do not parent them to 'armature' in FBX :/ ).
ob_obj.parented_to_armature = True
objects.update(bones)

View File

@ -803,7 +803,10 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
Note since a same Blender object might be 'mapped' to several FBX models (esp. with duplis),
we need to use a key to identify each.
"""
__slots__ = ('name', 'key', 'bdata', '_tag', '_ref', '_dupli_matrix')
__slots__ = (
'name', 'key', 'bdata', 'parented_to_armature',
'_tag', '_ref', '_dupli_matrix'
)
@classmethod
def cache_clear(cls):
@ -837,6 +840,7 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
self.name = get_blenderID_name(bdata)
self.bdata = bdata
self._ref = armature
self.parented_to_armature = False
def __eq__(self, other):
return isinstance(other, self.__class__) and self.key == other.key
@ -936,6 +940,10 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
is_global = (not local_space and
(global_space or not (self._tag in {'DP', 'BO'} or self.has_valid_parent(scene_data.objects))))
# Objects (meshes!) parented to armature are not parented to anything in FBX, hence we need them
# in global space, which is their 'virtual' local space...
is_global = is_global or self.parented_to_armature
# Since we have to apply corrections to some types of object, we always need local Blender space here...
matrix = self.matrix_rest_local if rest else self.matrix_local
parent = self.parent

View File

@ -502,7 +502,7 @@ def blen_read_armatures_add_bone(bl_obj, bl_arm, bones, b_uuid, matrices, fbx_tm
return ebo
def blen_read_armatures(fbx_tmpl, armatures, fbx_bones_to_fake_object, scene, global_matrix):
def blen_read_armatures(fbx_tmpl, armatures, fbx_bones_to_fake_object, scene, global_matrix, arm_parents):
from mathutils import Matrix
if global_matrix is None:
@ -557,6 +557,8 @@ def blen_read_armatures(fbx_tmpl, armatures, fbx_bones_to_fake_object, scene, gl
ob_me.parent = bl_adata
ob_me.matrix_basis = me_mat_back
# Store the pair for later space corrections (bring back mesh in parent space).
arm_parents.add((bl_adata, ob_me))
bl_adata.matrix_basis = arm_mat_back
# Set Pose transformations...
@ -1636,10 +1638,11 @@ def load(operator, context, filepath="",
_(); del _
# II) We can finish armatures processing.
arm_parents = set()
def _():
fbx_tmpl = fbx_template_get((b'Model', b'KFbxNode'))
blen_read_armatures(fbx_tmpl, armatures, fbx_bones_to_fake_object, scene, global_matrix)
blen_read_armatures(fbx_tmpl, armatures, fbx_bones_to_fake_object, scene, global_matrix, arm_parents)
_(); del _
def _():
@ -1684,6 +1687,12 @@ def load(operator, context, filepath="",
if blen_data.parent is None:
blen_data.matrix_basis = global_matrix * blen_data.matrix_basis
for (ob_arm, ob_me) in arm_parents:
# Rigged meshes are in global space in FBX...
ob_me.matrix_basis = global_matrix * ob_me.matrix_basis
# And reverse-apply armature transform, so that it gets valid parented (local) position!
ob_me.matrix_parent_inverse = ob_arm.matrix_basis.inverted()
_(); del _
def _():