[Bf-extensions-cvs] [295984b2] master: glTF exporter: fix animation when a property is single keyframed (not all property index)

Julien Duroure noreply at git.blender.org
Sun May 26 23:57:32 CEST 2019


Commit: 295984b200890cf6d5bdea6af5a3bd3d4260b765
Author: Julien Duroure
Date:   Sun May 26 22:34:29 2019 +0200
Branches: master
https://developer.blender.org/rBA295984b200890cf6d5bdea6af5a3bd3d4260b765

glTF exporter: fix animation when a property is single keyframed (not all property index)

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

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/exp/gltf2_blender_gather_animation_sampler_keyframes.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py
index 34e4c5e0..a6cd0f9e 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
@@ -37,7 +37,7 @@ class Keyframe:
         self.__in_tangent = None
         self.__out_tangent = None
 
-    def __get_target_len(self):
+    def get_target_len(self):
         length = {
             "delta_location": 3,
             "delta_rotation_euler": 3,
@@ -61,12 +61,23 @@ class Keyframe:
         # Sometimes blender animations only reference a subset of components of a data target. Keyframe should always
         # contain a complete Vector/ Quaternion --> use the array_index value of the keyframe to set components in such
         # structures
-        result = [0.0] * self.__get_target_len()
+        result = [0.0] * self.get_target_len()
         for i, v in zip(self.__indices, value):
             result[i] = v
         result = gltf2_blender_math.list_to_mathutils(result, self.target)
         return result
 
+    def get_indices(self):
+        return self.__indices
+
+    def set_value_index(self, idx, val):
+        self.__value[idx] = val
+
+    def set_full_value(self, val):
+        self.__value = [0.0] * self.get_target_len()
+        for i in range(0, self.get_target_len()):
+            self.set_value_index(i, val[i])
+
     @property
     def value(self) -> typing.Union[mathutils.Vector, mathutils.Euler, mathutils.Quaternion, typing.List[float]]:
         return self.__value
@@ -96,7 +107,9 @@ class Keyframe:
 @cached
 def gather_keyframes(blender_object_if_armature: typing.Optional[bpy.types.Object],
                      channels: typing.Tuple[bpy.types.FCurve],
-                     export_settings) -> typing.List[Keyframe]:
+                     non_keyed_values: typing.Tuple[typing.Optional[float]],
+                     export_settings
+                     ) -> typing.List[Keyframe]:
     """Convert the blender action groups' fcurves to keyframes for use in glTF."""
     # Find the start and end of the whole action group
     ranges = [channel.range() for channel in channels]
