[Bf-extensions-cvs] [aab3a66] fbx_io_development: FBX import: support animation for bones as well.
Bastien Montagne
noreply at git.blender.org
Fri May 23 17:49:38 CEST 2014
Commit: aab3a6647b3cb07a2a806191f82e1f68bd8f5813
Author: Bastien Montagne
Date: Fri May 23 16:39:03 2014 +0200
https://developer.blender.org/rBAaab3a6647b3cb07a2a806191f82e1f68bd8f5813
FBX import: support animation for bones as well.
===================================================================
M io_scene_fbx/import_fbx.py
===================================================================
diff --git a/io_scene_fbx/import_fbx.py b/io_scene_fbx/import_fbx.py
index dbc9bee..d94bb63 100644
--- a/io_scene_fbx/import_fbx.py
+++ b/io_scene_fbx/import_fbx.py
@@ -592,28 +592,35 @@ def blen_read_animations_curves_iter(curves, blen_start_offset, fbx_start_offset
break
-def blen_read_animations_action(action, ob, cnodes, global_matrix, fps):
+def blen_read_animations_action(action, ob, obpath, grpname, cnodes, global_matrix, fps):
"""
'Bake' loc/rot/scale into the action, taking into account global_matrix if no parent is present.
"""
+ from bpy.types import Object
from mathutils import Euler, Matrix
from itertools import chain
if ob not in object_tdata_cache:
- printf("ERROR! object '%s' has no transform data, while being animated!" % ob.name)
+ print("ERROR! object '%s' has no transform data, while being animated!" % ob.name)
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 = (("location", 3), ("rotation_quaternion", 4), ("scale", 3))
+ 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 = (("location", 3), ("rotation_axis_angle", 4), ("scale", 3))
+ 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 = (("location", 3), ("rotation_euler", 3), ("scale", 3))
- blen_curves = [action.fcurves.new(obprop, channel, obprop)
- for obprop, nbr_channels in obprops for channel in range(nbr_channels)]
+ 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))
@@ -621,9 +628,9 @@ def blen_read_animations_action(action, ob, cnodes, global_matrix, fps):
transform_data = object_tdata_cache[ob]
rot_prev = ob.rotation_euler.copy()
- for frame, values in blen_read_animations_curves_iter(fbx_curves, 0.0, 0.0, fps):
+ # 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):
- print(frame, fbxprop, channel, v)
if fbxprop == b'Lcl Translation':
transform_data.loc[channel] = v
elif fbxprop == b'Lcl Rotation':
@@ -631,9 +638,17 @@ def blen_read_animations_action(action, ob, cnodes, global_matrix, fps):
elif fbxprop == b'Lcl Scaling':
transform_data.sca[channel] = v
mat = blen_read_object_transform_do(transform_data)
- # Don't forget global matrix!
- if not ob.parent and global_matrix is not None:
- mat = global_matrix * mat
+ # Don't forget global matrix - but never for bones!
+ if isinstance(ob, Object):
+ if not ob.parent 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()
@@ -658,19 +673,28 @@ def blen_read_animations(fbx_tmpl_astack, fbx_tmpl_alayer, stacks, scene, global
Recreate an action per stack/layer/object combinations.
Note actions are not linked to objects, this is up to the user!
"""
+ actions = {}
for as_uuid, ((fbx_asdata, _blen_data), alayers) in stacks.items():
stack_name = elem_name_ensure_class(fbx_asdata, b'AnimStack')
- print("Stack {}:".format(stack_name))
for al_uuid, ((fbx_aldata, _blen_data), objects) in alayers.items():
layer_name = elem_name_ensure_class(fbx_aldata, b'AnimLayer')
- print(" " * 4 + "Layer {} ({} objects):".format(layer_name, len(objects)))
for ob, cnodes in objects.items():
- action_name = "|".join((ob.name, stack_name, layer_name))
- action = bpy.data.actions.new(action_name)
- action.use_fake_user = True
- print(" " * 8 + "Action {} for object {}: {} animated properties:"
- "".format(action_name, ob.name, len(cnodes)))
- blen_read_animations_action(action, ob, cnodes, global_matrix, scene.render.fps)
+ # We want to create actions for objects, but for bones we 'reuse' armatures' actions!
+ id_data = ob.id_data
+ key = (as_uuid, al_uuid, id_data)
+ if key in actions:
+ action = actions[key]
+ else:
+ action_name = "|".join((id_data.name, stack_name, layer_name))
+ actions[key] = action = bpy.data.actions.new(action_name)
+ action.use_fake_user = True
+ if id_data == ob:
+ obpath = ""
+ grpname = None
+ else:
+ obpath = ob.path_from_id() + "."
+ grpname = ob.name
+ blen_read_animations_action(action, ob, obpath, grpname, cnodes, global_matrix, scene.render.fps)
# ----
More information about the Bf-extensions-cvs
mailing list