bl_info = {
"name": "Export Armature to JSON",
"category": "Import-Export",
"blender": (2, 80, 0)
}
import bpy
import math
import json
class ExportArmatureToJSON(bpy.types.Operator):
bl_idname = 'import_export.armature2json'
bl_label = 'Export Armature to JSON'
bl_options = {'REGISTER'}
bl_category = 'Import-Export'
def execute(self, context):
def main():
armatureJSON = {
'actions': {},
'inverse_bind_poses': [],
'joint_index': {},
'bone_groups': {}
}
activeArmature = bpy.context.view_layer.objects.active
if activeArmature.type != 'ARMATURE':
for obj in bpy.context.scene.objects:
if obj.type == 'ARMATURE':
activeArmature = obj
bpy.context.view_layer.objects.active = activeArmature
break
actionsList = list(bpy.data.actions)
bpy.ops.object.mode_set(mode = 'POSE')
allBoneNames = []
for poseBone in activeArmature.pose.bones:
poseBone.bone.select = True
allBoneNames.append(poseBone.name)
for actionInfo in actionsList:
activeArmature.animation_data.action = bpy.data.actions.get(actionInfo.name)
actionKeyframes = getKeyframesInAction(activeArmature.animation_data.action)
if actionKeyframes == []:
continue
armatureJSON['actions'][actionInfo.name] = []
index = 0
for frame in actionKeyframes:
timeOfKeyframe = round(frame / bpy.context.scene.render.fps, 6)
armatureJSON['actions'][actionInfo.name].append({
'bones': [],
'frame_time_secs': None
})
for bone in getBonePosesAtKeyframe(frame, activeArmature, allBoneNames):
armatureJSON['actions'][actionInfo.name][index]['bones'].append({'Matrix': matrixToArray(bone.matrix)})
armatureJSON['actions'][actionInfo.name][index]['frame_time_secs'] = timeOfKeyframe
index += 1
for boneName in allBoneNames:
poseBone = activeArmature.pose.bones[boneName]
boneBindMatrix = activeArmature.matrix_world @ poseBone.bone.matrix_local
boneInverseBind = boneBindMatrix.copy().inverted()
armatureJSON['inverse_bind_poses'].append({'Matrix': matrixToArray(boneInverseBind)})
for boneIndex, boneName in enumerate(allBoneNames):
armatureJSON['joint_index'][boneName] = boneIndex
bone_groups_names = activeArmature.pose.bone_groups.keys()
for poseBone in activeArmature.pose.bones:
poseBone.bone.select = False
for bone_group_index, bone_group_name in enumerate(bone_groups_names):
armatureJSON['bone_groups'][bone_group_name] = []
activeArmature.pose.bone_groups.active_index = bone_group_index
bpy.ops.pose.group_select()
for poseBone in bpy.context.selected_pose_bones:
bone_index = armatureJSON['joint_index'][poseBone.bone.name]
armatureJSON['bone_groups'][bone_group_name].append(bone_index)
bpy.ops.pose.group_deselect()
output = "START_ARMATURE_JSON " + bpy.data.filepath + " " + activeArmature.name
output += "\n"
output += json.dumps(armatureJSON)
output += "\n"
output += "END_ARMATURE_JSON " + bpy.data.filepath + " " + activeArmature.name
print(output)
return {'FINISHED'}
def getKeyframesInAction(action):
keyframes = []
for fcurve in action.fcurves:
for keyframe in fcurve.keyframe_points:
x, y = keyframe.co
if x not in keyframes:
keyframes.append((math.ceil(x)))
return keyframes
def getBonePosesAtKeyframe(frame, armature, boneNames):
bonePosesAtKeyframe = []
bpy.context.scene.frame_set(frame)
for boneName in boneNames:
poseBone = armature.pose.bones[boneName]
bonePosesAtKeyframe.append(poseBone)
return bonePosesAtKeyframe
def matrixToArray (matrix):
array = []
for column in range(0, 4):
for row in range(0, 4):
array.append(matrix[column][row])
return array
return main()
def register():
bpy.utils.register_class(ExportArmatureToJSON)
def unregister():
bpy.utils.unregister_class(ExportArmatureToJSON)
if __name__ == "__main__":
register()