Created
January 3, 2022 12:45
-
-
Save creativeIKEP/7634b5b5f616a087dcb10b925168053a to your computer and use it in GitHub Desktop.
Auto rigging for mimiclear with Blender and Kinect
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# BlenderのAPIを呼び出すのに必要 | |
import bpy | |
import os | |
import csv | |
directory = os.path.dirname(bpy.data.filepath) | |
def delete_all_objects(): | |
# 全データオブジェクトを削除する | |
for item in bpy.data.objects: | |
bpy.data.objects.remove(item) | |
# 全メッシュデータを削除する | |
for item in bpy.data.meshes: | |
bpy.data.meshes.remove(item) | |
# 全マテリアルデータを削除する | |
for item in bpy.data.materials: | |
bpy.data.materials.remove(item) | |
return | |
# PIFuHDが生成したOBJファイルをBlenderのシーンにインポート | |
def mesh_import(): | |
path = os.path.join(directory, "Avatar.obj") | |
bpy.ops.import_scene.obj(filepath=path) | |
return bpy.context.scene.objects["Avatar"] | |
# メッシュデータをリグ付けりやすくする | |
def fix_model(object): | |
bpy.context.view_layer.objects.active = object | |
bpy.ops.object.mode_set(mode="EDIT") | |
bpy.ops.mesh.select_all(action="SELECT") | |
# https://nn-hokuson.hatenablog.com/entry/2017/08/30/195716 | |
# リグ付け成功率をあげるために、ここに書かれている処理をする | |
# PIFuHDが出力するメッシュは頂点数が多いため重複点は削除 | |
bpy.ops.mesh.remove_doubles() | |
# メッシュのスムージング | |
bpy.ops.mesh.vertices_smooth() | |
bpy.ops.object.mode_set(mode='OBJECT') | |
# CSVファイルを読み込んで使いやすいように整形 | |
def kinect_joint_import(): | |
path = os.path.join(directory, "KinectJoints.csv") | |
print(path) | |
with open(path) as f: | |
reader = csv.reader(f) | |
data = {} | |
for row in reader: | |
data[row[0]] = [float(row[1]), float(row[2]), float(row[3])] | |
return data | |
# 人骨格点情報からボーンを生成 | |
def create_bones(data): | |
# 親となるhipボーンを生成 | |
bpy.ops.object.armature_add(enter_editmode=True, location=(0, 0, 0)) | |
hip = bpy.context.object | |
kinect_joint_names = \ | |
["SpineBase", "SpineMid", "SpineShoulder", "Neck", "Head", | |
"ShoulderLeft", "ElbowLeft", "WristLeft", "HandLeft", "HandTipLeft", "ThumbLeft", | |
"ShoulderRight", "ElbowRight", "WristRight", "HandRight", "HandTipRight", "ThumbRight", | |
"HipLeft", "KneeLeft", "AnkleLeft", "FootLeft", | |
"HipRight", "KneeRight", "AnkleRight", "FootRight"] | |
# kinect_joint_namesのどのインデックス同士をつなぐか | |
joint_pairs = \ | |
[[0, 1], [1, 2], [2, 3], [3, 4], | |
[2, 5], [5, 6], [6, 7], [7, 8], [8, 9], [8, 10], | |
[2, 11], [11, 12], [12, 13], [13, 14], [14, 15], [14, 16], | |
[0, 17], [17, 18], [18, 19], [19, 20], | |
[0, 21], [21, 22], [22, 23], [23, 24] | |
] | |
init_bone = hip.data.edit_bones.get("Bone") | |
hip.data.edit_bones.remove(init_bone) | |
# PIFuHDのメッシュは腰が原点になっているので、Kinectからのすべての骨格点をSpineBaseの座標分だけずらすようにする | |
offset_pos = (-data["SpineBase"][0], -data["SpineBase"][1], -data["SpineBase"][2]) | |
for pair in joint_pairs: | |
# 新しくつなぐボーンの先端同士のKienctでの名前を取得 | |
name = kinect_joint_names[pair[0]] | |
name_next = kinect_joint_names[pair[1]] | |
# 新しくつなぐボーンの生成 | |
bone = hip.data.edit_bones.new(name_next) | |
# PIFuHDのメッシュは腰が原点になっているので、Kinectからのすべての骨格点をSpineBaseの座標分だけずらすようにする | |
bone.head = (-(data[name][0] + offset_pos[0]), data[name][2] + offset_pos[2], data[name][1] + offset_pos[1]) | |
bone.tail = (-(data[name_next][0] + offset_pos[0]), data[name_next][2] + offset_pos[2], data[name_next][1] + offset_pos[1]) | |
# ボーンの親子関係の構築 | |
to_head_list = ["SpineMid", "SpineShoulder", "Neck", "Head"] | |
to_lefthand_list = ["SpineShoulder", "ShoulderLeft", "ElbowLeft", "WristLeft", "HandLeft", "HandTipLeft"] | |
to_righthand_list = ["SpineShoulder", "ShoulderRight", "ElbowRight", "WristRight", "HandRight", "HandTipRight"] | |
to_thumbleft_list = ["HandLeft", "ThumbLeft"] | |
to_thumbright_list = ["HandRight", "ThumbRight"] | |
to_legleft_list = ["SpineMid", "HipLeft", "KneeLeft", "AnkleLeft", "FootLeft"] | |
to_legright_list = ["SpineMid", "HipRight", "KneeRight", "AnkleRight", "FootRight"] | |
bone_list = [to_head_list, to_lefthand_list, to_righthand_list, to_thumbleft_list, to_thumbright_list, to_legleft_list, to_legright_list] | |
for list in bone_list: | |
for i in range(len(list)): | |
if i == 0: | |
continue; | |
parent_bone = hip.data.edit_bones.get(list[i-1]) | |
child_bone = hip.data.edit_bones.get(list[i]) | |
child_bone.parent = parent_bone | |
# Kinect to Unity Bone mapping | |
# Unityで読み込んだ時に自動でどのボーンがどの部分かを判別しやすくするようにUnityでの名前に変換 | |
kinect_to_unity_bonename = { | |
"Head": "Head", | |
"Neck": "Neck", | |
"SpineMid": "Hips", | |
"SpineShoulder": "Spine", | |
"ElbowLeft": "LeftUpperArm", | |
"WristLeft": "LeftLowerArm", | |
"HandLeft": "LeftHand", | |
"ElbowRight": "RightUpperArm", | |
"WristRight": "RightLowerArm", | |
"HandRight": "RightHand", | |
"KneeLeft": "LeftUpperLeg", | |
"AnkleLeft": "LeftLowerLef", | |
"FootLeft": "LeftFoot", | |
"KneeRight": "RightUpperLeg", | |
"AnkleRight": "RightLowerLeg", | |
"FootRight": "RightFoot" | |
} | |
for name in kinect_joint_names: | |
if name not in kinect_to_unity_bonename: | |
continue | |
bone = hip.data.edit_bones.get(name) | |
bone.name = kinect_to_unity_bonename[name] | |
bpy.ops.object.mode_set(mode="OBJECT") | |
# main program | |
# リグ付け前の処理 | |
delete_all_objects() | |
data = kinect_joint_import() | |
create_bones(data) | |
avatar_mesh = mesh_import() | |
fix_model(avatar_mesh) | |
bpy.context.view_layer.objects.active = bpy.data.objects["Armature"] | |
# リグ付けの実行 | |
bpy.ops.object.parent_set(type='ARMATURE_AUTO') | |
# リグ付け後FBXファイルで出力 | |
bpy.ops.export_scene.fbx(filepath=os.path.join(directory, "Avatar.fbx")) | |
# Blenderを終了 | |
bpy.ops.wm.quit_blender() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment