【Blender】BlenderでもSkinning Converterをやりたい
HoudiniにはSkinning ConverterというSOPがある。
頂点アニメーションをボーンアニメーションに近似変換する。
近似するボーン数も指定出来て便利。
疑問
他のDCCソフトでも出来ないか?
解決手段
Dem BonesというOSSがある。
それを使えば実装できそう?
使用例
実際に使ってみた
解説の通り、FBXとAlembicを用意する。
DemBoneを保存したパス内の\bin\Windows\でPowershellを起動。
FBXとかもそのパスに移動させる。
以下の通り入力
.\DemBones.exe -a="cloth.abc" -i="cloth.fbx" -o="out.fbx" -b=64
(自分の場合、DemBones.exeの前に.\を付けろと怒られた...)
以下の様な表示になったら成功
Blenderスクリプトで自動化する
import bpy
import subprocess
# DemBones.exeが保存されているパス
path = "C:\\Users\\neko\\3D Objects\\dem-bones\\bin\\Windows\\"
dim_bone_path = path + "DemBones.exe"
abc_path = path + "a.abc"
fbx_path = path + "a.fbx"
out_path = path + "out.fbx"
bone_num = 16
active_object = bpy.context.view_layer.objects.active
bpy.ops.object.select_all(action='DESELECT')
active_object.select_set(True)
bpy.context.view_layer.objects.active = active_object
bpy.ops.wm.alembic_export(filepath=abc_path, selected=True)
bpy.ops.export_scene.fbx(filepath=fbx_path, global_scale=0.01, use_selection=True)
result = subprocess.run([dim_bone_path, '-a=' + abc_path, '-i=' + fbx_path, '-o=' + out_path, "-b=" + str(bone_num)], capture_output=True, text=True)
bpy.ops.import_scene.fbx(filepath=out_path)
bpy.context.view_layer.objects.active.scale = (1.0, 1.0, 1.0)
使用方法は、アニメーションが付いたオブジェクトを選択してスクリプトを実行。
解説
選択したオブジェクトをAlembicとFBXとして保存。
その後、適切なargsを入力して実行ファイルを実行。
作成されたFBXをBlenderにインポート。
どうせならUIまで作っちゃう!
import bpy
import subprocess
from bpy.props import StringProperty
from bpy.types import Operator, Panel
# カスタムプロパティを定義(フォルダーパス用)
class MyProperties(bpy.types.PropertyGroup):
folder_path: StringProperty(
name="Folder Path",
description="Select a Dem Bone folder",
subtype='DIR_PATH'
)
# パネルを定義(3Dビューのサイドバーに表示)
class MY_PT_panel(Panel):
bl_label = "Skinning Converter"
bl_idname = "VIEW3D_PT_my_panel"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = "My Tools"
def draw(self, context):
layout = self.layout
scene = context.scene
mytool = scene.my_tool
layout.label(text="DemBones.exe Folder")
layout.prop(mytool, "folder_path")
layout.prop(scene, "bone_num", text=f"ボーン数:{scene.bone_num}")
layout.operator("wm.execute_button", text="Execute")
# Executeボタン用のオペレーターを定義
class WM_OT_execute_button(Operator):
bl_label = "Execute Button"
bl_idname = "wm.execute_button"
def execute(self, context):
path = context.scene.my_tool.folder_path
dim_bone_path = path + "DemBones.exe"
abc_path = path + "a.abc"
fbx_path = path + "a.fbx"
out_path = path + "out.fbx"
bone_num = context.scene.bone_num
active_object = bpy.context.view_layer.objects.active
bpy.ops.object.select_all(action='DESELECT')
active_object.select_set(True)
bpy.context.view_layer.objects.active = active_object
bpy.ops.wm.alembic_export(filepath=abc_path, selected=True)
bpy.ops.export_scene.fbx(filepath=fbx_path, global_scale=0.01, use_selection=True)
result = subprocess.run([dim_bone_path, '-a=' + abc_path, '-i=' + fbx_path, '-o=' + out_path, "-b=" + str(bone_num)], capture_output=True, text=True)
print("STDOUT:", result.stdout)
print("STDERR:", result.stderr)
bpy.ops.import_scene.fbx(filepath=out_path)
bpy.context.view_layer.objects.active.scale = (1.0, 1.0, 1.0)
self.report({'INFO'}, "Execute button pressed")
return {'FINISHED'}
# プロパティとパネルを登録
def register():
bpy.utils.register_class(MyProperties)
bpy.utils.register_class(MY_PT_panel)
bpy.utils.register_class(WM_OT_execute_button)
bpy.types.Scene.my_tool = bpy.props.PointerProperty(type=MyProperties)
bpy.types.Scene.bone_num = bpy.props.IntProperty(
name="Bone Num",
description="ボーン数",
default=16,
min = 1
)
# プロパティとパネルを解除
def unregister():
bpy.utils.unregister_class(MyProperties)
bpy.utils.unregister_class(MY_PT_panel)
bpy.utils.unregister_class(WM_OT_execute_button)
del bpy.types.Scene.my_tool
del bpy.types.Scene.bone_num
if __name__ == "__main__":
register()
使用方法
3Dビューのサイドバーにこのツールが追加される。
DemBones.exeが格納されたパスを選択する箇所があるので設定する。
作成するボーン数を入力。
アニメーション付きオブジェクトを選択して、Excuteを押す。
使用例
usage.txt引用
USAGE:
DemBones -a=<filename> ... -i=<filename> ... -o=<filename> ...
[-b=<int>] [--nInitIters=<int>] [-n=<int>]
[--tolerance=<double>] [--patience=<int>]
[--nTransIters=<int>] [--bindUpdate=<int>]
[--transAffine=<double>] [--transAffineNorm=<double>]
[--nWeightsIters=<int>] [-z=<int>]
[--weightsSmooth=<double>] [--weightsSmoothStep=<double>]
[--dbg=<int>] [--log=<filename>] [--] [--version] [-h]
Where:
-a=<filename>, --abc=<filename> (accepted multiple times)
(required) animated mesh sequences (alembic geometry cache files)
-i=<filename>, --init=<filename> (accepted multiple times)
(required) rest pose/init skin clusters (fbx files), each file
correspond to one abc file
-o=<filename>, --out=<filename> (accepted multiple times)
(required) output (fbx files), each outut correspond to one abc file
-b=<int>, --nBones=<int>
number of bones
--nInitIters=<int>
number iterations per init cluster splitting
-n=<int>, --nIters=<int>
number of global iterations
--tolerance=<double>
convergence tolerance, stop if error relatively reduces less than
[--tolerance] in [--patience] consecutive iterations
--patience=<int>
convergence patience, stop if error relatively reduces less than
[--tolerance] in [--patience] consecutive iterations
--nTransIters=<int>
number of transformation update iterations per global iteration
--bindUpdate=<int>
update bind pose (0=no update, 1=update joint positions, 2=regroup
joints under one root)
--transAffine=<double>
bone translations affinity soft constraint
--transAffineNorm=<double>
p-Norm for bone translations affinity
--nWeightsIters=<int>
number of weights update iterations per global iteration
-z=<int>, --nnz=<int>
number of non-zero weights per vertex
--weightsSmooth=<double>
weights smoothness soft constraint
--weightsSmoothStep=<double>
step size for the weights smoothness
--dbg=<int>
debug level
--log=<filename>
log file name
--, --ignore_rest
Ignores the rest of the labeled arguments following this flag.
--version
Displays version information and exits.
-h, --help
Displays usage information and exits.
Dem Bones - (c) Electronic Arts 2019
-
This tool only handles clean input data, i.e. only one piece of
geometry with one skinCluster and no excessive joint. -
To hard-lock the transformations of bones: in the input fbx files,
create bool attributes for joint nodes (bones) with name "demLock" and
set the value to "true". -
To soft-lock skinning weights of vertices: in the input fbx files,
paint per-vertex colors in gray-scale. The closer the color to white,
the more skinning weights of the vertex are preserved.
ループアニメーション
下記動画でループするクロスアニメーションを作成。
そのまま変換しようとすると失敗した。
1度Alembicとして書き出し、再度インポートしたオブジェクトにて変換。
すると成功した。(無駄なデータが残っていた?
Blender→Unity
変換後、そのままFBXとして出力すると上手くいったりいかなかったりした。
特にボーン数が多い場合、いくつかのボーンが動かなかったりした。
そこで、FBX書き出し時のアニメーションの設定を以下の通りに変更。
するとちゃんとFBXに出力でき、Blenderでの再インポートやUnityへの移行が可能となった。