|
@@ -697,6 +697,25 @@ def generate_uvs(uv_layers, option_uv_coords):
|
|
|
|
|
|
return ",".join("[%s]" % n for n in layers)
|
|
return ",".join("[%s]" % n for n in layers)
|
|
|
|
|
|
|
|
+# ##############################################################################
|
|
|
|
+# Model exporter - armature
|
|
|
|
+# (only the first armature will exported)
|
|
|
|
+# ##############################################################################
|
|
|
|
+def get_armature():
|
|
|
|
+ if len(bpy.data.armatures) == 0:
|
|
|
|
+ print("Warning: no armatures in the scene")
|
|
|
|
+ return None, None
|
|
|
|
+
|
|
|
|
+ armature = bpy.data.armatures[0]
|
|
|
|
+
|
|
|
|
+ # Someone please figure out a proper way to get the armature node
|
|
|
|
+ for object in bpy.data.objects:
|
|
|
|
+ if object.type == 'ARMATURE':
|
|
|
|
+ return armature, object
|
|
|
|
+
|
|
|
|
+ print("Warning: no node of type 'ARMATURE' in the scene")
|
|
|
|
+ return None, None
|
|
|
|
+
|
|
# ##############################################################################
|
|
# ##############################################################################
|
|
# Model exporter - bones
|
|
# Model exporter - bones
|
|
# (only the first armature will exported)
|
|
# (only the first armature will exported)
|
|
@@ -704,39 +723,39 @@ def generate_uvs(uv_layers, option_uv_coords):
|
|
|
|
|
|
def generate_bones(option_bones, flipyz):
|
|
def generate_bones(option_bones, flipyz):
|
|
|
|
|
|
- if not option_bones or len(bpy.data.armatures) == 0:
|
|
|
|
|
|
+ if not option_bones:
|
|
return "", 0
|
|
return "", 0
|
|
|
|
|
|
- hierarchy = []
|
|
|
|
|
|
+ armature, armatureObject = get_armature()
|
|
|
|
+ if armature is None or armatureObject is None:
|
|
|
|
+ return "", 0
|
|
|
|
|
|
- armature = bpy.data.armatures[0]
|
|
|
|
|
|
+ hierarchy = []
|
|
|
|
|
|
TEMPLATE_BONE = '{"parent":%d,"name":"%s","pos":[%g,%g,%g],"rotq":[0,0,0,1]}'
|
|
TEMPLATE_BONE = '{"parent":%d,"name":"%s","pos":[%g,%g,%g],"rotq":[0,0,0,1]}'
|
|
|
|
|
|
for bone in armature.bones:
|
|
for bone in armature.bones:
|
|
|
|
+ bonePos = None
|
|
|
|
+ boneIndex = None
|
|
if bone.parent == None:
|
|
if bone.parent == None:
|
|
- if flipyz:
|
|
|
|
- joint = TEMPLATE_BONE % (-1, bone.name, bone.head.x, bone.head.z, -bone.head.y)
|
|
|
|
- hierarchy.append(joint)
|
|
|
|
- else:
|
|
|
|
- joint = TEMPLATE_BONE % (-1, bone.name, bone.head.x, bone.head.y, bone.head.z)
|
|
|
|
- hierarchy.append(joint)
|
|
|
|
|
|
+ bonePos = bone.head_local
|
|
|
|
+ boneIndex = -1
|
|
else:
|
|
else:
|
|
- index = i = 0
|
|
|
|
|
|
+ bonePos = bone.head_local - bone.parent.head_local
|
|
|
|
+ boneIndex = i = 0
|
|
for parent in armature.bones:
|
|
for parent in armature.bones:
|
|
if parent.name == bone.parent.name:
|
|
if parent.name == bone.parent.name:
|
|
- index = i
|
|
|
|
|
|
+ boneIndex = i
|
|
i += 1
|
|
i += 1
|
|
|
|
|
|
- position = bone.head_local - bone.parent.head_local
|
|
|
|
-
|
|
|
|
- if flipyz:
|
|
|
|
- joint = TEMPLATE_BONE % (index, bone.name, position.x, position.z, -position.y)
|
|
|
|
- hierarchy.append(joint)
|
|
|
|
- else:
|
|
|
|
- joint = TEMPLATE_BONE % (index, bone.name, position.x, position.y, position.z)
|
|
|
|
- hierarchy.append(joint)
|
|
|
|
-
|
|
|
|
|
|
+ bonePosWorld = armatureObject.matrix_world * bonePos
|
|
|
|
+ if flipyz:
|
|
|
|
+ joint = TEMPLATE_BONE % (boneIndex, bone.name, bonePosWorld.x, bonePosWorld.z, -bonePosWorld.y)
|
|
|
|
+ hierarchy.append(joint)
|
|
|
|
+ else:
|
|
|
|
+ joint = TEMPLATE_BONE % (boneIndex, bone.name, bonePosWorld.x, bonePosWorld.y, bonePosWorld.z)
|
|
|
|
+ hierarchy.append(joint)
|
|
|
|
+
|
|
bones_string = ",".join(hierarchy)
|
|
bones_string = ",".join(hierarchy)
|
|
|
|
|
|
return bones_string, len(armature.bones)
|
|
return bones_string, len(armature.bones)
|
|
@@ -754,7 +773,7 @@ def generate_indices_and_weights(meshes, option_skinning):
|
|
indices = []
|
|
indices = []
|
|
weights = []
|
|
weights = []
|
|
|
|
|
|
- armature = bpy.data.armatures[0]
|
|
|
|
|
|
+ armature, armatureObject = get_armature()
|
|
|
|
|
|
for mesh, object in meshes:
|
|
for mesh, object in meshes:
|
|
|
|
|
|
@@ -828,13 +847,15 @@ def generate_indices_and_weights(meshes, option_skinning):
|
|
|
|
|
|
def generate_animation(option_animation_skeletal, option_frame_step, flipyz):
|
|
def generate_animation(option_animation_skeletal, option_frame_step, flipyz):
|
|
|
|
|
|
- if not option_animation_skeletal or len(bpy.data.actions) == 0 or len(bpy.data.armatures) == 0:
|
|
|
|
|
|
+ if not option_animation_skeletal or len(bpy.data.actions) == 0:
|
|
return ""
|
|
return ""
|
|
|
|
|
|
# TODO: Add scaling influences
|
|
# TODO: Add scaling influences
|
|
|
|
|
|
action = bpy.data.actions[0]
|
|
action = bpy.data.actions[0]
|
|
- armature = bpy.data.armatures[0]
|
|
|
|
|
|
+ armature, armatureObject = get_armature()
|
|
|
|
+ if armature is None or armatureObject is None:
|
|
|
|
+ return "", 0
|
|
|
|
|
|
parents = []
|
|
parents = []
|
|
parent_index = -1
|
|
parent_index = -1
|
|
@@ -857,8 +878,8 @@ def generate_animation(option_animation_skeletal, option_frame_step, flipyz):
|
|
|
|
|
|
for frame in range(int(start_frame), int(end_frame / option_frame_step) + 1):
|
|
for frame in range(int(start_frame), int(end_frame / option_frame_step) + 1):
|
|
|
|
|
|
- pos, pchange = position(hierarchy, frame * option_frame_step)
|
|
|
|
- rot, rchange = rotation(hierarchy, frame * option_frame_step)
|
|
|
|
|
|
+ pos, pchange = position(hierarchy, frame * option_frame_step, action, armatureObject.matrix_world)
|
|
|
|
+ rot, rchange = rotation(hierarchy, frame * option_frame_step, action, armatureObject.matrix_world)
|
|
|
|
|
|
if flipyz:
|
|
if flipyz:
|
|
px, py, pz = pos.x, pos.z, -pos.y
|
|
px, py, pz = pos.x, pos.z, -pos.y
|
|
@@ -930,16 +951,13 @@ def handle_position_channel(channel, frame, position):
|
|
|
|
|
|
return change
|
|
return change
|
|
|
|
|
|
-def position(bone, frame):
|
|
|
|
|
|
+def position(bone, frame, action, armatureMatrix):
|
|
|
|
|
|
position = mathutils.Vector((0,0,0))
|
|
position = mathutils.Vector((0,0,0))
|
|
change = False
|
|
change = False
|
|
|
|
|
|
- action = bpy.data.actions[0]
|
|
|
|
ngroups = len(action.groups)
|
|
ngroups = len(action.groups)
|
|
|
|
|
|
-
|
|
|
|
-
|
|
|
|
if ngroups > 0:
|
|
if ngroups > 0:
|
|
|
|
|
|
index = 0
|
|
index = 0
|
|
@@ -982,7 +1000,7 @@ def position(bone, frame):
|
|
position.y += (bone.head * parentInvertedLocalMatrix).y + parentHeadTailDiff.y
|
|
position.y += (bone.head * parentInvertedLocalMatrix).y + parentHeadTailDiff.y
|
|
position.z += (bone.head * parentInvertedLocalMatrix).z + parentHeadTailDiff.z
|
|
position.z += (bone.head * parentInvertedLocalMatrix).z + parentHeadTailDiff.z
|
|
|
|
|
|
- return position, change
|
|
|
|
|
|
+ return armatureMatrix*position, change
|
|
|
|
|
|
def handle_rotation_channel(channel, frame, rotation):
|
|
def handle_rotation_channel(channel, frame, rotation):
|
|
|
|
|
|
@@ -1010,7 +1028,7 @@ def handle_rotation_channel(channel, frame, rotation):
|
|
|
|
|
|
return change
|
|
return change
|
|
|
|
|
|
-def rotation(bone, frame):
|
|
|
|
|
|
+def rotation(bone, frame, action, armatureMatrix):
|
|
|
|
|
|
# TODO: calculate rotation also from rotation_euler channels
|
|
# TODO: calculate rotation also from rotation_euler channels
|
|
|
|
|
|
@@ -1018,7 +1036,6 @@ def rotation(bone, frame):
|
|
|
|
|
|
change = False
|
|
change = False
|
|
|
|
|
|
- action = bpy.data.actions[0]
|
|
|
|
ngroups = len(action.groups)
|
|
ngroups = len(action.groups)
|
|
|
|
|
|
# animation grouped by bones
|
|
# animation grouped by bones
|
|
@@ -1049,7 +1066,7 @@ def rotation(bone, frame):
|
|
change = change or hasChanged
|
|
change = change or hasChanged
|
|
|
|
|
|
rot3 = rotation.to_3d()
|
|
rot3 = rotation.to_3d()
|
|
- rotation.xyz = rot3 * bone.matrix_local.inverted()
|
|
|
|
|
|
+ rotation.xyz = armatureMatrix * bone.matrix_local.inverted() * rot3
|
|
|
|
|
|
return rotation, change
|
|
return rotation, change
|
|
|
|
|