diff options
3 files changed, 47 insertions, 30 deletions
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 |