[Bf-extensions-cvs] [b890f0d7] master: FBX IO: add support for import & export of camera focal length animation.

Bastien Montagne noreply at git.blender.org
Mon Feb 19 17:28:38 CET 2018


Commit: b890f0d7e8a666cb82a908cf9b06c6b500e9e2fc
Author: Bastien Montagne
Date:   Mon Feb 19 17:27:05 2018 +0100
Branches: master
https://developer.blender.org/rBAb890f0d7e8a666cb82a908cf9b06c6b500e9e2fc

FBX IO: add support for import & export of camera focal length animation.

Requested in T54050, usually would not add new stuff to FBX but this
looked like totally needed for compo needs...

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

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

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

diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py
index d161844f..b75a8977 100644
--- a/io_scene_fbx/export_fbx_bin.py
+++ b/io_scene_fbx/export_fbx_bin.py
@@ -1896,8 +1896,9 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No
                                ACNW(ob_obj.key, 'LCL_SCALING', force_key, force_sek, scale))
         p_rots[ob_obj] = rot
 
-    animdata_shapes = OrderedDict()
     force_key = (simplify_fac == 0.0)
+
+    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:
@@ -1908,6 +1909,12 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No
             acnode.add_group(me_key, shape.name, shape.name, (shape.name,))
             animdata_shapes[channel_key] = (acnode, me, shape)
 
+    animdata_cameras = OrderedDict()
+    for cam_obj, cam_key in scene_data.data_cameras.items():
+        cam = cam_obj.bdata.data
+        acnode = AnimationCurveNodeWrapper(cam_key, 'CAMERA_FOCAL', force_key, force_sek, (cam.lens,))
+        animdata_cameras[cam_key] = (acnode, cam)
+
     currframe = f_start
     while currframe <= f_end:
         real_currframe = currframe - f_start if start_zero else currframe
@@ -1927,6 +1934,8 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No
             ob_obj.dupli_list_clear()
         for anim_shape, me, shape in animdata_shapes.values():
             anim_shape.add_keyframe(real_currframe, (shape.value * 100.0,))
+        for anim_camera, camera in animdata_cameras.values():
+            anim_camera.add_keyframe(real_currframe, (camera.lens,))
         currframe += bake_step
 
     scene.frame_set(back_currframe, 0.0)
@@ -1958,6 +1967,18 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No
                     anim_data = animations[elem_key] = ("dummy_unused_key", OrderedDict())
                 anim_data[1][fbx_group] = (group_key, group, fbx_gname)
 
+    # And cameras' lens keys.
+    for cam_key, (anim_camera, camera) in animdata_cameras.items():
+        final_keys = OrderedDict()
+        anim_camera.simplify(simplify_fac, bake_step, force_keep)
+        if not anim_camera:
+            continue
+        for elem_key, group_key, group, fbx_group, fbx_gname in anim_camera.get_final_data(scene, ref_id, force_keep):
+                anim_data = animations.get(elem_key)
+                if anim_data is None:
+                    anim_data = animations[elem_key] = ("dummy_unused_key", OrderedDict())
+                anim_data[1][fbx_group] = (group_key, group, fbx_gname)
+
     astack_key = get_blender_anim_stack_key(scene, ref_id)
     alayer_key = get_blender_anim_layer_key(scene, ref_id)
     name = (get_blenderID_name(ref_id) if ref_id else scene.name).encode()
diff --git a/io_scene_fbx/fbx_utils.py b/io_scene_fbx/fbx_utils.py
index 368e8685..82e17fe2 100644
--- a/io_scene_fbx/fbx_utils.py
+++ b/io_scene_fbx/fbx_utils.py
@@ -729,6 +729,7 @@ class AnimationCurveNodeWrapper:
         'LCL_ROTATION': ("Lcl Rotation", "R", ("X", "Y", "Z")),
         'LCL_SCALING': ("Lcl Scaling", "S", ("X", "Y", "Z")),
         'SHAPE_KEY': ("DeformPercent", "DeformPercent", ("DeformPercent",)),
+        'CAMERA_FOCAL': ("FocalLength", "FocalLength", ("FocalLength",)),
     }
 
     def __init__(self, elem_key, kind, force_keying, force_startend_keying, default_values=...):
diff --git a/io_scene_fbx/import_fbx.py b/io_scene_fbx/import_fbx.py
index cb67aa76..c0d7b758 100644
--- a/io_scene_fbx/import_fbx.py
+++ b/io_scene_fbx/import_fbx.py
@@ -557,7 +557,7 @@ def blen_read_animations_action_item(action, item, cnodes, fps, anim_offset):
     'Bake' loc/rot/scale into the action,
     taking any pre_ and post_ matrix into account to transform from fbx into blender space.
     """
-    from bpy.types import Object, PoseBone, ShapeKey, Material
+    from bpy.types import Object, PoseBone, ShapeKey, Material, Camera
     from itertools import chain
 
     fbx_curves = []
@@ -577,6 +577,8 @@ def blen_read_animations_action_item(action, item, cnodes, fps, anim_offset):
         props = [("diffuse_color", 3, grpname or "Diffuse Color")]
     elif isinstance(item, ShapeKey):
         props = [(item.path_from_id("value"), 1, "Key")]
+    elif isinstance(item, Camera):
+        props = [(item.path_from_id("lens"), 1, "Camera")]
     else:  # Object or PoseBone:
         if item.is_bone:
             bl_obj = item.bl_obj.pose.bones[item.bl_bone]
@@ -624,6 +626,17 @@ def blen_read_animations_action_item(action, item, cnodes, fps, anim_offset):
             for fc, v in zip(blen_curves, (value,)):
                 fc.keyframe_points.insert(frame, v, {'NEEDED', 'FAST'}).interpolation = 'LINEAR'
 
+    elif isinstance(item, Camera):
+        for frame, values in blen_read_animations_curves_iter(fbx_curves, anim_offset, 0, fps):
+            value = 0.0
+            for v, (fbxprop, channel, _fbx_acdata) in values:
+                assert(fbxprop == b'FocalLength')
+                assert(channel == 0)
+                value = v
+
+            for fc, v in zip(blen_curves, (value,)):
+                fc.keyframe_points.insert(frame, v, {'NEEDED', 'FAST'}).interpolation = 'LINEAR'
+
     else:  # Object or PoseBone:
         if item.is_bone:
             bl_obj = item.bl_obj.pose.bones[item.bl_bone]
@@ -686,7 +699,7 @@ def blen_read_animations(fbx_tmpl_astack, fbx_tmpl_alayer, stacks, scene, anim_o
     Only the first found action is linked to objects, more complex setups are not handled,
     it's up to user to reproduce them!
     """
-    from bpy.types import ShapeKey, Material
+    from bpy.types import ShapeKey, Material, Camera
 
     actions = {}
     for as_uuid, ((fbx_asdata, _blen_data), alayers) in stacks.items():
@@ -698,6 +711,8 @@ def blen_read_animations(fbx_tmpl_astack, fbx_tmpl_alayer, stacks, scene, anim_o
                     id_data = item
                 elif isinstance(item, ShapeKey):
                     id_data = item.id_data
+                elif isinstance(item, Camera):
+                    id_data = item
                 else:
                     id_data = item.bl_obj
                     # XXX Ignore rigged mesh animations - those are a nightmare to handle, see note about it in
@@ -2838,6 +2853,13 @@ def load(operator, context, filepath="",
                         if keyblocks is None:
                             continue
                         items += [(kb, lnk_prop) for kb in keyblocks]
+                    elif lnk_prop == b'FocalLength':  # Camera lens.
+                        from bpy.types import Camera
+                        fbx_item = fbx_table_nodes.get(n_uuid, None)
+                        if fbx_item is None or not isinstance(fbx_item[1], Camera):
+                            continue
+                        cam = fbx_item[1]
+                        items.append((cam, lnk_prop))
                     elif lnk_prop == b'DiffuseColor':
                         from bpy.types import Material
                         fbx_item = fbx_table_nodes.get(n_uuid, None)
@@ -2874,7 +2896,11 @@ def load(operator, context, filepath="",
                         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': 0, b'd|Y': 1, b'd|Z': 2, b'd|DeformPercent': 0}.get(acn_ctype.props[3], None)
+                    channel = {
+                        b'd|X': 0, b'd|Y': 1, b'd|Z': 2,
+                        b'd|DeformPercent': 0,
+                        b'd|FocalLength': 0
+                    }.get(acn_ctype.props[3], None)
                     if channel is None:
                         continue
                     curvenodes[acn_uuid][ac_uuid] = (fbx_acitem, channel)



More information about the Bf-extensions-cvs mailing list