[Bf-extensions-cvs] [1ec2d064] master: glTF exporter: fix animation tangents

Julien Duroure noreply at git.blender.org
Tue Apr 2 22:01:23 CEST 2019


Commit: 1ec2d0647ea24ce71a915cf2f461578f76468b86
Author: Julien Duroure
Date:   Tue Apr 2 22:01:02 2019 +0200
Branches: master
https://developer.blender.org/rBA1ec2d0647ea24ce71a915cf2f461578f76468b86

glTF exporter: fix animation tangents

===================================================================

M	io_scene_gltf2/blender/com/gltf2_blender_math.py
M	io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py
M	io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_samplers.py

===================================================================

diff --git a/io_scene_gltf2/blender/com/gltf2_blender_math.py b/io_scene_gltf2/blender/com/gltf2_blender_math.py
index dd15ce2f..f3a20038 100755
--- a/io_scene_gltf2/blender/com/gltf2_blender_math.py
+++ b/io_scene_gltf2/blender/com/gltf2_blender_math.py
@@ -46,7 +46,7 @@ def list_to_mathutils(values: typing.List[float], data_path: str) -> typing.Unio
     elif target == 'scale':
         return Vector(values)
     elif target == 'value':
-        return values
+        return Vector(values)
 
     return values
 
@@ -145,6 +145,7 @@ def transform_location(location: Vector, transform: Matrix = Matrix.Identity(4))
 
 def transform_rotation(rotation: Quaternion, transform: Matrix = Matrix.Identity(4)) -> Quaternion:
     """Transform rotation."""
+    rotation.normalize()
     m = rotation.to_matrix().to_4x4()
     m = multiply(transform, m)
     return m.to_quaternion()
diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py
index 4ec68c88..4eb4df5c 100755
--- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py
+++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py
@@ -123,27 +123,31 @@ def gather_keyframes(channels: typing.Tuple[bpy.types.FCurve], export_settings)
             if channels[0].keyframe_points[0].interpolation == "BEZIER":
                 # Construct the in tangent
                 if time == times[0]:
-                    # start in-tangent has zero length
-                    key.in_tangent = [0.0 for _ in channels]
+                    # start in-tangent should become all zero
+                    key.in_tangent = key.value
                 else:
-                    # otherwise construct an in tangent from the keyframes control points
-
+                    # otherwise construct an in tangent coordinate from the keyframes control points. We intermediately
+                    # use a point at t-1 to define the tangent. This allows the tangent control point to be transformed
+                    # normally
                     key.in_tangent = [
-                        3.0 * (c.keyframe_points[i].co[1] - c.keyframe_points[i].handle_left[1]
-                               ) / (time - times[i - 1])
+                        c.keyframe_points[i].co[1] + ((c.keyframe_points[i].co[1] - c.keyframe_points[i].handle_left[1]
+                                                       ) / (time - times[i - 1]))
                         for c in channels
                     ]
                 # Construct the out tangent
                 if time == times[-1]:
-                    # end out-tangent has zero length
-                    key.out_tangent = [0.0 for _ in channels]
+                    # end out-tangent should become all zero
+                    key.out_tangent = key.value
                 else:
-                    # otherwise construct an out tangent from the keyframes control points
+                    # otherwise construct an in tangent coordinate from the keyframes control points. We intermediately
+                    # use a point at t+1 to define the tangent. This allows the tangent control point to be transformed
+                    # normally
                     key.out_tangent = [
-                        3.0 * (c.keyframe_points[i].handle_right[1] - c.keyframe_points[i].co[1]
-                               ) / (times[i + 1] - time)
+                        c.keyframe_points[i].co[1] + ((c.keyframe_points[i].handle_right[1] - c.keyframe_points[i].co[1]
+                                                       ) / (times[i + 1] - time))
                         for c in channels
                     ]
+
             keyframes.append(key)
 
     return keyframes
@@ -197,11 +201,11 @@ def needs_baking(channels: typing.Tuple[bpy.types.FCurve],
                                      "Baking animation because of differently located keyframes in one channel")
         return True
 
-    # Baking is required when the animation targets a quaternion with bezier interpolation
-    if channels[0].data_path == "rotation_quaternion" and interpolation == "BEZIER":
-        gltf2_io_debug.print_console("WARNING",
-                                     "Baking animation because targeting a quaternion with bezier interpolation")
-        return True
+    # # Baking is required when the animation targets a quaternion with bezier interpolation
+    # if channels[0].data_path == "rotation_quaternion" and interpolation == "BEZIER":
+    #     gltf2_io_debug.print_console("WARNING",
+    #                                  "Baking animation because targeting a quaternion with bezier interpolation")
+    #     return True
 
     return False
 
diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_samplers.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_samplers.py
index 981428c9..b4fda3c6 100755
--- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_samplers.py
+++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_samplers.py
@@ -16,6 +16,7 @@
 import typing
 
 import bpy
+import mathutils
 from io_scene_gltf2.blender.com import gltf2_blender_math
 from io_scene_gltf2.blender.com.gltf2_blender_data_path import get_target_property_name, get_target_object_path
 from io_scene_gltf2.blender.exp import gltf2_blender_gather_animation_sampler_keyframes
@@ -104,7 +105,7 @@ def __gather_output(channels: typing.Tuple[bpy.types.FCurve],
 
     target_datapath = channels[0].data_path
 
-    transform = parent_inverse
+    transform = mathutils.Matrix.Identity(4)
 
     is_yup = export_settings[gltf2_blender_export_keys.YUP]
 
@@ -113,17 +114,19 @@ def __gather_output(channels: typing.Tuple[bpy.types.FCurve],
     if is_armature_animation:
         bone = blender_object_if_armature.path_resolve(object_path)
         if isinstance(bone, bpy.types.PoseBone):
-            if bone.parent is not None:
-                parent_transform = bone.parent.bone.matrix_local
-                transform = gltf2_blender_math.multiply(transform, parent_transform.inverted())
-                # if not is_yup:
-                #     transform = gltf2_blender_math.multiply(transform, gltf2_blender_math.to_zup())
+            axis_basis_change = mathutils.Matrix.Identity(4)
+            if export_settings[gltf2_blender_export_keys.YUP]:
+                axis_basis_change = mathutils.Matrix(
+                    ((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, -1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0)))
+
+            # extract bone transform
+            if bone.parent is None:
+                correction_matrix_local = gltf2_blender_math.multiply(axis_basis_change, bone.bone.matrix_local)
             else:
-                # only apply the y-up conversion to root bones, as child bones already are in the y-up space
-                if is_yup:
-                    transform = gltf2_blender_math.multiply(transform, gltf2_blender_math.to_yup())
-            local_transform = bone.bone.matrix_local
-            transform = gltf2_blender_math.multiply(transform, local_transform)
+                correction_matrix_local = gltf2_blender_math.multiply(
+                    bone.parent.bone.matrix_local.inverted(), bone.bone.matrix_local)
+
+            transform = gltf2_blender_math.multiply(correction_matrix_local, bone.matrix_basis)
 
     values = []
     for keyframe in keyframes:
@@ -132,16 +135,25 @@ def __gather_output(channels: typing.Tuple[bpy.types.FCurve],
         if is_yup and not is_armature_animation:
             value = gltf2_blender_math.swizzle_yup(value, target_datapath)
         keyframe_value = gltf2_blender_math.mathutils_to_gltf(value)
+
         if keyframe.in_tangent is not None:
+            # we can directly transform the tangent as it currently is represented by a control point
             in_tangent = gltf2_blender_math.transform(keyframe.in_tangent, target_datapath, transform)
             if is_yup and blender_object_if_armature is None:
                 in_tangent = gltf2_blender_math.swizzle_yup(in_tangent, target_datapath)
-            keyframe_value = gltf2_blender_math.mathutils_to_gltf(in_tangent) + keyframe_value
+            # the tangent in glTF is relative to the keyframe value
+            in_tangent = value - in_tangent if not isinstance(value, list) else [value[0] - in_tangent[0]]
+            keyframe_value = gltf2_blender_math.mathutils_to_gltf(in_tangent) + keyframe_value  # append
+
         if keyframe.out_tangent is not None:
+            # we can directly transform the tangent as it currently is represented by a control point
             out_tangent = gltf2_blender_math.transform(keyframe.out_tangent, target_datapath, transform)
             if is_yup and blender_object_if_armature is None:
                 out_tangent = gltf2_blender_math.swizzle_yup(out_tangent, target_datapath)
-            keyframe_value = keyframe_value + gltf2_blender_math.mathutils_to_gltf(out_tangent)
+            # the tangent in glTF is relative to the keyframe value
+            out_tangent = value - out_tangent if not isinstance(value, list) else [value[0] - out_tangent[0]]
+            keyframe_value = keyframe_value + gltf2_blender_math.mathutils_to_gltf(out_tangent)  # append
+
         values += keyframe_value
 
     component_type = gltf2_io_constants.ComponentType.Float



More information about the Bf-extensions-cvs mailing list