Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2018-02-19 19:27:05 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2018-02-19 19:27:05 +0300
commitb890f0d7e8a666cb82a908cf9b06c6b500e9e2fc (patch)
tree81453b3fdcb4b365d18abba286a96c270cd8c5d7
parent7e18281d2f1039bf281968427fec45daa79c7531 (diff)
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...
-rw-r--r--io_scene_fbx/export_fbx_bin.py23
-rw-r--r--io_scene_fbx/fbx_utils.py1
-rw-r--r--io_scene_fbx/import_fbx.py32
3 files changed, 52 insertions, 4 deletions
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)