[Bf-extensions-cvs] [59ff66f] master: FBX export: rework animation handling, and add shapes animation support.

Bastien Montagne noreply at git.blender.org
Sun Jul 6 22:02:29 CEST 2014


Commit: 59ff66fa7aca6a56dfa516ee4a456428516d2c6f
Author: Bastien Montagne
Date:   Sun Jul 6 21:49:06 2014 +0200
https://developer.blender.org/rBA59ff66fa7aca6a56dfa516ee4a456428516d2c6f

FBX export: rework animation handling, and add shapes animation support.

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

M	io_scene_fbx/export_fbx_bin.py
M	io_scene_fbx/fbx_utils.py

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

diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py
index adc0cd4..3c46fa7 100644
--- a/io_scene_fbx/export_fbx_bin.py
+++ b/io_scene_fbx/export_fbx_bin.py
@@ -55,6 +55,7 @@ from .fbx_utils import (
     FBX_POSE_BIND_VERSION, FBX_DEFORMER_SKIN_VERSION, FBX_DEFORMER_CLUSTER_VERSION,
     FBX_MATERIAL_VERSION, FBX_TEXTURE_VERSION,
     FBX_ANIM_KEY_VERSION,
+    FBX_ANIM_PROPSGROUP_NAME,
     FBX_KTIME,
     BLENDER_OTHER_OBJECT_TYPES, BLENDER_OBJECT_TYPES_MESHLIKE,
     FBX_LIGHT_TYPES, FBX_LIGHT_DECAY_TYPES,
@@ -83,6 +84,8 @@ from .fbx_utils import (
     elem_props_template_init, elem_props_template_set, elem_props_template_finalize,
     # Templates.
     FBXTemplate, fbx_templates_generate,
+    # Animation.
+    AnimationCurveNodeWrapper,
     # Objects.
     ObjectWrapper, fbx_name_class,
     # Top level.
@@ -496,7 +499,7 @@ def fbx_template_def_animlayer(scene, settings, override_defaults=None, nbr_user
 
 def fbx_template_def_animcurvenode(scene, settings, override_defaults=None, nbr_users=0):
     props = OrderedDict((
-        (b"d", (None, "p_compound", False)),
+        (FBX_ANIM_PROPSGROUP_NAME.encode(), (None, "p_compound", False)),
     ))
     if override_defaults is not None:
         props.update(override_defaults)
@@ -1693,61 +1696,13 @@ def fbx_skeleton_from_armature(scene, settings, arm_obj, objects, data_meshes,
     objects.update(bones)
 
 
-def fbx_animations_simplify(scene_data, animdata):
-    """
-    Simplifies FCurves!
-    """
-    fac = scene_data.settings.bake_anim_simplify_factor
-    step = scene_data.settings.bake_anim_step
-    # So that, with default factor and step values (1), we get:
-    max_frame_diff = step * fac * 10  # max step of 10 frames.
-    value_diff_fac = fac / 1000  # min value evolution: 0.1% of whole range.
-    min_significant_diff = 1.0e-6
-
-    for keys in animdata.values():
-        if not keys:
-            continue
-        extremums = [(min(values), max(values)) for values in zip(*(k[1] for k in keys))]
-        min_diffs = [max((mx - mn) * value_diff_fac, min_significant_diff) for mn, mx in extremums]
-        p_currframe, p_key, p_key_write = keys[0]
-        p_keyed = [(p_currframe - max_frame_diff, val) for val in p_key]
-        are_keyed = [False] * len(p_key)
-        for currframe, key, key_write in keys:
-            for idx, (val, p_val) in enumerate(zip(key, p_key)):
-                p_keyedframe, p_keyedval = p_keyed[idx]
-                if val == p_val:
-                    # Never write keyframe when value is exactly the same as prev one!
-                    continue
-                if abs(val - p_val) >= min_diffs[idx]:
-                    # If enough difference from previous sampled value, key this value *and* the previous one!
-                    key_write[idx] = True
-                    p_key_write[idx] = True
-                    p_keyed[idx] = (currframe, val)
-                    are_keyed[idx] = True
-                else:
-                    frame_diff = currframe - p_keyedframe
-                    val_diff = abs(val - p_keyedval)
-                    if ((val_diff >= min_diffs[idx]) or
-                        ((val_diff >= min_significant_diff) and (frame_diff >= max_frame_diff))):
-                        # Else, if enough difference from previous keyed value
-                        # (or any significant difference and max gap between keys is reached),
-                        # key this value only!
-                        key_write[idx] = True
-                        p_keyed[idx] = (currframe, val)
-                        are_keyed[idx] = True
-            p_currframe, p_key, p_key_write = currframe, key, key_write
-        # If we did key something, ensure first and last sampled values are keyed as well.
-        for idx, is_keyed in enumerate(are_keyed):
-            if is_keyed:
-                keys[0][2][idx] = keys[-1][2][idx] = True
-
-
-def fbx_animations_objects_do(scene_data, ref_id, f_start, f_end, start_zero, objects=None, force_keep=False):
+def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=None, force_keep=False):
     """
     Generate animation data (a single AnimStack) from objects, for a given frame range.
     """
     bake_step = scene_data.settings.bake_anim_step
     scene = scene_data.scene
+    meshes = scene_data.data_meshes
 
     if objects is not None:
         # Add bones and duplis!
@@ -1764,15 +1719,22 @@ def fbx_animations_objects_do(scene_data, ref_id, f_start, f_end, start_zero, ob
     else:
         objects = scene_data.objects
 
-    # FBX mapping info: Property affected, and name of the "sub" property (to distinguish e.g. vector's channels).
-    fbx_names = (
-        ("Lcl Translation", "T", "d|X"), ("Lcl Translation", "T", "d|Y"), ("Lcl Translation", "T", "d|Z"),
-        ("Lcl Rotation", "R", "d|X"), ("Lcl Rotation", "R", "d|Y"), ("Lcl Rotation", "R", "d|Z"),
-        ("Lcl Scaling", "S", "d|X"), ("Lcl Scaling", "S", "d|Y"), ("Lcl Scaling", "S", "d|Z"),
-    )
-
     back_currframe = scene.frame_current
-    animdata = OrderedDict((obj, []) for obj in objects)
+    animdata_ob = OrderedDict((ob_obj, (AnimationCurveNodeWrapper(ob_obj.key, 'LCL_TRANSLATION', (0.0, 0.0, 0.0)),
+                                        AnimationCurveNodeWrapper(ob_obj.key, 'LCL_ROTATION', (0.0, 0.0, 0.0)),
+                                        AnimationCurveNodeWrapper(ob_obj.key, 'LCL_SCALING', (1.0, 1.0, 1.0))))
+                              for ob_obj in objects)
+
+    animdata_shapes = OrderedDict()
+    for me, (me_key, _shapes_key, shapes) in scene_data.data_deformers_shape.items():
+        # Ignore absolute shape keys for now!
+        if not me.shape_keys.use_relative:
+            continue
+        for shape, (channel_key, geom_key, _shape_verts_co, _shape_verts_idx) in shapes.items():
+            acnode = AnimationCurveNodeWrapper(channel_key, 'SHAPE_KEY', (0.0,))
+            # Sooooo happy to have to twist again like a mad snake... Yes, we need to write those curves twice. :/
+            acnode.add_group(me_key, shape.name, shape.name, (shape.name,))
+            animdata_shapes[channel_key] = (acnode, me, shape)
 
     p_rots = {}
 
@@ -1781,63 +1743,49 @@ def fbx_animations_objects_do(scene_data, ref_id, f_start, f_end, start_zero, ob
         real_currframe = currframe - f_start if start_zero else currframe
         scene.frame_set(int(currframe), currframe - int(currframe))
 
-        for ob_obj in objects:
+        for ob_obj in animdata_ob:
             ob_obj.dupli_list_create(scene, 'RENDER')
-        for ob_obj in objects:
+        for ob_obj, (anim_loc, anim_rot, anim_scale) in animdata_ob.items():
             # We compute baked loc/rot/scale for all objects (rot being euler-compat with previous value!).
             p_rot = p_rots.get(ob_obj, None)
             loc, rot, scale, _m, _mr = ob_obj.fbx_object_tx(scene_data, rot_euler_compat=p_rot)
             p_rots[ob_obj] = rot
-            tx = tuple(loc) + tuple(convert_rad_to_deg_iter(rot)) + tuple(scale)
-            animdata[ob_obj].append((real_currframe, tx, [False] * len(tx)))
+            anim_loc.add_keyframe(real_currframe, loc)
+            anim_rot.add_keyframe(real_currframe, tuple(convert_rad_to_deg_iter(rot)))
+            anim_scale.add_keyframe(real_currframe, scale)
         for ob_obj in objects:
             ob_obj.dupli_list_clear()
+        for anim_shape, me, shape in animdata_shapes.values():
+            anim_shape.add_keyframe(real_currframe, (shape.value * 100.0,))
         currframe += bake_step
 
     scene.frame_set(back_currframe, 0.0)
 
-    fbx_animations_simplify(scene_data, animdata)
-
     animations = OrderedDict()
-
-    # And now, produce final data (usable by FBX export code)...
-    for ob_obj, keys in animdata.items():
-        if not keys:
-            continue
-        curves = [[] for k in keys[0][1]]
-        for currframe, key, key_write in keys:
-            for idx, (val, wrt) in enumerate(zip(key, key_write)):
-                if wrt:
-                    curves[idx].append((currframe, val))
-
-        obj_key = ob_obj.key
-        # Get PoseBone from bone...
-        #tobj = bone_map[obj] if isinstance(obj, Bone) else obj
-        #loc, rot, scale, _m, _mr = fbx_object_tx(scene_data, tobj)
-        #tx = tuple(loc) + tuple(convert_rad_to_deg_iter(rot)) + tuple(scale)
-        dtx = (0.0, 0.0, 0.0) + (0.0, 0.0, 0.0) + (1.0, 1.0, 1.0)
-        # If animation for a channel, (True, keyframes), else (False, current value).
+    simplify_fac = scene_data.settings.bake_anim_simplify_factor
+
+    # And now, produce final data (usable by FBX export code)
+    # Objects-like loc/rot/scale...
+    for ob_obj, anims in animdata_ob.items():
+        for anim in anims:
+            anim.simplfy(simplify_fac, bake_step)
+            if anim:
+                for obj_key, group_key, group, fbx_group, fbx_gname in anim.get_final_data(scene, ref_id, force_keep):
+                    anim_data = animations.get(obj_key)
+                    if anim_data is None:
+                        anim_data = animations[obj_key] = ("dummy_unused_key", OrderedDict())
+                    anim_data[1][fbx_group] = (group_key, group, fbx_gname)
+
+    # And meshes' shape keys.
+    for channel_key, (anim_shape, me, shape) in animdata_shapes.items():
         final_keys = OrderedDict()
-        for idx, c in enumerate(curves):
-            fbx_group, fbx_gname, fbx_item = fbx_names[idx]
-            fbx_item_key = get_blender_anim_curve_key(scene, ref_id, obj_key, fbx_group, fbx_item)
-            if fbx_group not in final_keys:
-                fbx_group_key = get_blender_anim_curve_node_key(scene, ref_id, obj_key, fbx_group)
-                final_keys[fbx_group] = (fbx_group_key, OrderedDict(), fbx_gname)
-            final_keys[fbx_group][1][fbx_item] = (fbx_item_key, dtx[idx], c,
-                                                  True if (len(c) > 1 or (len(c) > 0 and force_keep)) else False)
-        # And now, remove anim groups (i.e. groups of curves affecting a single FBX property) with no curve at all!
-        del_groups = []
-        for grp, (_k, data, _n) in 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list