[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