やりたいこと
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()