[Bf-extensions-cvs] [0abd36f] master: FBX export: add shape keys support (no anim yet).

Bastien Montagne noreply at git.blender.org
Sun Jul 6 22:02:29 CEST 2014


Commit: 0abd36f1ecbe687a9a5c9d1eccac7484799145a4
Author: Bastien Montagne
Date:   Sun Jul 6 21:08:16 2014 +0200
https://developer.blender.org/rBA0abd36f1ecbe687a9a5c9d1eccac7484799145a4

FBX export: add shape keys support (no anim yet).

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

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

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

diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py
index 928c296..adc0cd4 100644
--- a/io_scene_fbx/export_fbx_bin.py
+++ b/io_scene_fbx/export_fbx_bin.py
@@ -51,6 +51,7 @@ from .fbx_utils import (
     FBX_GEOMETRY_VERSION, FBX_GEOMETRY_NORMAL_VERSION, FBX_GEOMETRY_BINORMAL_VERSION, FBX_GEOMETRY_TANGENT_VERSION,
     FBX_GEOMETRY_SMOOTHING_VERSION, FBX_GEOMETRY_VCOLOR_VERSION, FBX_GEOMETRY_UV_VERSION,
     FBX_GEOMETRY_MATERIAL_VERSION, FBX_GEOMETRY_LAYER_VERSION,
+    FBX_GEOMETRY_SHAPE_VERSION, FBX_DEFORMER_SHAPE_VERSION, FBX_DEFORMER_SHAPECHANNEL_VERSION,
     FBX_POSE_BIND_VERSION, FBX_DEFORMER_SKIN_VERSION, FBX_DEFORMER_CLUSTER_VERSION,
     FBX_MATERIAL_VERSION, FBX_TEXTURE_VERSION,
     FBX_ANIM_KEY_VERSION,
@@ -59,13 +60,14 @@ from .fbx_utils import (
     FBX_LIGHT_TYPES, FBX_LIGHT_DECAY_TYPES,
     RIGHT_HAND_AXES, FBX_FRAMERATES,
     # Miscellaneous utils.
-    units_convertor, units_convertor_iter, matrix4_to_array, similar_values,
+    units_convertor, units_convertor_iter, matrix4_to_array, similar_values, similar_values_iter,
     # UUID from key.
     get_fbx_uuid_from_key,
     # Key generators.
     get_blenderID_key, get_blenderID_name,
+    get_blender_mesh_shape_key, get_blender_mesh_shape_channel_key,
     get_blender_empty_key, get_blender_bone_key,
-    get_blender_armature_bindpose_key, get_blender_armature_skin_key, get_blender_bone_cluster_key,
+    get_blender_bindpose_key, get_blender_armature_skin_key, get_blender_bone_cluster_key,
     get_blender_anim_id_base, get_blender_anim_stack_key, get_blender_anim_layer_key,
     get_blender_anim_curve_node_key, get_blender_anim_curve_key,
     # FBX element data.
@@ -683,6 +685,105 @@ def fbx_data_camera_elements(root, cam_obj, scene_data):
     elem_data_single_float64(cam, b"CameraOrthoZoom", 1.0)
 
 
+def fbx_data_bindpose_element(root, me_obj, me, scene_data, arm_obj=None, bones=[]):
+    """
+    Helper, since bindpose are used by both meshes shape keys and armature bones...
+    """
+    if arm_obj is None:
+        arm_obj = me_obj
+    # We assume bind pose for our bones are their "Editmode" pose...
+    # All matrices are expected in global (world) space.
+    bindpose_key = get_blender_bindpose_key(arm_obj.bdata, me)
+    fbx_pose = elem_data_single_int64(root, b"Pose", get_fbx_uuid_from_key(bindpose_key))
+    fbx_pose.add_string(fbx_name_class(me.name.encode(), b"Pose"))
+    fbx_pose.add_string(b"BindPose")
+
+    elem_data_single_string(fbx_pose, b"Type", b"BindPose")
+    elem_data_single_int32(fbx_pose, b"Version", FBX_POSE_BIND_VERSION)
+    elem_data_single_int32(fbx_pose, b"NbPoseNodes", 1 + len(bones))
+
+    # First node is mesh/object.
+    mat_world_obj = me_obj.fbx_object_matrix(scene_data, global_space=True)
+    fbx_posenode = elem_empty(fbx_pose, b"PoseNode")
+    elem_data_single_int64(fbx_posenode, b"Node", me_obj.fbx_uuid)
+    elem_data_single_float64_array(fbx_posenode, b"Matrix", matrix4_to_array(mat_world_obj))
+    # And all bones of armature!
+    mat_world_bones = {}
+    for bo_obj in bones:
+        bomat = bo_obj.fbx_object_matrix(scene_data, rest=True, global_space=True)
+        mat_world_bones[bo_obj] = bomat
+        fbx_posenode = elem_empty(fbx_pose, b"PoseNode")
+        elem_data_single_int64(fbx_posenode, b"Node", bo_obj.fbx_uuid)
+        elem_data_single_float64_array(fbx_posenode, b"Matrix", matrix4_to_array(bomat))
+
+    return mat_world_obj, mat_world_bones
+
+
+def fbx_data_mesh_shapes_elements(root, me_obj, me, scene_data, fbx_me_tmpl, fbx_me_props):
+    """
+    Write shape keys related data.
+    """
+    if me not in scene_data.data_deformers_shape:
+        return
+
+    # First, write the geometry data itself (i.e. shapes).
+    _me_key, shape_key, shapes = scene_data.data_deformers_shape[me]
+
+    channels = []
+
+    for shape, (channel_key, geom_key, shape_verts_co, shape_verts_idx) in shapes.items():
+        # Use vgroups as weights, if defined.
+        if shape.vertex_group and shape.vertex_group in me_obj.bdata.vertex_groups:
+            shape_verts_weights = [0.0] * (len(shape_verts_co) // 3)
+            vg_idx = me_obj.bdata.vertex_groups[shape.vertex_group].index
+            for sk_idx, v_idx in enumerate(shape_verts_idx):
+                for vg in me.vertices[v_idx].groups:
+                    if vg.group == vg_idx:
+                        shape_verts_weights[sk_idx] = vg.weight * 100.0
+        else:
+            shape_verts_weights = [100.0] * (len(shape_verts_co) // 3)
+        channels.append((channel_key, shape, shape_verts_weights))
+
+        geom = elem_data_single_int64(root, b"Geometry", get_fbx_uuid_from_key(geom_key))
+        geom.add_string(fbx_name_class(shape.name.encode(), b"Geometry"))
+        geom.add_string(b"Shape")
+
+        tmpl = elem_props_template_init(scene_data.templates, b"Geometry")
+        props = elem_properties(geom)
+        elem_props_template_finalize(tmpl, props)
+
+        elem_data_single_int32(geom, b"Version", FBX_GEOMETRY_SHAPE_VERSION)
+
+        elem_data_single_int32_array(geom, b"Indexes", shape_verts_idx)
+        elem_data_single_float64_array(geom, b"Vertices", shape_verts_co)
+        elem_data_single_float64_array(geom, b"Normals", [0.0] * len(shape_verts_co))
+
+    # Yiha! BindPose for shapekeys too! Dodecasigh...
+    # XXX Not sure yet whether several bindposes on same mesh are allowed, or not... :/
+    fbx_data_bindpose_element(root, me_obj, me, scene_data)
+
+    # ...and now, the deformers stuff.
+    fbx_shape = elem_data_single_int64(root, b"Deformer", get_fbx_uuid_from_key(shape_key))
+    fbx_shape.add_string(fbx_name_class(me.name.encode(), b"Deformer"))
+    fbx_shape.add_string(b"BlendShape")
+
+    elem_data_single_int32(fbx_shape, b"Version", FBX_DEFORMER_SHAPE_VERSION)
+
+    for channel_key, shape, shape_verts_weights in channels:
+        fbx_channel = elem_data_single_int64(root, b"Deformer", get_fbx_uuid_from_key(channel_key))
+        fbx_channel.add_string(fbx_name_class(shape.name.encode(), b"SubDeformer"))
+        fbx_channel.add_string(b"BlendShapeChannel")
+
+        elem_data_single_int32(fbx_channel, b"Version", FBX_DEFORMER_SHAPECHANNEL_VERSION)
+        elem_data_single_float64(fbx_channel, b"DeformPercent", shape.value * 100.0)  # Percents...
+        elem_data_single_float64_array(fbx_channel, b"FullWeights", shape_verts_weights)
+
+        # *WHY* add this in linked mesh properties too? *cry*
+        # No idea whether it’s percent here too, or more usual factor (assume percentage for now) :/
+        elem_props_template_set(fbx_me_tmpl, fbx_me_props, "p_number", shape.name.encode(), shape.value * 100.0,
+                                animatable=True)
+
+
 def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
     """
     Write the Mesh (Geometry) data block.
@@ -701,7 +802,7 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
     # No gscale/gmat here, all data are supposed to be in object space.
     smooth_type = scene_data.settings.mesh_smooth_type
 
-    do_bake_space_transform = ObjectWrapper(me_obj).use_bake_space_transform(scene_data)
+    do_bake_space_transform = me_obj.use_bake_space_transform(scene_data)
 
     # Vertices are in object space, but we are post-multiplying all transforms with the inverse of the
     # global matrix, so we need to apply the global matrix to the vertices to get the correct result.
@@ -720,8 +821,6 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
     tmpl = elem_props_template_init(scene_data.templates, b"Geometry")
     props = elem_properties(geom)
 
-    elem_props_template_finalize(tmpl, props)
-
     # Custom properties.
     if scene_data.settings.use_custom_properties:
         fbx_data_element_custom_properties(props, me)
@@ -1061,6 +1160,10 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
             elem_data_single_string(lay_tan, b"Type", b"LayerElementTangent")
             elem_data_single_int32(lay_tan, b"TypedIndex", tspaceidx)
 
+    # Shape keys...
+    fbx_data_mesh_shapes_elements(root, me_obj, me, scene_data, tmpl, props)
+
+    elem_props_template_finalize(tmpl, props)
     done_meshes.add(me_key)
 
 
@@ -1272,36 +1375,14 @@ def fbx_data_armature_elements(root, arm_obj, scene_data):
         if scene_data.settings.use_custom_properties:
             fbx_data_element_custom_properties(props, bo)
 
-    # Deformers and BindPoses.
+    # Skin deformers and BindPoses.
     # Note: we might also use Deformers for our "parent to vertex" stuff???
-    deformer = scene_data.data_deformers.get(arm_obj, None)
+    deformer = scene_data.data_deformers_skin.get(arm_obj, None)
     if deformer is not None:
         for me, (skin_key, ob_obj, clusters) in deformer.items():
             # BindPose.
-            # We assume bind pose for our bones are their "Editmode" pose...
-            # All matrices are expected in global (world) space.
-            bindpose_key = get_blender_armature_bindpose_key(arm_obj.bdata, me)
-            fbx_pose = elem_data_single_int64(root, b"Pose", get_fbx_uuid_from_key(bindpose_key))
-            fbx_pose.add_string(fbx_name_class(me.name.encode(), b"Pose"))
-            fbx_pose.add_string(b"BindPose")
-
-            elem_data_single_string(fbx_pose, b"Type", b"BindPose")
-            elem_data_single_int32(fbx_pose, b"Version", FBX_POSE_BIND_VERSION)
-            elem_data_single_int32(fbx_pose, b"NbPoseNodes", 1 + len(bones))
-
-            # First node is mesh/object.
-            mat_world_obj = ob_obj.fbx_object_matrix(scene_data, global_space=True)
-            fbx_posenode = elem_empty(fbx_pose, b"PoseNode")
-            elem_data_single_int64(fbx_posenode, b"Node", ob_obj.fbx_uuid)
-            elem_data_single_float64_array(fbx_posenode, b"Matrix", matrix4_to_array(mat_world_obj))
-            # And all bones of armature!
-            mat_world_bones = {}
-            for bo_obj in bones:
-                bomat = bo_obj.fbx_object_matrix(scene_data, rest=True, global_space=True)
-                mat_world_bones[bo_obj] = bomat
-                fbx_posenode = elem_empty(fbx_pose, b"PoseNode")
-               

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list