Browse Source

Transform bones and animations by the armature world matrix

Mesh vertices are already transformed
Robert Carnecky 12 years ago
parent
commit
495eb628ac

+ 50 - 33
utils/exporters/blender/2.66/scripts/addons/io_mesh_threejs/export_threejs.py

@@ -697,6 +697,25 @@ def generate_uvs(uv_layers, option_uv_coords):
 
     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
 # (only the first armature will exported)
@@ -704,39 +723,39 @@ def generate_uvs(uv_layers, option_uv_coords):
 
 def generate_bones(option_bones, flipyz):
 
-    if not option_bones or len(bpy.data.armatures) == 0:
+    if not option_bones:
         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]}'
 
     for bone in armature.bones:
+        bonePos = None
+        boneIndex = 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:
-            index = i = 0
+            bonePos = bone.head_local - bone.parent.head_local
+            boneIndex = i = 0
             for parent in armature.bones:
                 if parent.name == bone.parent.name:
-                    index = i
+                    boneIndex = i
                 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)
 
     return bones_string, len(armature.bones)
@@ -754,7 +773,7 @@ def generate_indices_and_weights(meshes, option_skinning):
     indices = []
     weights = []
 
-    armature = bpy.data.armatures[0]
+    armature, armatureObject = get_armature()
 
     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):
 
-    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 ""
 
     # TODO: Add scaling influences
 
     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 = []
     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):
 
-            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:
                 px, py, pz = pos.x, pos.z, -pos.y
@@ -930,16 +951,13 @@ def handle_position_channel(channel, frame, position):
 
     return change
 
-def position(bone, frame):
+def position(bone, frame, action, armatureMatrix):
 
     position = mathutils.Vector((0,0,0))
     change = False
 
-    action = bpy.data.actions[0]
     ngroups = len(action.groups)
 
-
-
     if ngroups > 0:
 
         index = 0
@@ -982,7 +1000,7 @@ def position(bone, frame):
         position.y += (bone.head * parentInvertedLocalMatrix).y + parentHeadTailDiff.y
         position.z += (bone.head * parentInvertedLocalMatrix).z + parentHeadTailDiff.z
 
-    return position, change
+    return armatureMatrix*position, change
 
 def handle_rotation_channel(channel, frame, rotation):
 
@@ -1010,7 +1028,7 @@ def handle_rotation_channel(channel, frame, rotation):
 
     return change
 
-def rotation(bone, frame):
+def rotation(bone, frame, action, armatureMatrix):
 
     # TODO: calculate rotation also from rotation_euler channels
 
@@ -1018,7 +1036,6 @@ def rotation(bone, frame):
 
     change = False
 
-    action = bpy.data.actions[0]
     ngroups = len(action.groups)
 
     # animation grouped by bones
@@ -1049,7 +1066,7 @@ def rotation(bone, frame):
                 change = change or hasChanged
 
     rot3 = rotation.to_3d()
-    rotation.xyz = rot3 * bone.matrix_local.inverted()
+    rotation.xyz = armatureMatrix * bone.matrix_local.inverted() * rot3
 
     return rotation, change