[Bf-extensions-cvs] [80a753b] fbx_io_development: Merge branch 'master' into fbx_io_development
Bastien Montagne
noreply at git.blender.org
Sun Jul 13 18:36:14 CEST 2014
Commit: 80a753be921cfa95a90e894f20c6b379883c416e
Author: Bastien Montagne
Date: Sun Jul 13 18:12:44 2014 +0200
https://developer.blender.org/rBA80a753be921cfa95a90e894f20c6b379883c416e
Merge branch 'master' into fbx_io_development
Conflicts:
io_scene_fbx/import_fbx.py
===================================================================
===================================================================
diff --cc io_scene_fbx/import_fbx.py
index 3466929,c5a12e0..757051d
--- a/io_scene_fbx/import_fbx.py
+++ b/io_scene_fbx/import_fbx.py
@@@ -405,370 -390,7 +404,371 @@@ def blen_read_object(fbx_tmpl, fbx_obj
return obj
+# --------
+# Armature
+
+def blen_read_armatures_add_bone(bl_obj, bl_arm, bones, b_uuid, matrices, fbx_tmpl_model):
+ from mathutils import Matrix, Vector
+
+ b_item, bsize, p_uuid, clusters = bones[b_uuid]
+ fbx_bdata, bl_bname = b_item
+ if bl_bname is not None:
+ return bl_arm.edit_bones[bl_bname] # Have already been created...
+
+ p_ebo = None
+ if p_uuid is not None:
+ # Recurse over parents!
+ p_ebo = blen_read_armatures_add_bone(bl_obj, bl_arm, bones, p_uuid, matrices, fbx_tmpl_model)
+
+ if clusters:
+ # Note in some cases, one bone can have several clusters (kind of LoD?), in Blender we'll always
+ # use only the first, for now.
+ fbx_cdata, meshes, objects = clusters[0]
+ objects = {blen_o for fbx_o, blen_o in objects}
+
+ # We assume matrices in cluster are rest pose of bones (they are in Global space!).
+ # TransformLink is matrix of bone, in global space.
+ # TransformAssociateModel is matrix of armature, in global space (at bind time).
+ elm = elem_find_first(fbx_cdata, b'Transform', default=None)
+ mmat_bone = array_to_matrix4(elm.props[0]) if elm is not None else None
+ elm = elem_find_first(fbx_cdata, b'TransformLink', default=None)
+ bmat_glob = array_to_matrix4(elm.props[0]) if elm is not None else Matrix()
+ elm = elem_find_first(fbx_cdata, b'TransformAssociateModel', default=None)
+ amat_glob = array_to_matrix4(elm.props[0]) if elm is not None else Matrix()
+
+ mmat_glob = bmat_glob * mmat_bone
+
+ # We seek for matrix of bone in armature space...
+ bmat_arm = amat_glob.inverted() * bmat_glob
+
+ # Bone correction, works here...
+ bmat_loc = (p_ebo.matrix.inverted() * bmat_arm) if p_ebo else bmat_arm
+ bmat_loc = bmat_loc * MAT_CONVERT_BONE
+ bmat_arm = (p_ebo.matrix * bmat_loc) if p_ebo else bmat_loc
+ else:
+ # Armature bound to no mesh...
+ fbx_cdata, meshes, objects = (None, (), ())
+ mmat_bone = None
+ amat_glob = bl_obj.matrix_world
+
+ fbx_props = (elem_find_first(fbx_bdata, b'Properties70'),
+ elem_find_first(fbx_tmpl_model, b'Properties70', fbx_elem_nil))
+ assert(fbx_props[0] is not None)
+
+ # Bone correction, works here...
+ transform_data = blen_read_object_transform_preprocess(fbx_props, fbx_bdata, MAT_CONVERT_BONE)
+ bmat_loc = blen_read_object_transform_do(transform_data)
+ # Bring back matrix in armature space.
+ bmat_arm = (p_ebo.matrix * bmat_loc) if p_ebo else bmat_loc
+
+ # ----
+ # Now, create the (edit)bone.
+ bone_name = elem_name_ensure_class(fbx_bdata, b'Model')
+
+ ebo = bl_arm.edit_bones.new(name=bone_name)
+ bone_name = ebo.name # Might differ from FBX bone name!
+ b_item[1] = bone_name # since ebo is only valid in Edit mode... :/
+
+ # So that our bone gets its final length, but still Y-aligned in armature space.
+ ebo.tail = Vector((0.0, 1.0, 0.0)) * bsize
+ # And rotate/move it to its final "rest pose".
+ ebo.matrix = bmat_arm.normalized()
+
+ # Connection to parent.
+ if p_ebo is not None:
+ ebo.parent = p_ebo
+ if similar_values_iter(p_ebo.tail, ebo.head):
+ ebo.use_connect = True
+
+ if fbx_cdata is not None:
+ # ----
+ # Add a new vgroup to the meshes (their objects, actually!).
+ # Quite obviously, only one mesh is expected...
+ indices = elem_prop_first(elem_find_first(fbx_cdata, b'Indexes', default=None), default=())
+ weights = elem_prop_first(elem_find_first(fbx_cdata, b'Weights', default=None), default=())
+ add_vgroup_to_objects(indices, weights, bone_name, objects)
+
+ # ----
+ # If we get a valid mesh matrix (in bone space), store armature and mesh global matrices, we need to set temporarily
+ # both objects to those matrices when actually binding them via the modifier.
+ # Note we assume all bones were bound with the same mesh/armature (global) matrix, we do not support otherwise
+ # in Blender anyway!
+ if mmat_bone is not None:
+ for obj in objects:
+ if obj in matrices:
+ continue
+ matrices[obj] = (amat_glob, mmat_glob)
+
+ return ebo
+
+
+def blen_read_armatures(fbx_tmpl, armatures, fbx_bones_to_fake_object, scene, global_matrix):
+ from mathutils import Matrix
+
+ if global_matrix is None:
+ global_matrix = Matrix()
+
+ for a_item, bones in armatures:
+ fbx_adata, bl_adata = a_item
+ matrices = {}
+
+ # ----
+ # Armature data.
+ elem_name_utf8 = elem_name_ensure_class(fbx_adata, b'Model')
+ bl_arm = bpy.data.armatures.new(name=elem_name_utf8)
+
+ # Need to create the object right now, since we can only add bones in Edit mode... :/
+ assert(a_item[1] is None)
+
+ if fbx_adata.props[2] in {b'LimbNode', b'Root'}:
+ # rootbone-as-armature case...
+ fbx_bones_to_fake_object[fbx_adata.props[0]] = bl_adata = blen_read_object(fbx_tmpl, fbx_adata, bl_arm)
+ # reset transform.
+ bl_adata.matrix_basis = Matrix()
+ else:
+ bl_adata = a_item[1] = blen_read_object(fbx_tmpl, fbx_adata, bl_arm)
+
+ # Instantiate in scene.
+ obj_base = scene.objects.link(bl_adata)
+ obj_base.select = True
+
+ # Switch to Edit mode.
+ scene.objects.active = bl_adata
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ for b_uuid in bones:
+ blen_read_armatures_add_bone(bl_adata, bl_arm, bones, b_uuid, matrices, fbx_tmpl)
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Bind armature to objects.
+ arm_mat_back = bl_adata.matrix_basis.copy()
+ for ob_me, (amat, mmat) in matrices.items():
+ # bring global armature & mesh matrices into *Blender* global space.
+ amat = global_matrix * amat
+ mmat = global_matrix * mmat
+
+ bl_adata.matrix_basis = amat
+ me_mat_back = ob_me.matrix_basis.copy()
+ ob_me.matrix_basis = mmat
+
+ mod = ob_me.modifiers.new(elem_name_utf8, 'ARMATURE')
+ mod.object = bl_adata
+
+ ob_me.parent = bl_adata
+ ob_me.matrix_basis = me_mat_back
+ bl_adata.matrix_basis = arm_mat_back
+
+ # Set Pose transformations...
+ for b_item, _b_size, _p_uuid, _clusters in bones.values():
+ fbx_bdata, bl_bname = b_item
+ fbx_props = (elem_find_first(fbx_bdata, b'Properties70'),
+ elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil))
+ assert(fbx_props[0] is not None)
+
+ pbo = b_item[1] = bl_adata.pose.bones[bl_bname]
+ transform_data = object_tdata_cache.get(pbo)
+ if transform_data is None:
+ # Bone correction, gives a mess as result. :(
+ transform_data = blen_read_object_transform_preprocess(fbx_props, fbx_bdata, MAT_CONVERT_BONE)
+ object_tdata_cache[pbo] = transform_data
+ mat = blen_read_object_transform_do(transform_data)
+ if pbo.parent:
+ # Bring back matrix in armature space.
+ mat = pbo.parent.matrix * mat
+ pbo.matrix = mat
+
+
+# ---------
+# Animation
+def blen_read_animations_curves_iter(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.
+ blen_start_offset is expected in frames, while fbx_start_offset is expected in FBX ktime.
+ """
+ # As a first step, assume linear interpolation between key frames, we'll (try to!) handle more
+ # of FBX curves later.
+ 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)
+
+ while True:
+ tmin = min(fbx_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
+ if idx != -1:
+ do_break = False
+ if times[idx] > curr_fbxktime:
+ if idx == 0:
+ curr_values.append(values[idx])
+ 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])
+ else:
+ curr_values.append(values[idx])
+ if idx >= 0:
+ idx += 1
+ if idx >= len(times):
+ # We have reached our last element for this curve, stay on it from now on...
+ idx = -1
+ item[0] = idx
+ curr_blenkframe = (curr_fbxktime - fbx_start_offset) * timefac + blen_start_offset
+ yield (curr_blenkframe, curr_values)
+ if do_break:
+ break
+
+
+def blen_read_animations_action_object(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 chai
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list