[Bf-extensions-cvs] [5dba7a81] master: glTF importer: Huge speedup performance for animation import

Julien Duroure noreply at git.blender.org
Sun Jan 27 18:16:55 CET 2019


Commit: 5dba7a81397ac3b1d2a93be28a51165f8eaf3767
Author: Julien Duroure
Date:   Sun Jan 27 18:15:02 2019 +0100
Branches: master
https://developer.blender.org/rBA5dba7a81397ac3b1d2a93be28a51165f8eaf3767

glTF importer: Huge speedup performance for animation import

Using foreach_set instead of individual keyframing
Thanks to Scurest for the PR :)

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

M	io_scene_gltf2/__init__.py
M	io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py
M	io_scene_gltf2/blender/imp/gltf2_blender_animation_node.py

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

diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py
index c01a3e81..0f44e327 100755
--- a/io_scene_gltf2/__init__.py
+++ b/io_scene_gltf2/__init__.py
@@ -17,6 +17,7 @@
 #
 
 import os
+import time
 import bpy
 from bpy_extras.io_utils import ImportHelper, ExportHelper
 from bpy.types import Operator, AddonPreferences
@@ -482,8 +483,10 @@ class ImportGLTF2(Operator, ImportHelper):
             self.report({'ERROR'}, txt)
             return {'CANCELLED'}
         self.gltf_importer.log.critical("Data are loaded, start creating Blender stuff")
+        start_time = time.time()
         BlenderGlTF.create(self.gltf_importer)
-        self.gltf_importer.log.critical("glTF import is now finished")
+        elapsed_s = "{:.2f}s".format(time.time() - start_time)
+        self.gltf_importer.log.critical("glTF import finished in " + elapsed_s)
         self.gltf_importer.log.removeHandler(self.gltf_importer.log_handler)
 
         return {'FINISHED'}
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py b/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py
index 9e632255..343e66b7 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import json
 import bpy
 from mathutils import Matrix
 
@@ -39,38 +40,46 @@ class BlenderBoneAnim():
     @staticmethod
     def parse_translation_channel(gltf, node, obj, bone, channel, animation):
         """Manage Location animation."""
-        fps = bpy.context.scene.render.fps
-        blender_path = "location"
+        blender_path = "pose.bones[" + json.dumps(bone.name) + "].location"
+        group_name = "location"
 
         keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
         values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
         inv_bind_matrix = node.blender_bone_matrix.to_quaternion().to_matrix().to_4x4().inverted() \
             @ Matrix.Translation(node.blender_bone_matrix.to_translation()).inverted()
 
-        for idx, key in enumerate(keys):
-            if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
-                # TODO manage tangent?
-                translation_keyframe = loc_gltf_to_blender(values[idx * 3 + 1])
-            else:
-                translation_keyframe = loc_gltf_to_blender(values[idx])
-            if node.parent is None:
+        if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
+            # TODO manage tangent?
+            translation_keyframes = (
+                loc_gltf_to_blender(values[idx * 3 + 1])
+                for idx in range(0, len(keys))
+            )
+        else:
+            translation_keyframes = (loc_gltf_to_blender(vals) for vals in values)
+        if node.parent is None:
+            parent_mat = Matrix()
+        else:
+            if not gltf.data.nodes[node.parent].is_joint:
                 parent_mat = Matrix()
             else:
-                if not gltf.data.nodes[node.parent].is_joint:
-                    parent_mat = Matrix()
-                else:
-                    parent_mat = gltf.data.nodes[node.parent].blender_bone_matrix
-
-            # Pose is in object (armature) space and it's value if the offset from the bind pose
-            # (which is also in object space)
-            # Scale is not taken into account
-            final_trans = (parent_mat @ Matrix.Translation(translation_keyframe)).to_translation()
-            bone.location = inv_bind_matrix @ final_trans
-            bone.keyframe_insert(blender_path, frame=key[0] * fps, group="location")
-
-        for fcurve in [curve for curve in obj.animation_data.action.fcurves if curve.group.name == "location"]:
-            for kf in fcurve.keyframe_points:
-                BlenderBoneAnim.set_interpolation(animation.samplers[channel.sampler].interpolation, kf)
+                parent_mat = gltf.data.nodes[node.parent].blender_bone_matrix
+
+        # Pose is in object (armature) space and it's value if the offset from the bind pose
+        # (which is also in object space)
+        # Scale is not taken into account
+        final_translations = [
+            inv_bind_matrix @ (parent_mat @ Matrix.Translation(translation_keyframe)).to_translation()
+            for translation_keyframe in translation_keyframes
+        ]
+
+        BlenderBoneAnim.fill_fcurves(
+            obj.animation_data.action,
+            keys,
+            final_translations,
+            group_name,
+            blender_path,
+            animation.samplers[channel.sampler].interpolation
+        )
 
     @staticmethod
     def parse_rotation_channel(gltf, node, obj, bone, channel, animation):
