機械学習基礎理論独習

誤りがあればご指摘いただけると幸いです。数式が整うまで少し時間かかります。リンクフリーです。

勉強ログです。リンクフリーです
目次へ戻る

【Blender】glTFに出力されない項目の出力【Addon】

やりたいこと

glTF2.0で出力されないボーンの rotation mode と bone constraint を出力するプログラムです。


以下のような感じで. json で出力します。

{
  "clavicle": {
    "rotation_mode": "YXZ",
    "constraints": []
  },
  "upperarm": {
    "rotation_mode": "YXZ",
    "constraints": []
  },
  "forearm": {
    "rotation_mode": "YXZ",
    "constraints": []
  },
  "elbowShareBone": {
    "rotation_mode": "YXZ",
    "constraints": [
      {
        "type": "COPY_ROTATION",
        "target": "armature",
        "subtarget": "forearm",
        "use_x": false,
        "use_y": true,
        "use_z": false,
        "invert_x": false,
        "invert_y": true,
        "invert_z": false,
        "mix_mode": "REPLACE",
        "target_space": "LOCAL",
        "owner_space": "LOCAL",
        "influence": 0.5
      }
    ]
  },
  ...
}

Addon の使い方


アーマチュアを選択して Export ボタンを押すだけです。
.blend と同じフォルダに bone_meta.json というファイルが作成されます。
ですので .blend が一度も保存されていないと Blender のデフォルトフォルダに保存されます。

Addon のソース

以下を適当な xxxx.py に貼り付けて Blender で読み込んでください。
bone constraint は copy rotation のみに対応しています。
人によっては異なる項目を出力したい人もいると思います。
その場合はソースを改変してください。

bl_info = {
    "name": "Bone Meta",
    "author": "PG0721",
    "version": (1, 0),
    "blender": (4, 5, 2),
    "location": "View3D > Sidebar > Bone Meta",
    "description": "Export bone rotation_mode and constraints to bone_meta.json",
    "category": "Rigging",
}

import bpy
import json


# ---------------------------------------------------------
# Export Operator
# ---------------------------------------------------------
class BME_OT_export(bpy.types.Operator):
    bl_idname = "bme.export_bone_meta"
    bl_label = "Export"
    bl_description = "Export Euler rotation_mode and constraints to JSON"

    def execute(self, context):
        obj = context.active_object

        # Armature チェック
        if obj is None or obj.type != 'ARMATURE':
            self.report({'ERROR'}, "Select an Armature")
            return {'CANCELLED'}

        # .blend 保存チェック
        if not bpy.data.filepath:
            self.report({'ERROR'}, "Please save the .blend file first")
            return {'CANCELLED'}

        data = {}

        for pbone in obj.pose.bones:
            bone_info = {
                "rotation_mode": pbone.rotation_mode,
                "constraints": []
            }

            for c in pbone.constraints:
                c_info = {"type": c.type}

                # 共通項目
                if hasattr(c, "target") and c.target:
                    c_info["target"] = c.target.name
                if hasattr(c, "subtarget") and c.subtarget:
                    c_info["subtarget"] = c.subtarget

                # COPY_ROTATION の詳細
                if c.type == 'COPY_ROTATION':
                    c_info.update({
                        "use_x": c.use_x,
                        "use_y": c.use_y,
                        "use_z": c.use_z,
                        "invert_x": c.invert_x,
                        "invert_y": c.invert_y,
                        "invert_z": c.invert_z,
                        "mix_mode": c.mix_mode,
                        "target_space": c.target_space,
                        "owner_space": c.owner_space,
                        "influence": c.influence
                    })

                bone_info["constraints"].append(c_info)

            data[pbone.name] = bone_info

        # 出力パス(.blend と同じ場所)
        path = bpy.path.abspath("//bone_meta.json")

        with open(path, "w", encoding="utf-8") as f:
            json.dump(data, f, indent=2)

        self.report({'INFO'}, f"Exported to {path}")
        return {'FINISHED'}


# ---------------------------------------------------------
# UI Panel
# ---------------------------------------------------------
class BME_PT_panel(bpy.types.Panel):
    bl_label = "Bone Meta"
    bl_idname = "BME_PT_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Bone Meta"

    def draw(self, context):
        layout = self.layout
        col = layout.column()
        col.operator("bme.export_bone_meta", icon="EXPORT")


# ---------------------------------------------------------
# Register
# ---------------------------------------------------------
classes = (
    BME_OT_export,
    BME_PT_panel,
)

def register():
    for c in classes:
        bpy.utils.register_class(c)

def unregister():
    for c in reversed(classes):
        bpy.utils.unregister_class(c)


if __name__ == "__main__":
    register()
目次へ戻る