[Bf-extensions-cvs] [aab3a66] fbx_io_development: FBX import: support animation for bones as well.

Bastien Montagne noreply at git.blender.org
Fri May 23 17:49:38 CEST 2014


Commit: aab3a6647b3cb07a2a806191f82e1f68bd8f5813
Author: Bastien Montagne
Date:   Fri May 23 16:39:03 2014 +0200
https://developer.blender.org/rBAaab3a6647b3cb07a2a806191f82e1f68bd8f5813

FBX import: support animation for bones as well.

===================================================================

M	io_scene_fbx/import_fbx.py

===================================================================

diff --git a/io_scene_fbx/import_fbx.py b/io_scene_fbx/import_fbx.py
index dbc9bee..d94bb63 100644
--- a/io_scene_fbx/import_fbx.py
+++ b/io_scene_fbx/import_fbx.py
@@ -592,28 +592,35 @@ def blen_read_animations_curves_iter(curves, blen_start_offset, fbx_start_offset
             break
 
 
-def blen_read_animations_action(action, ob, cnodes, global_matrix, fps):
+def blen_read_animations_action(action, ob, obpath, grpname, cnodes, global_matrix, fps):
     """
     'Bake' loc/rot/scale into the action, taking into account global_matrix if no parent is present.
     """
+    from bpy.types import Object
     from mathutils import Euler, Matrix
     from itertools import chain
 
     if ob not in object_tdata_cache:
-        printf("ERROR! object '%s' has no transform data, while being animated!" % ob.name)
+        print("ERROR! object '%s' has no transform data, while being animated!" % ob.name)
 
     fbx_curves = []
     # Since we might get other channels animated in the end, due to all FBX transform magic,
     # we need to add curves for whole loc/rot/scale in any case.
     rot_mode = ob.rotation_mode
     if rot_mode == 'QUATERNION':
-        obprops = (("location", 3), ("rotation_quaternion", 4), ("scale", 3))
+        obprops = ((obpath + "location", 3, grpname or "Location"),
+                   (obpath + "rotation_quaternion", 4, grpname or "Quaternion Rotation"),
+                   (obpath + "scale", 3, grpname or "Scale"))
     elif rot_mode == 'AXIS_ANGLE':
-        obprops = (("location", 3), ("rotation_axis_angle", 4), ("scale", 3))
+        obprops = ((obpath + "location", 3, grpname or "Location"),
+                   (obpath + "rotation_axis_angle", 4, grpname or "Axis Angle Rotation"),
+                   (obpath + "scale", 3, grpname or "Scale"))
     else:  # Euler
-        obprops = (("location", 3), ("rotation_euler", 3), ("scale", 3))
-    blen_curves = [action.fcurves.new(obprop, channel, obprop)
-                   for obprop, nbr_channels in obprops for channel in range(nbr_channels)]
+        obprops = ((obpath + "location", 3, grpname or "Location"),
+                   (obpath + "rotation_euler", 3, grpname or "Euler Rotation"),
+                   (obpath + "scale", 3, grpname or "Scale"))
+    blen_curves = [action.fcurves.new(obprop, channel, grpname)
+                   for obprop, nbr_channels, grpname in obprops for channel in range(nbr_channels)]
     for acn_uuid, (curves, fbxprop) in cnodes.items():
         for ac_uuid, ((fbx_acdata, _blen_data), channel) in curves.items():
             fbx_curves.append((fbxprop, channel, fbx_acdata))
@@ -621,9 +628,9 @@ def blen_read_animations_action(action, ob, cnodes, global_matrix, fps):
     transform_data = object_tdata_cache[ob]
 
     rot_prev = ob.rotation_euler.copy()
-    for frame, values in blen_read_animations_curves_iter(fbx_curves, 0.0, 0.0, fps):
+    # We assume for now blen init point is frame 1.0, while FBX ktime init point is 0.
+    for frame, values in blen_read_animations_curves_iter(fbx_curves, 1.0, 0, fps):
         for v, (fbxprop, channel, _fbx_acdata) in zip(values, fbx_curves):
-            print(frame, fbxprop, channel, v)
             if fbxprop == b'Lcl Translation':
                 transform_data.loc[channel] = v
             elif fbxprop == b'Lcl Rotation':
@@ -631,9 +638,17 @@ def blen_read_animations_action(action, ob, cnodes, global_matrix, fps):
             elif fbxprop == b'Lcl Scaling':
                 transform_data.sca[channel] = v
         mat = blen_read_object_transform_do(transform_data)
-        # Don't forget global matrix!
-        if not ob.parent and global_matrix is not None:
-            mat = global_matrix * mat
+        # Don't forget global matrix - but never for bones!
+        if isinstance(ob, Object):
+            if not ob.parent and global_matrix is not None:
+                mat = global_matrix * mat
+        else:  # PoseBone, Urg!
+            # First, get local (i.e. parentspace) rest pose matrix
+            restmat = ob.bone.matrix_local
+            if ob.parent:
+                restmat = ob.parent.bone.matrix_local.inverted() * restmat
+            # And now, remove that rest pose matrix from current mat (also in parent space).
+            mat = restmat.inverted() * mat
 
         # Now we have a virtual matrix of transform from AnimCurves, we can insert keyframes!
         loc, rot, sca = mat.decompose()
@@ -658,19 +673,28 @@ def blen_read_animations(fbx_tmpl_astack, fbx_tmpl_alayer, stacks, scene, global
     Recreate an action per stack/layer/object combinations.
     Note actions are not linked to objects, this is up to the user!
     """
+    actions = {}
     for as_uuid, ((fbx_asdata, _blen_data), alayers) in stacks.items():
         stack_name = elem_name_ensure_class(fbx_asdata, b'AnimStack')
-        print("Stack {}:".format(stack_name))
         for al_uuid, ((fbx_aldata, _blen_data), objects) in alayers.items():
             layer_name = elem_name_ensure_class(fbx_aldata, b'AnimLayer')
-            print(" " * 4 + "Layer {} ({} objects):".format(layer_name, len(objects)))
             for ob, cnodes in objects.items():
-                action_name = "|".join((ob.name, stack_name, layer_name))
-                action = bpy.data.actions.new(action_name)
-                action.use_fake_user = True
-                print(" " * 8 + "Action {} for object {}: {} animated properties:"
-                      "".format(action_name, ob.name, len(cnodes)))
-                blen_read_animations_action(action, ob, cnodes, global_matrix, scene.render.fps)
+                # We want to create actions for objects, but for bones we 'reuse' armatures' actions!
+                id_data = ob.id_data
+                key = (as_uuid, al_uuid, id_data)
+                if key in actions:
+                    action = actions[key]
+                else:
+                    action_name = "|".join((id_data.name, stack_name, layer_name))
+                    actions[key] = action = bpy.data.actions.new(action_name)
+                    action.use_fake_user = True
+                if id_data == ob:
+                    obpath = ""
+                    grpname = None
+                else:
+                    obpath = ob.path_from_id() + "."
+                    grpname = ob.name
+                blen_read_animations_action(action, ob, obpath, grpname, cnodes, global_matrix, scene.render.fps)
 
 
 # ----



More information about the Bf-extensions-cvs mailing list