@@ -82,73 +91,120 @@ class BlenderBoneAnim():
         # Converting to euler and then back to quaternion is a dirty fix preventing this issue in animation, until a
         # better solution is found
         # This fix is skipped when parent matrix is identity
-        fps = bpy.context.scene.render.fps
-        blender_path = "rotation_quaternion"
+        blender_path = "pose.bones[" + json.dumps(bone.name) + "].rotation_quaternion"
+        group_name = "rotation"
 
         keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
         values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
         bind_rotation = node.blender_bone_matrix.to_quaternion()
 
-        for idx, key in enumerate(keys):
-            if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
-                # TODO manage tangent?
-                quat_keyframe = quaternion_gltf_to_blender(values[idx * 3 + 1])
+        if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
+            # TODO manage tangent?
+            quat_keyframes = (
+                quaternion_gltf_to_blender(values[idx * 3 + 1])
+                for idx in range(0, len(keys))
+            )
+        else:
+            quat_keyframes = (quaternion_gltf_to_blender(vals) for vals in values)
+        if not node.parent:
+            final_rots = [
+                bind_rotation.inverted() @ quat_keyframe
+                for quat_keyframe in quat_keyframes
+            ]
+        else:
+            if not gltf.data.nodes[node.parent].is_joint:
+                parent_mat = Matrix()
             else:
-                quat_keyframe = quaternion_gltf_to_blender(values[idx])
-            if not node.parent:
-                bone.rotation_quaternion = bind_rotation.inverted() @ quat_keyframe
+                parent_mat = gltf.data.nodes[node.parent].blender_bone_matrix
+
+            if parent_mat != parent_mat.inverted():
+                final_rots = [
+                    bind_rotation.rotation_difference(
+                        (parent_mat @ quat_keyframe.to_matrix().to_4x4()).to_quaternion()
+                    ).to_euler().to_quaternion()
+                    for quat_keyframe in quat_keyframes
+                ]
             else:
-                if not gltf.data.nodes[node.parent].is_joint:
-                    parent_mat = Matrix()
-                else:
-                    parent_mat = gltf.data.nodes[node.parent].blender_bone_matrix
-
-                if parent_mat != parent_mat.inverted():
-                    final_rot = (parent_mat @ quat_keyframe.to_matrix().to_4x4()).to_quaternion()
-                    bone.rotation_quaternion = bind_rotation.rotation_difference(final_rot).to_euler().to_quaternion()
-                else:
-                    bone.rotation_quaternion = \
-                        bind_rotation.rotation_difference(quat_keyframe).to_euler().to_quaternion()
-
-            bone.keyframe_insert(blender_path, frame=key[0] * fps, group='rotation')
-
-        for fcurve in [curve for curve in obj.animation_data.action.fcurves if curve.group.name == "rotation"]:
-            for kf in fcurve.keyframe_points:
-                BlenderBoneAnim.set_interpolation(animation.samplers[channel.sampler].interpolation, kf)
+                final_rots = [
+                    bind_rotation.rotation_difference(quat_keyframe).to_euler().to_quaternion()
+                    for quat_keyframe in quat_keyframes
+                ]
+
+        BlenderBoneAnim.fill_fcurves(
+            obj.animation_data.action,
+            keys,
+            final_rots,
+            group_name,
+            blender_path,
+            animation.samplers[channel.sampler].interpolation
+        )
 
     @staticmethod
     def parse_scale_channel(gltf, node, obj, bone, channel, animation):
         """Manage scaling animation."""
-        fps = bpy.context.scene.render.fps
-        blender_path = "scale"
+        blender_path = "pose.bones[" + json.dumps(bone.name) + "].scale"
+        group_name = "scale"
 
         keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
         values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
         bind_scale = scale_to_matrix(node.blender_bone_matrix.to_scale())
 
-        for idx, key in enumerate(keys):
-            if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
-                # TODO manage tangent?
-                scale_mat = scale_to_matrix(loc_gltf_to_blender(values[idx * 3 + 1]))
-            else:
-                scale_mat = scale_to_matrix(loc_gltf_to_blender(values[idx]))
-            if not node.parent:
-                bone.scale = (bind_scale.inverted() @ scale_mat).to_scale()
+        if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
+            # TODO manage tangent?
+            scale_mats = (
+                scale_to_matrix(loc_gltf_to_blender(values[idx * 3 + 1]))
+                for idx in range(0, len(keys))
+            )
+        else:
+            scale_mats = (scale_to_matrix(loc_gltf_to_blender(vals)) for vals in values)
+        if not node.parent:
+            final_scales = [
+               

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list