@@ -105,16 +118,17 @@ def gather_keyframes(blender_object_if_armature: typing.Optional[bpy.types.Objec
     end_frame = max([channel.range()[1] for channel in channels])
 
     keyframes = []
+
+    if blender_object_if_armature is not None:
+        pose_bone_if_armature = gltf2_blender_get.get_object_from_datapath(blender_object_if_armature,
+                                                                           channels[0].data_path)
+    else:
+        pose_bone_if_armature = None
+
     if needs_baking(blender_object_if_armature, channels, export_settings):
         # Bake the animation, by evaluating the animation for all frames
         # TODO: maybe baking can also be done with FCurve.convert_to_samples
 
-        if blender_object_if_armature is not None:
-            pose_bone_if_armature = gltf2_blender_get.get_object_from_datapath(blender_object_if_armature,
-                                                                               channels[0].data_path)
-        else:
-            pose_bone_if_armature = None
-
         # sample all frames
         frame = start_frame
         step = export_settings['gltf_frame_step']
@@ -123,18 +137,21 @@ def gather_keyframes(blender_object_if_armature: typing.Optional[bpy.types.Objec
             if isinstance(pose_bone_if_armature, bpy.types.PoseBone):
                 # we need to bake in the constraints
                 bpy.context.scene.frame_set(frame)
+                # TODO, this is not working if the action is not active (NLA case for example)
                 trans, rot, scale = pose_bone_if_armature.matrix_basis.decompose()
                 target_property = channels[0].data_path.split('.')[-1]
-                key.value = {
+                # Store all values, not only the data from fcurve:
+                # All indices must be stored
+                key.set_full_value({
                     "location": trans,
                     "rotation_axis_angle": rot,
                     "rotation_euler": rot,
                     "rotation_quaternion": rot,
                     "scale": scale
-                }[target_property]
-
+                }[target_property])
             else:
                 key.value = [c.evaluate(frame) for c in channels]
+                complete_key(key, non_keyed_values)
             keyframes.append(key)
             frame += step
     else:
@@ -142,8 +159,10 @@ def gather_keyframes(blender_object_if_armature: typing.Optional[bpy.types.Objec
         frames = [keyframe.co[0] for keyframe in channels[0].keyframe_points]
         for i, frame in enumerate(frames):
             key = Keyframe(channels, frame)
-            # key.value = [c.keyframe_points[i].co[0] for c in action_group.channels]
             key.value = [c.evaluate(frame) for c in channels]
+            # Complete key with non keyed values, if needed
+            if len(channels) != key.get_target_len():
+                complete_key(key, non_keyed_values)
 
             # compute tangents for cubic spline interpolation
             if channels[0].keyframe_points[0].interpolation == "BEZIER":
@@ -179,6 +198,18 @@ def gather_keyframes(blender_object_if_armature: typing.Optional[bpy.types.Objec
     return keyframes
 
 
+def complete_key(key: Keyframe, non_keyed_values: typing.Tuple[typing.Optional[float]]):
+    """
+    Complete keyframe with non keyed values
+    """
+
+    if key.target == "value":
+        return # No array_index
+    for i in range(0, key.get_target_len()):
+        if i in key.get_indices():
+            continue # this is a keyed array_index
+        key.set_value_index(i, non_keyed_values[i])
+
 def needs_baking(blender_object_if_armature: typing.Optional[bpy.types.Object],
                  channels: typing.Tuple[bpy.types.FCurve],
                  export_settings
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 827ec91e..cdd4be7b 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
@@ -34,17 +34,81 @@ def gather_animation_sampler(channels: typing.Tuple[bpy.types.FCurve],
                              blender_object: bpy.types.Object,
                              export_settings
                              ) -> gltf2_io.AnimationSampler:
+
     blender_object_if_armature = blender_object if blender_object.type == "ARMATURE" else None
+    if blender_object_if_armature is not None:
+        pose_bone_if_armature = gltf2_blender_get.get_object_from_datapath(blender_object_if_armature,
+                                                                           channels[0].data_path)
+    else:
+        pose_bone_if_armature = None
+    non_keyed_values = __gather_non_keyed_values(channels, blender_object,
+                                                 blender_object_if_armature, pose_bone_if_armature,
+                                                 export_settings)
+
+
     return gltf2_io.AnimationSampler(
         extensions=__gather_extensions(channels, blender_object_if_armature, export_settings),
         extras=__gather_extras(channels, blender_object_if_armature, export_settings),
-        input=__gather_input(channels, blender_object_if_armature, export_settings),
+        input=__gather_input(channels, blender_object_if_armature, non_keyed_values, export_settings),
         interpolation=__gather_interpolation(channels, blender_object_if_armature, export_settings),
         output=__gather_output(channels, blender_object.matrix_parent_inverse.copy().freeze(),
                                blender_object_if_armature,
+                               non_keyed_values,
                                export_settings)
     )
 
+def __gather_non_keyed_values(channels: typing.Tuple[bpy.types.FCurve],
+                              blender_object: bpy.types.Object,
+                              blender_object_if_armature: typing.Optional[bpy.types.Object],
+                              pose_bone_if_armature: typing.Optional[bpy.types.PoseBone],
+                              export_settings
+                              ) ->  typing.Tuple[typing.Optional[float]]:
+
+    non_keyed_values = []
+
+    target = channels[0].data_path.split('.')[-1]
+    if target == "value":
+        return ()
+
+    indices = [c.array_index for c in channels]
+    indices.sort()
+    length = {
+        "delta_location": 3,
+        "delta_rotation_euler": 3,
+        "location": 3,
+        "rotation_axis_angle": 4,
+        "rotation_euler": 3,
+        "rotation_quaternion": 4,
+        "scale": 3,
+        "value": 1
+    }.get(target)
+
+    for i in range(0, length):
+        if i in indices:
+            non_keyed_values.append(None)
+        else:
+            if blender_object_if_armature is None:
+                non_keyed_values.append({
+                    "delta_location" : blender_object.delta_location,
+                    "delta_rotation_euler" : blender_object.delta_rotation_euler,
+                    "location" : blender_object.location,
+                    "rotation_axis_angle" : blender_object.rotation_axis_angle,
+                    "rotation_euler" : blender_object.rotation_euler,
+                    "rotation_quaternion" : blender_object.rotation_quaternion,
+                    "scale" : blender_object.scale
+                }[target][i])
+            else:
+                 # TODO, this is not working if the action is not active (NLA case for example)
+                 trans, rot, scale = pose_bone_if_armature.matrix_basis.decompose()
+                 non_keyed_values.append({
+                    "location": trans,
+                    "rotation_axis_angle": rot,
+                    "rotation_euler": rot,
+                    "rotation_quaternion": rot,
+

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list