Closed8

【Blender】BlenderでもSkinning Converterをやりたい

nekoconekoco

実際に使ってみた

解説の通り、FBXとAlembicを用意する。
DemBoneを保存したパス内の\bin\Windows\でPowershellを起動。
FBXとかもそのパスに移動させる。

以下の通り入力

.\DemBones.exe -a="cloth.abc" -i="cloth.fbx" -o="out.fbx" -b=64

(自分の場合、DemBones.exeの前に.\を付けろと怒られた...)

以下の様な表示になったら成功

https://x.com/nekoco_vrc/status/1839214813924438262

nekoconekoco

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にインポート。

nekoconekoco

どうせなら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を押す。

使用例

https://twitter.com/nekoco_vrc/status/1839307473930563900

nekoconekoco

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.

nekoconekoco

Blender→Unity

変換後、そのままFBXとして出力すると上手くいったりいかなかったりした。
特にボーン数が多い場合、いくつかのボーンが動かなかったりした。

そこで、FBX書き出し時のアニメーションの設定を以下の通りに変更。

するとちゃんとFBXに出力でき、Blenderでの再インポートやUnityへの移行が可能となった。

https://x.com/nekoco_vrc/status/1840019342819504384

このスクラップは2ヶ月前にクローズされました