[Bf-extensions-cvs] [651596b] fbx_io_development: FBX import: First step toward animation (read anim fbxdata and parse its relations).

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


Commit: 651596bf4396923ec7eaaea02de6b64311764108
Author: Bastien Montagne
Date:   Sun May 18 17:35:54 2014 +0200
https://developer.blender.org/rBA651596bf4396923ec7eaaea02de6b64311764108

FBX import: First step toward animation (read anim fbxdata and parse its relations).

Nothing usable yet!

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

M	io_scene_fbx/import_fbx.py

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

diff --git a/io_scene_fbx/import_fbx.py b/io_scene_fbx/import_fbx.py
index 724ad96..850b224 100644
--- a/io_scene_fbx/import_fbx.py
+++ b/io_scene_fbx/import_fbx.py
@@ -257,6 +257,21 @@ def elem_props_get_enum(elem, elem_prop_id, default=None):
     return default
 
 
+"""
+def elem_props_get_compound(elem, elem_prop_id, default=None, getter=elem_props_find_first):
+    elem_prop = getter(elem, elem_prop_id)
+    if elem_prop is not None:
+        assert(elem_prop.props[0] == elem_prop_id)
+        assert(elem_prop.props[1] == b'Compound')
+        assert(elem_prop.props[2] == b'')
+        assert(elem_prop.props[3] == b'')
+
+        root = elem_prop_id + b'|'
+        def getter(elem, elem_prop_id):
+            return elem_props_find_first(elem, root + elem_prop_id)
+        return getter
+    return default
+"""
 # ----------------------------------------------------------------------------
 # Blender
 
@@ -390,7 +405,6 @@ def blen_read_armatures_add_bone(bl_obj, bl_arm, bones, b_uuid, matrices):
     # We assume matrices in cluster are rest pose of bones (they are in Global space!).
     # TransformLink is matrix of bone, in global space.
     # TransformAssociateModel is matrix of armature, in global space (at bind time).
-    # We seek for matrix of bone in armature space...
     elm = elem_find_first(fbx_cdata, b'Transform', default=None)
     mmat_bone = array_to_matrix4(elm.props[0]) if elm is not None else None
     elm = elem_find_first(fbx_cdata, b'TransformLink', default=None)
@@ -400,6 +414,7 @@ def blen_read_armatures_add_bone(bl_obj, bl_arm, bones, b_uuid, matrices):
 
     # ----
     # Now, create the (edit)bone.
+    # We seek for matrix of bone in armature space...
     bmat_arm = amat_glob.inverted() * bmat_glob
     bone_name = elem_name_ensure_class(fbx_bdata, b'Model')
 
@@ -1409,7 +1424,7 @@ def load(operator, context, filepath="",
                 # armatures and bones, handled separately.
                 continue
             fbx_obj, blen_data = fbx_item
-            if fbx_obj.id != b'Model' or fbx_obj[2] == b'LimbNode':
+            if fbx_obj.id != b'Model' or fbx_obj.props[2] == b'LimbNode':
                 continue
 
             # Create empty object or search for object data
@@ -1453,6 +1468,90 @@ def load(operator, context, filepath="",
         blen_read_armatures(fbx_tmpl, armatures, scene, global_matrix)
     _(); del _
 
+    # Animation!
+    def _():
+        stacks = {}
+        animlayers_ignored = set()
+
+        # AnimationStacks.
+        for fbx_uuid, fbx_item in fbx_table_nodes.items():
+            fbx_asdata, blen_data = fbx_item
+            if fbx_asdata.id != b'AnimationStack' or fbx_asdata.props[2] != b'':
+                continue
+            stacks[fbx_uuid] = (fbx_asdata, set(), {})
+
+        # AnimationLayers (only one per stack currently).
+        def get_astacks_from_alayer(al_uuid):
+            for as_uuid, as_ctype in fbx_connection_map.get(al_uuid, ()):
+                if as_ctype.props[0] != b'OO':
+                    continue
+                fbx_asdata, _bl_asdata = fbx_table_nodes.get(as_uuid, (None, None))
+                if (fbx_asdata is None or fbx_asdata.id != b'AnimationStack' or fbx_asdata.props[2] != b'' or
+                    as_uuid not in stacks or (as_uuid, al_uuid) in animlayers_ignored):
+                    continue
+                yield as_uuid
+        for fbx_uuid, fbx_item in fbx_table_nodes.items():
+            fbx_aldata, _blen_data = fbx_item
+            if fbx_aldata.id != b'AnimationLayer' or fbx_aldata.props[2] != b'':
+                continue
+            for as_uuid in get_astacks_from_alayer(fbx_uuid):
+                _fbx_asdata, alayers, _acnodes = stacks[as_uuid]
+                alayers.add(fbx_uuid)
+                if len(alayers) > 1:
+                    # For now, we only support one animlayer per animstack!
+                    animlayers_ignored.add((as_uuid, fbx_uuid))
+
+        # AnimationCurveNodes (also the ones linked to actual animated data!).
+        curvenodes = {}
+        for fbx_uuid, fbx_item in fbx_table_nodes.items():
+            fbx_acndata, _blen_data = fbx_item
+            if fbx_acndata.id != b'AnimationCurveNode' or fbx_acndata.props[2] != b'':
+                continue
+            cnode = curvenodes[fbx_uuid] = {}
+            objs = []
+            for ob_uuid, ob_ctype in fbx_connection_map.get(fbx_uuid, ()):
+                if ob_ctype.props[0] != b'OP':
+                    continue
+                lnk_prop = {
+                    b'Lcl Location': "location",
+                    b'Lcl Rotation': "rotation_euler",
+                    b'Lcl Scaling': "scale"
+                }.get(ob_ctype.props[3], None)
+                if lnk_prop is None:
+                    continue
+                objs.append((ob_uuid, lnk_prop))
+            for al_uuid, al_ctype in fbx_connection_map.get(acn_uuid, ()):
+                if al_ctype.props[0] != b'OO':
+                    continue
+                fbx_aldata, _bl_aldata = fbx_table_nodes.get(al_uuid, (None, None))
+                if fbx_aldata is None or fbx_aldata.id != b'AnimationLayer' or fbx_aldata.props[2] != b'':
+                    continue
+                for as_uuid in get_astacks_from_alayer(al_uuid):
+                    _fbx_asdata, _alayers, objects = stacks[as_uuid]
+                    for ob_uuid, ob_prop in objs:
+                        objects.setdefault(ob_uuid, {})[fbx_uuid] = (cnode, ob_prop)
+
+        # AnimationCurves (real animation data).
+        for fbx_uuid, fbx_item in fbx_table_nodes.items():
+            fbx_acdata, _blen_data = fbx_item
+            if fbx_acdata.id != b'AnimationCurve' or fbx_acdata.props[2] != b'':
+                continue
+            for acn_uuid, acn_ctype in fbx_connection_map.get(ac_uuid, ()):
+                if acn_ctype.props[0] != b'OP':
+                    continue
+                fbx_acndata, _bl_acndata = fbx_table_nodes.get(acn_uuid, (None, None))
+                if (fbx_acndata is None or fbx_acndata.id != b'AnimationCurveNode' or
+                    fbx_acndata.props[2] != b'' or acn_uuid not in curvenodes):
+                    continue
+                # Note this is an infamous simplification of the compound props stuff,
+                # seems to be standard naming but we'll probably have to be smarter to handle more exotic files?
+                channel = {b'd|X': 'x', b'd|Y': 'y', b'd|Z': 'z'}.get(acn_ctype.props[3], None)
+                curvenodes[acn_uuid][channel] = fbx_acdata
+
+        print(stacks)
+
+    _(); del _
+
     def _():
         # Parent objects, after we created them...
         for fbx_uuid, fbx_item in fbx_table_nodes.items():



More information about the Bf-extensions-cvs mailing list