[Bf-extensions-cvs] [08d13c02] master: glTF exporter: Fixed bezier control points to cubic spline tangents conversion

Julien Duroure noreply at git.blender.org
Wed Jul 13 12:10:23 CEST 2022


Commit: 08d13c024f60b03e7f525082db9fb12fbc576502
Author: Julien Duroure
Date:   Wed Jul 13 12:10:03 2022 +0200
Branches: master
https://developer.blender.org/rBA08d13c024f60b03e7f525082db9fb12fbc576502

glTF exporter: Fixed bezier control points to cubic spline tangents conversion

Fix when animation are not baked

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

M	io_scene_gltf2/__init__.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/__init__.py b/io_scene_gltf2/__init__.py
index 5c8872f3..be8aa8ed 100755
--- a/io_scene_gltf2/__init__.py
+++ b/io_scene_gltf2/__init__.py
@@ -4,7 +4,7 @@
 bl_info = {
     'name': 'glTF 2.0 format',
     'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
-    "version": (3, 3, 15),
+    "version": (3, 3, 16),
     'blender': (3, 3, 0),
     'location': 'File > Import-Export',
     'description': 'Import-Export as glTF 2.0',
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 e1ed19ea..ba331b74 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
@@ -398,11 +398,17 @@ def gather_keyframes(blender_obj_uuid: str,
                     key.set_first_tangent()
                 else:
                     # 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
+                    # use a point at t+1 to define the tangent. This allows the tangent control point to be transformed
+                    # normally, but only works for locally linear transformation. The more non-linear a transform, the
+                    # more imprecise this method is.
+                    # We could use any other (v1, t1) for which (v1 - v0) / (t1 - t0) equals the tangent. By using t+1
+                    # for both in and out tangents, we guarantee that (even if there are errors or numerical imprecisions)
+                    # symmetrical control points translate to symmetrical tangents.
+                    # Note: I am not sure that linearity is never broken with quaternions and their normalization.
+                    # Especially at sign swap it might occure that the value gets negated but the control point not.
+                    # I have however not once encountered an issue with this.
                     key.in_tangent = [
-                        c.keyframe_points[i].co[1] + ((c.keyframe_points[i].co[1] - c.keyframe_points[i].handle_left[1]
-                                                       ) / (frame - frames[i - 1]))
+                        c.keyframe_points[i].co[1] + (c.keyframe_points[i].handle_left[1] - c.keyframe_points[i].co[1]) / (c.keyframe_points[i].handle_left[0] - c.keyframe_points[i].co[0])
                         for c in channels if c is not None
                     ]
                 # Construct the out tangent
@@ -410,12 +416,10 @@ def gather_keyframes(blender_obj_uuid: str,
                     # end out-tangent should become all zero
                     key.set_last_tangent()
                 else:
-                    # 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
+                    # otherwise construct an in tangent coordinate from the keyframes control points.
+                    # This happens the same way how in tangents are handled above.
                     key.out_tangent = [
-                        c.keyframe_points[i].co[1] + ((c.keyframe_points[i].handle_right[1] - c.keyframe_points[i].co[1]
-                                                       ) / (frames[i + 1] - frame))
+                        c.keyframe_points[i].co[1] + (c.keyframe_points[i].handle_right[1] - c.keyframe_points[i].co[1]) / (c.keyframe_points[i].handle_right[0] - c.keyframe_points[i].co[0])
                         for c in channels if c is not None
                     ]
 
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 1ee98a29..5c8011ed 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
@@ -414,6 +414,7 @@ def __gather_output(channels: typing.Tuple[bpy.types.FCurve],
         transform = parent_inverse
 
     values = []
+    fps = bpy.context.scene.render.fps
     for keyframe in keyframes:
         # Transform the data and build gltf control points
         value = gltf2_blender_math.transform(keyframe.value, target_datapath, transform, need_rotation_correction)
@@ -426,11 +427,11 @@ def __gather_output(channels: typing.Tuple[bpy.types.FCurve],
             in_tangent = gltf2_blender_math.transform(keyframe.in_tangent, target_datapath, transform, need_rotation_correction)
             if is_yup and blender_object_if_armature is None:
                 in_tangent = gltf2_blender_math.swizzle_yup(in_tangent, target_datapath)
-            # the tangent in glTF is relative to the keyframe value
+            # the tangent in glTF is relative to the keyframe value and uses seconds
             if not isinstance(value, list):
-                in_tangent = value - in_tangent
+                in_tangent = fps * (in_tangent - value)
             else:
-                in_tangent = [value[i] - in_tangent[i] for i in range(len(value))]
+                in_tangent = [fps * (in_tangent[i] - value[i]) for i in range(len(value))]
             keyframe_value = gltf2_blender_math.mathutils_to_gltf(in_tangent) + keyframe_value  # append
 
         if keyframe.out_tangent is not None:
@@ -438,11 +439,11 @@ def __gather_output(channels: typing.Tuple[bpy.types.FCurve],
             out_tangent = gltf2_blender_math.transform(keyframe.out_tangent, target_datapath, transform, need_rotation_correction)
             if is_yup and blender_object_if_armature is None:
                 out_tangent = gltf2_blender_math.swizzle_yup(out_tangent, target_datapath)
-            # the tangent in glTF is relative to the keyframe value
+            # the tangent in glTF is relative to the keyframe value and uses seconds
             if not isinstance(value, list):
-                out_tangent = value - out_tangent
+                out_tangent = fps * (out_tangent - value)
             else:
-                out_tangent = [value[i] - out_tangent[i] for i in range(len(value))]
+                out_tangent = [fps * (out_tangent[i] - value[i]) for i in range(len(value))]
             keyframe_value = keyframe_value + gltf2_blender_math.mathutils_to_gltf(out_tangent)  # append
 
         values += keyframe_value



More information about the Bf-extensions-cvs mailing list