Browse Source

new track system, plus blend shapes

jackcaron 10 years ago
parent
commit
2d1745d48d
1 changed files with 121 additions and 9 deletions
  1. 121 9
      utils/exporters/blender/addons/io_three/exporter/api/object.py

+ 121 - 9
utils/exporters/blender/addons/io_three/exporter/api/object.py

@@ -92,8 +92,8 @@ def cast_shadow(obj):
         if obj.data.type in (SPOT, SUN):
         if obj.data.type in (SPOT, SUN):
             ret = obj.data.shadow_method != NO_SHADOW
             ret = obj.data.shadow_method != NO_SHADOW
         else:
         else:
-            logger.info("%s is a lamp but this lamp type does not "
-                        "have supported shadows in ThreeJS", obj.name)
+            logger.info('%s is a lamp but this lamp type does not '\
+                'have supported shadows in ThreeJS', obj.name)
             ret = None
             ret = None
         return ret
         return ret
     elif obj.type == MESH:
     elif obj.type == MESH:
@@ -131,6 +131,82 @@ def material(obj):
     except IndexError:
     except IndexError:
         pass
         pass
 
 
+QUAT_CONVERSION = axis_conversion(from_forward='Y', from_up='Z', to_forward='Z', to_up='Y')
+
+def __swap_quaternions(track):
+    for t in track:
+        a = t["value"]
+        q = mathutils.Quaternion(a)
+        q = (QUAT_CONVERSION*q.to_matrix()).to_quaternion()
+        a[0] =-q.x
+        a[1] =-q.y
+        a[2] =-q.z
+        a[3] =-q.w
+    pass
+
+def __swap_vector3(track):
+    for t in track:
+        v = t["value"]
+        tmp = v[1]
+        v[1] = v[2]
+        v[2] = tmp
+    pass
+
+def __parse_tracked_vector(fcurves, start_index, nb_curves):
+    track = []
+    for xx in fcurves[start_index].keyframe_points:
+        track.append({ "time": xx.co.x, "value": [xx.co.y] })
+
+    swapFunction = __swap_vector3 if nb_curves == 3 else __swap_quaternions
+
+    nb_curves += start_index
+    start_index += 1
+    while start_index < nb_curves:
+        i = 0
+        for xx in fcurves[start_index].keyframe_points:
+            track[i]["value"].append(xx.co.y)
+            i += 1
+        start_index += 1
+    swapFunction(track)
+    return track
+
+# trackable transform fields ( <output field>, <nb fcurve>, <type> )
+TRACKABLE_FIELDS = {
+    "location": ( "position", 3, "vector3" ),
+    "scale": ( "scale", 3, "vector3" ),
+    "rotation_euler": ( "rotation", 3, "vector3" ),
+    "rotation_quaternion": ( "quaternion", 4, "quaternion" )
+}
+
+@_object
+def animated_xform(obj):
+    fcurves = obj.animation_data
+    if not fcurves:
+        return {}
+    fcurves = fcurves.action.fcurves
+
+    tracks = []
+    i = 0
+    nb_curves = len(fcurves)
+    while i < nb_curves:
+        field_info = TRACKABLE_FIELDS.get(fcurves[i].data_path)
+        if field_info:
+            nb_curves = field_info[1]
+            tracks.append({
+                constants.NAME: field_info[0],
+                constants.TYPE: field_info[2],
+                constants.KEYS: __parse_tracked_vector(fcurves, i, nb_curves)
+            })
+            i += nb_curves
+        else:
+            i += 1
+
+    animation = {
+        constants.KEYFRAMES: tracks,
+        constants.FPS: context.scene.render.fps,
+        constants.NAME: obj.name
+    }
+    return animation
 
 
 @_object
 @_object
 def mesh(obj, options):
 def mesh(obj, options):
@@ -217,7 +293,6 @@ def nodes(valid_types, options):
         if _valid_node(obj, valid_types, options):
         if _valid_node(obj, valid_types, options):
             yield obj.name
             yield obj.name
 
 
-
 @_object
 @_object
 def position(obj, options):
 def position(obj, options):
     """
     """
@@ -245,10 +320,8 @@ def receive_shadow(obj):
         else:
         else:
             return False
             return False
 
 
-
 AXIS_CONVERSION = axis_conversion(to_forward='Z', to_up='Y').to_4x4()
 AXIS_CONVERSION = axis_conversion(to_forward='Z', to_up='Y').to_4x4()
 
 
-
 @_object
 @_object
 def matrix(obj, options):
 def matrix(obj, options):
     """
     """
