Skip to content
Snippets Groups Projects
Commit 08d13c02 authored by Julien Duroure's avatar Julien Duroure
Browse files

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

Fix when animation are not baked
parent 40828240
No related branches found
No related tags found
No related merge requests found
......@@ -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',
......
......@@ -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
]
......
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment