How to rig a mesh of obj file with FBX Python SDK

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
What I want to do is import obj file and rig it with FBX Python SDK. As far as I understand from the sample code of ExportScene01.py, what I should do is as follow.
- create fbx manager and fbx scene
- load obj file and fill the scene with it
- create skeletons and their hierarchy, and add skeleton root to scene
- create clusters for each skeleton
- create skin (deformer) and add clusters to it
- add skin to mesh attribute
- save to fbx file
However, when I import fbx file to Autodesk Maya, the following error occurs.
The imported scene has no initial binding position (Bind Pose) for the skin. The plug-in will compute one automatically. However, running the 'Go To Bind Pose' command may create unexpected results
My code is based on ExportScene01.py but why do I need to initialize binding position in my case? and actually I don't know how to do it.
In addition, when I import the fbx file to blender, blender doesn't display mesh, and some skeletons' positions are incorrect.
I exported fbx files of "mesh only", "skeletons only", "mesh and skeletons (without binding)" each, and their result looks good. So maybe the problem occurs at binding. Could anybody help me, please? I'm struggling to deal with this problem for about a week.
My codes are as follow:
import FbxCommon
from fbx import *
def get_keypoint_pos_dict():
keypoint_dict = {
"Neck": [0.502, 0.722, 0.490],
"RShoulder": [0.428, 0.721, 0.480],
"RElbow": [0.354, 0.622, 0.482],
"RWrist": [0.278, 0.540, 0.545],
...
"RSmallToe": [0.397, 0.068, 0.520],
"RHeel": [0.425, 0.090, 0.452],
}
return keypoint_dict_filtered
def create_skeleton_tree(fbx_manager, keypoint_dict):
# root node
root_name = "skeleton_root"
root_attr = FbxSkeleton.Create(fbx_manager, root_name)
root_attr.SetSkeletonType(FbxSkeleton.eRoot)
root_node = FbxNode.Create(fbx_manager, root_name)
root_node.SetNodeAttribute(root_attr)
root_node.LclScaling.Set(FbxDouble3(0.1, 0.1, 0.1))
# skeletons
skeleton_nodes = {}
for key in keypoint_dict:
node_name = key
node_attr = FbxSkeleton.Create(fbx_manager, node_name)
node_attr.SetSkeletonType(FbxSkeleton.eLimbNode)
node = FbxNode.Create(fbx_manager, "skeleton_" + node_name)
node.SetNodeAttribute(node_attr)
node.LclScaling.Set(FbxDouble3(0.1, 0.1, 0.1))
skeleton_nodes[key] = node
root_node.AddChild(skeleton_nodes["MidHip"])
skeleton_nodes["MidHip"].AddChild(skeleton_nodes["Neck"])
skeleton_nodes["Neck"].AddChild(skeleton_nodes["LShoulder"])
skeleton_nodes["LShoulder"].AddChild(skeleton_nodes["LElbow"])
skeleton_nodes["LElbow"].AddChild(skeleton_nodes["LWrist"])
skeleton_nodes["Neck"].AddChild(skeleton_nodes["RShoulder"])
skeleton_nodes["RShoulder"].AddChild(skeleton_nodes["RElbow"])
skeleton_nodes["RElbow"].AddChild(skeleton_nodes["RWrist"])
...
skeleton_nodes["RBigToe"].AddChild(skeleton_nodes["RSmallToe"])
return root_node
def set_skeleton_pose(skeleton_node, keypoint_pos_dict):
if skeleton_node.GetNodeAttribute():
skeleton_type = skeleton_node.GetNodeAttribute().GetSkeletonType()
if skeleton_type == FbxSkeleton.eRoot:
skeleton_node.LclTranslation.Set(FbxDouble3(0.0, 0.0, 0.0))
elif skeleton_type == FbxSkeleton.eLimbNode:
skeleton_node_name = skeleton_node.GetName()
parent_node_name = skeleton_node.GetParent().GetName()
skeleton_node_pos = np.array(keypoint_pos_dict[skeleton_node_name.replace("skeleton_", "")])
if parent_node_name == "skeleton_root":
parent_node_pos = np.array([0.0, 0.0, 0.0])
else:
parent_node_pos = np.array(keypoint_pos_dict[parent_node_name.replace("skeleton_", "")])
local_translation = skeleton_node_pos - parent_node_pos
skeleton_node.LclTranslation.Set(FbxDouble3(*local_translation))
for i in range(skeleton_node.GetChildCount()):
set_skeleton_pose(skeleton_node.GetChild(i), keypoint_pos_dict)
def create_cps_weight_dict(mesh_attr, keypoint_pos_dict):
cps_weight_dict = {
"Neck": [0.0, 0.0, 0.0, ...],
"RShoulder": [0.0, 0.0, 0.0, ...],
"RElbow": [0.0, 0.0, 0.0, ...],
"RWrist": [0.2, 0.2, 0.2, ...],
...
"RSmallToe": [0.0, 0.0, 0.0, ...],
"RHeel": [0.0, 0.0, 0.0, ...],
}
return cps_weight_dict
def create_skin(manager, scene, mesh_node, skeleton_root, cps_weight_dict):
cluster_to_root = FbxCluster.Create(manager, "cluster_to_root")
cluster_to_root.SetLink(skeleton_root)
cluster_to_root.SetLinkMode(FbxCluster.eAdditive)
cluster_dict = {}
for key in cps_weight_dict:
cluster_dict[key] = FbxCluster.Create(manager, "cluster_to_"+key)
cluster_dict[key].SetLink(scene.FindNodeByName("skeleton_"+key))
cluster_dict[key].SetLinkMode(FbxCluster.eAdditive)
for i in range(len(cps_weight_dict[key])):
if cps_weight_dict[key][i] != 0:
cluster_dict[key].AddControlPointIndex(i, cps_weight_dict[key][i])
# set transform matrix (matrix from mesh node)
x_mat = scene.GetAnimationEvaluator().GetNodeGlobalTransform(mesh_node)
cluster_to_root.SetTransformMatrix(x_mat)
for key in cluster_dict:
cluster_dict[key].SetTransformMatrix(x_mat)
# set transform link matrix (root node)
x_mat = scene.GetAnimationEvaluator().GetNodeGlobalTransform(skeleton_root)
cluster_to_root.SetTransformLinkMatrix(x_mat)
# set transform link matrix (each limb)
for key in cluster_dict:
x_mat = scene.GetAnimationEvaluator().GetNodeGlobalTransform(scene.FindNodeByName("skeleton_"+key))
cluster_dict[key].SetTransformLinkMatrix(x_mat)
# create skin and add cluster
skin = FbxSkin.Create(manager, "")
skin.AddCluster(cluster_to_root)
for key in cluster_dict:
skin.AddCluster(cluster_dict[key])
return skin
if __name__ == "__main__":
manager, scene = FbxCommon.InitializeSdkObjects()
print("Add Mesh")
FbxCommon.LoadScene(manager, scene, "./mesh_file.obj")
scene.GetRootNode().GetChild(0).GetChild(0).SetName("mesh_node")
FbxGeometryConverter(manager).Triangulate(scene, True)
print("Add Skeleton")
keypoint_pos_dict = get_keypoint_pos_dict()
skeleton_root = create_skeleton_tree(manager, keypoint_pos_dict)
set_skeleton_pose(skeleton_root, keypoint_pos_dict)
scene.GetRootNode().GetChild(0).AddChild(skeleton_root)
print("Calculate weight for each control points, for each keypoint")
mesh_node = scene.FindNodeByName("mesh_node")
mesh_node = scene.GetRootNode().GetChild(0).GetChild(0)
mesh_attr = mesh_node.GetNodeAttribute()
cps_weight_dict = create_cps_weight_dict(mesh_attr, keypoint_pos_dict)
print("Create skin")
skin = create_skin(manager, scene, mesh_node, skeleton_root, cps_weight_dict)
print("Bind")
mesh_attr.AddDeformer(skin)
print("Save to fbx")
FbxCommon.SaveScene(manager, scene, "./mesh_with_bind.fbx", pFileFormat=0)