[Bf-extensions-cvs] [2e372f0] fbx_io_development: FBX import: Refactor anim system a bit.
Bastien Montagne
noreply at git.blender.org
Mon Jul 21 21:16:33 CEST 2014
Commit: 2e372f06d6f59e98801eddfa7574c37f710f7b44
Author: Bastien Montagne
Date: Mon Jul 21 21:11:46 2014 +0200
Branches: fbx_io_development
https://developer.blender.org/rBA2e372f06d6f59e98801eddfa7574c37f710f7b44
FBX import: Refactor anim system a bit.
Hopefully it's more consistent now, should be easier too if we want to read more
animated things later (like materials things...).
===================================================================
M io_scene_fbx/import_fbx.py
===================================================================
diff --git a/io_scene_fbx/import_fbx.py b/io_scene_fbx/import_fbx.py
index ff75011..18f31a0 100644
--- a/io_scene_fbx/import_fbx.py
+++ b/io_scene_fbx/import_fbx.py
@@ -583,7 +583,7 @@ def blen_read_armatures(fbx_tmpl, armatures, fbx_bones_to_fake_object, scene, gl
# ---------
# Animation
-def blen_read_animations_curves_iter(curves, blen_start_offset, fbx_start_offset, fps):
+def blen_read_animations_curves_iter(fbx_curves, blen_start_offset, fbx_start_offset, fps):
"""
Get raw FBX AnimCurve list, and yield values for all curves at each singular curves' keyframes,
together with (blender) timing, in frames.
@@ -594,29 +594,30 @@ def blen_read_animations_curves_iter(curves, blen_start_offset, fbx_start_offset
from .fbx_utils import FBX_KTIME
timefac = fps / FBX_KTIME
- fbx_curves = tuple([0,
- elem_prop_first(elem_find_first(c[2], b'KeyTime')),
- elem_prop_first(elem_find_first(c[2], b'KeyValueFloat'))]
- for c in curves)
+ curves = tuple([0,
+ elem_prop_first(elem_find_first(c[2], b'KeyTime')),
+ elem_prop_first(elem_find_first(c[2], b'KeyValueFloat')),
+ c]
+ for c in fbx_curves)
while True:
- tmin = min(fbx_curves, key=lambda e: e[1][e[0]])
+ tmin = min(curves, key=lambda e: e[1][e[0]])
curr_fbxktime = tmin[1][tmin[0]]
curr_values = []
do_break = True
- for item in fbx_curves:
- idx, times, values = item
+ for item in curves:
+ idx, times, values, fbx_curve = item
if idx != -1:
do_break = False
if times[idx] > curr_fbxktime:
if idx == 0:
- curr_values.append(values[idx])
+ curr_values.append((values[idx], fbx_curve))
else:
# Interpolate between this key and the previous one.
ifac = (curr_fbxktime - times[idx - 1]) / (times[idx] - times[idx - 1])
- curr_values.append((values[idx] - values[idx - 1]) * ifac + values[idx - 1])
+ curr_values.append(((values[idx] - values[idx - 1]) * ifac + values[idx - 1], fbx_curve))
else:
- curr_values.append(values[idx])
+ curr_values.append((values[idx], fbx_curve))
if idx >= 0:
idx += 1
if idx >= len(times):
@@ -629,109 +630,107 @@ def blen_read_animations_curves_iter(curves, blen_start_offset, fbx_start_offset
break
-def blen_read_animations_action_object(action, ob, obpath, grpname, cnodes, global_matrix, force_global, fps):
+def blen_read_animations_action_item(action, item, cnodes, global_matrix, force_global, fps):
"""
'Bake' loc/rot/scale into the action, taking into account global_matrix if no parent is present.
"""
- from bpy.types import Object
+ from bpy.types import Object, PoseBone, ShapeKey
from mathutils import Euler, Matrix
from itertools import chain
- if ob not in object_tdata_cache:
- print("ERROR! object '%s' has no transform data, while being animated!" % ob.name)
-
+ blen_curves = []
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 = ((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 = ((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 = ((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))
-
- transform_data = object_tdata_cache[ob]
-
- rot_prev = ob.rotation_euler.copy()
- # 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):
- if fbxprop == b'Lcl Translation':
- transform_data.loc[channel] = v
- elif fbxprop == b'Lcl Rotation':
- transform_data.rot[channel] = v
- elif fbxprop == b'Lcl Scaling':
- transform_data.sca[channel] = v
- mat = blen_read_object_transform_do(transform_data)
- # Don't forget global matrix - but never for bones!
- if isinstance(ob, Object):
- if (not ob.parent or force_global) 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()
+ props = []
+
+ if isinstance(item, ShapeKey):
+ props = [(item.path_from_id("value"), 1, "Key")]
+ else: # Object or PoseBone:
+ if item not in object_tdata_cache:
+ print("ERROR! object '%s' has no transform data, while being animated!" % ob.name)
+ return
+
+ # We want to create actions for objects, but for bones we 'reuse' armatures' actions!
+ grpname = None
+ if item.id_data != item:
+ grpname = item.name
+
+ # 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.
+ props = [(item.path_from_id("location"), 3, grpname or "Location"),
+ None,
+ (item.path_from_id("scale"), 3, grpname or "Scale")]
+ rot_mode = item.rotation_mode
if rot_mode == 'QUATERNION':
- pass # nothing to do!
+ props[1] = (item.path_from_id("rotation_quaternion"), 4, grpname or "Quaternion Rotation")
elif rot_mode == 'AXIS_ANGLE':
- vec, ang = rot.to_axis_angle()
- rot = ang, vec.x, vec.y, vec.z
+ props[1] = (item.path_from_id("rotation_axis_angle"), 4, grpname or "Axis Angle Rotation")
else: # Euler
- rot = rot.to_euler(rot_mode, rot_prev)
- rot_prev = rot
- for fc, value in zip(blen_curves, chain(loc, rot, sca)):
- fc.keyframe_points.insert(frame, value, {'NEEDED', 'FAST'}).interpolation = 'LINEAR'
-
- # Since we inserted our keyframes in 'FAST' mode, we have to update the fcurves now.
- for fc in blen_curves:
- fc.update()
+ props[1] = (item.path_from_id("rotation_euler"), 3, grpname or "Euler Rotation")
+ blen_curves = [action.fcurves.new(prop, channel, grpname)
+ for prop, nbr_channels, grpname in props for channel in range(nbr_channels)]
-def blen_read_animations_action_shapes(action, kb, curves, fps):
- """
- 'Bake' shapekeys' value into the action.
- """
- fbx_curves = []
- kbpath = kb.path_from_id("value")
-
- blen_curves = [action.fcurves.new(kbpath, 0, "Key")]
- for ac_uuid, ((fbx_acdata, _blen_data), channel) in curves.items():
- fbx_curves.append((b'DeformPercent', channel, fbx_acdata))
-
- # 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):
- value = 0.0
- for v, (fbxprop, channel, _fbx_acdata) in zip(values, fbx_curves):
- assert(fbxprop == b'DeformPercent')
- value = v / 100.0
+ for curves, fbxprop in cnodes.values():
+ for (fbx_acdata, _blen_data), channel in curves.values():
+ fbx_curves.append((fbxprop, channel, fbx_acdata))
- for fc, v in zip(blen_curves, (value,)):
- fc.keyframe_points.insert(frame, v, {'NEEDED', 'FAST'}).interpolation = 'LINEAR'
+ if isinstance(item, ShapeKey):
+ # 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):
+ value = 0.0
+ for v, (fbxprop, channel, _fbx_acdata) in values:
+ assert(fbxprop == b'DeformPercent')
+ assert(channel == 0)
+ value = v / 100.0
+
+ for fc, v in zip(blen_curves, (value,)):
+ fc.keyframe_points.insert(frame, v, {'NEEDED', 'FAST'}).interpolation = 'LINEAR'
+
+ else: # Object or PoseBone:
+ transform_data = object_tdata_cache[item]
+ rot_prev = item.rotation_euler.copy()
+
+ # 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 values:
+ if fbxprop == b'Lcl Translation':
+ transform_data.loc[channel] = v
+ elif fbxprop == b'Lcl Rotation':
+ transform_data.rot
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list