@@ -331,10 +404,7 @@ def extract_mesh(obj, options, recalculate=False):
 
 
     """
     """
     logger.debug('object.extract_mesh(%s, %s)', obj, options)
     logger.debug('object.extract_mesh(%s, %s)', obj, options)
-    apply_modifiers = options.get(constants.APPLY_MODIFIERS, True)
-    if apply_modifiers:
-        bpy.ops.object.mode_set(mode='OBJECT')
-    mesh_node = obj.to_mesh(context.scene, apply_modifiers, RENDER)
+    mesh_node = obj.to_mesh(context.scene, True, RENDER)
 
 
     # transfer the geometry type to the extracted mesh
     # transfer the geometry type to the extracted mesh
     mesh_node.THREE_geometry_type = obj.data.THREE_geometry_type
     mesh_node.THREE_geometry_type = obj.data.THREE_geometry_type
@@ -346,6 +416,8 @@ def extract_mesh(obj, options, recalculate=False):
     opt_buffer = opt_buffer == constants.BUFFER_GEOMETRY
     opt_buffer = opt_buffer == constants.BUFFER_GEOMETRY
     prop_buffer = mesh_node.THREE_geometry_type == constants.BUFFER_GEOMETRY
     prop_buffer = mesh_node.THREE_geometry_type == constants.BUFFER_GEOMETRY
 
 
+    bpy.context.scene.objects.active = obj
+
     # if doing buffer geometry it is imperative to triangulate the mesh
     # if doing buffer geometry it is imperative to triangulate the mesh
     if opt_buffer or prop_buffer:
     if opt_buffer or prop_buffer:
         original_mesh = obj.data
         original_mesh = obj.data
@@ -354,6 +426,8 @@ def extract_mesh(obj, options, recalculate=False):
                      original_mesh.name,
                      original_mesh.name,
                      mesh_node.name)
                      mesh_node.name)
 
 
+        hidden_state = obj.hide
+        obj.hide = False
         bpy.ops.object.mode_set(mode='OBJECT')
         bpy.ops.object.mode_set(mode='OBJECT')
         obj.select = True
         obj.select = True
         bpy.context.scene.objects.active = obj
         bpy.context.scene.objects.active = obj
@@ -363,6 +437,7 @@ def extract_mesh(obj, options, recalculate=False):
                                       modifier='Triangulate')
                                       modifier='Triangulate')
         obj.data = original_mesh
         obj.data = original_mesh
         obj.select = False
         obj.select = False
+        obj.hide = hidden_state
 
 
     # recalculate the normals to face outwards, this is usually
     # recalculate the normals to face outwards, this is usually
     # best after applying a modifiers, especialy for something
     # best after applying a modifiers, especialy for something
@@ -384,6 +459,43 @@ def extract_mesh(obj, options, recalculate=False):
         xrot = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
         xrot = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
         mesh_node.transform(xrot * obj.matrix_world)
         mesh_node.transform(xrot * obj.matrix_world)
 
 
+    # blend shapes
+    if options.get(constants.BLEND_SHAPES) and not options.get(constants.MORPH_TARGETS):
+        original_mesh = obj.data
+        if original_mesh.shape_keys:
+            logger.info('Using blend shapes')
+            obj.data = mesh_node  # swap to be able to add the shape keys
+            shp = original_mesh.shape_keys
+
+            animCurves = shp.animation_data
+            if animCurves:
+                animCurves = animCurves.action.fcurves
+
+            src_kbs = shp.key_blocks
+            for key in src_kbs.keys():
+                logger.info("-- Parsing key %s", key)
+                obj.shape_key_add(name=key, from_mix=False)
+                src_kb = src_kbs[key].data
+                if key == 'Basis':
+                    dst_kb = mesh_node.vertices
+                else:
+                    dst_kb = mesh_node.shape_keys.key_blocks[key].data
+                for idx in range(len(src_kb)):
+                    dst_kb[idx].co = src_kb[idx].co
+
+                if animCurves:
+                    data_path = 'key_blocks["'+key+'"].value'
+                    for fcurve in animCurves:
+                        if fcurve.data_path == data_path:
+                            dst_kb = mesh_node.shape_keys.key_blocks[key]
+                            for xx in fcurve.keyframe_points:
+                                dst_kb.value = xx.co.y
+                                dst_kb.keyframe_insert("value",frame=xx.co.x)
+                            pass
+                            break  # no need to continue to loop
+                    pass
+            obj.data = original_mesh
+
     # now generate a unique name
     # now generate a unique name
     index = 0
     index = 0
     while True:
     while True: