Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulien Duroure <julien.duroure@gmail.com>2020-04-11 16:36:52 +0300
committerJulien Duroure <julien.duroure@gmail.com>2020-04-11 16:36:52 +0300
commit8dd0687a6796227c3846f94454dcd40358896c92 (patch)
treea805b559132de9151b290e58f63dea420b684781
parent7a3fdf08f3fe4984bc81219a075a8bd3234c7d72 (diff)
glTF importer: refactoring animation import
-rwxr-xr-xio_scene_gltf2/__init__.py2
-rwxr-xr-xio_scene_gltf2/blender/imp/gltf2_blender_animation.py55
-rwxr-xr-xio_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py206
-rwxr-xr-xio_scene_gltf2/blender/imp/gltf2_blender_animation_node.py207
-rw-r--r--io_scene_gltf2/blender/imp/gltf2_blender_animation_utils.py6
-rw-r--r--io_scene_gltf2/blender/imp/gltf2_blender_animation_weight.py6
-rwxr-xr-xio_scene_gltf2/blender/imp/gltf2_blender_scene.py15
7 files changed, 165 insertions, 332 deletions
diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py
index ffcfeb7d..5317f0f8 100755
--- a/io_scene_gltf2/__init__.py
+++ b/io_scene_gltf2/__init__.py
@@ -15,7 +15,7 @@
bl_info = {
'name': 'glTF 2.0 format',
'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
- "version": (1, 2, 61),
+ "version": (1, 2, 62),
'blender': (2, 82, 7),
'location': 'File > Import-Export',
'description': 'Import-Export as glTF 2.0',
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_animation.py b/io_scene_gltf2/blender/imp/gltf2_blender_animation.py
index 71f3ec00..f01e5ee9 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_animation.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_animation.py
@@ -14,48 +14,47 @@
import bpy
-from .gltf2_blender_animation_bone import BlenderBoneAnim
from .gltf2_blender_animation_node import BlenderNodeAnim
from .gltf2_blender_animation_weight import BlenderWeightAnim
-from .gltf2_blender_animation_utils import restore_animation_on_object
+from .gltf2_blender_animation_utils import simulate_stash, restore_animation_on_object
from .gltf2_blender_vnode import VNode
class BlenderAnimation():
- """Dispatch Animation to bone or object animation."""
+ """Dispatch Animation to node or morph weights animation."""
def __new__(cls, *args, **kwargs):
raise RuntimeError("%s should not be instantiated" % cls)
@staticmethod
- def anim(gltf, anim_idx, vnode_id):
- """Dispatch Animation to bone or object."""
- if isinstance(vnode_id, int):
- if gltf.vnodes[vnode_id].type == VNode.Bone:
- BlenderBoneAnim.anim(gltf, anim_idx, vnode_id)
- elif gltf.vnodes[vnode_id].type == VNode.Object:
+ def anim(gltf, anim_idx):
+ """Create actions/tracks for one animation."""
+ # Caches the action for each object (keyed by object name)
+ gltf.action_cache = {}
+ # Things we need to stash when we're done.
+ gltf.needs_stash = []
+
+ for vnode_id in gltf.vnodes:
+ if isinstance(vnode_id, int):
BlenderNodeAnim.anim(gltf, anim_idx, vnode_id)
+ BlenderWeightAnim.anim(gltf, anim_idx, vnode_id)
- BlenderWeightAnim.anim(gltf, anim_idx, vnode_id)
-
- for child in gltf.vnodes[vnode_id].children:
- BlenderAnimation.anim(gltf, anim_idx, child)
+ # Push all actions onto NLA tracks with this animation's name
+ track_name = gltf.data.animations[anim_idx].track_name
+ for (obj, action) in gltf.needs_stash:
+ simulate_stash(obj, track_name, action)
@staticmethod
- def restore_animation(gltf, vnode_id, animation_name):
- """Restores the actions for an animation by its track name on
- the subtree starting at node_idx."""
- vnode = gltf.vnodes[vnode_id]
-
- obj = None
- if vnode.type == VNode.Bone:
- obj = gltf.vnodes[vnode.bone_arma].blender_object
- elif vnode.type == VNode.Object:
- obj = vnode.blender_object
-
- if obj is not None:
+ def restore_animation(gltf, animation_name):
+ """Restores the actions for an animation by its track name."""
+ for vnode_id in gltf.vnodes:
+ vnode = gltf.vnodes[vnode_id]
+ if vnode.type == VNode.Bone:
+ obj = gltf.vnodes[vnode.bone_arma].blender_object
+ elif vnode.type == VNode.Object:
+ obj = vnode.blender_object
+ else:
+ continue
+
restore_animation_on_object(obj, animation_name)
if obj.data and hasattr(obj.data, 'shape_keys'):
restore_animation_on_object(obj.data.shape_keys, animation_name)
-
- for child in gltf.vnodes[vnode_id].children:
- BlenderAnimation.restore_animation(gltf, child, animation_name)
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py b/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py
deleted file mode 100755
index 6f65de43..00000000
--- a/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py
+++ /dev/null
@@ -1,206 +0,0 @@
-# Copyright 2018-2019 The glTF-Blender-IO authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import json
-import bpy
-from mathutils import Vector
-
-from ...io.imp.gltf2_io_binary import BinaryData
-from .gltf2_blender_animation_utils import simulate_stash, make_fcurve
-
-
-# In Blender we animate a pose bone. The final TRS of the bone depends on
-# both the edit bone and pose bone
-#
-# Final = EditBone * PoseBone
-# where
-# Final = Trans[ft] Rot[fr] Scale[fs]
-# EditBone = Trans[et] Rot[er] (edit bones have no scale)
-# PoseBone = Trans[pt] Rot[pr] Scale[ps]
-#
-# Given Final we can solve for the PoseBone we need to use with
-#
-# pt = Rot[er^{-1}] (ft - et)
-# pr = er^{-1} fr
-# ps = fs
-
-class BlenderBoneAnim():
- """Blender Bone Animation."""
- def __new__(cls, *args, **kwargs):
- raise RuntimeError("%s should not be instantiated" % cls)
-
- @staticmethod
- def parse_translation_channel(gltf, vnode, obj, bone, channel, animation):
- """Manage Location animation."""
- blender_path = "pose.bones[" + json.dumps(bone.name) + "].location"
- group_name = bone.name
-
- keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
- values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
-
- if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
- # TODO manage tangent?
- translation_keyframes = (
- gltf.loc_gltf_to_blender(values[idx * 3 + 1])
- for idx in range(0, len(keys))
- )
- else:
- translation_keyframes = (gltf.loc_gltf_to_blender(vals) for vals in values)
-
- final_translations = vnode.base_locs_to_final_locs(translation_keyframes)
-
- # Calculate pose bone trans from final bone trans
- edit_trans, edit_rot = vnode.editbone_trans, vnode.editbone_rot
- edit_rot_inv = edit_rot.conjugated()
- pose_translations = [
- edit_rot_inv @ (trans - edit_trans)
- for trans in final_translations
- ]
-
- BlenderBoneAnim.fill_fcurves(
- obj.animation_data.action,
- keys,
- pose_translations,
- group_name,
- blender_path,
- animation.samplers[channel.sampler].interpolation
- )
-
- @staticmethod
- def parse_rotation_channel(gltf, vnode, obj, bone, channel, animation):
- """Manage rotation animation."""
- blender_path = "pose.bones[" + json.dumps(bone.name) + "].rotation_quaternion"
- group_name = bone.name
-
- keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
- values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
-
- if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
- # TODO manage tangent?
- quat_keyframes = [
- gltf.quaternion_gltf_to_blender(values[idx * 3 + 1])
- for idx in range(0, len(keys))
- ]
- else:
- quat_keyframes = [gltf.quaternion_gltf_to_blender(vals) for vals in values]
-
- final_rots = vnode.base_rots_to_final_rots(quat_keyframes)
-
- # Calculate pose bone rotation from final bone rotation
- edit_rot = vnode.editbone_rot
- edit_rot_inv = edit_rot.conjugated()
- pose_rots = [
- edit_rot_inv @ rot
- for rot in final_rots
- ]
-
- # Manage antipodal quaternions
- for i in range(1, len(pose_rots)):
- if pose_rots[i].dot(pose_rots[i-1]) < 0:
- pose_rots[i] = -pose_rots[i]
-
- BlenderBoneAnim.fill_fcurves(
- obj.animation_data.action,
- keys,
- pose_rots,
- group_name,
- blender_path,
- animation.samplers[channel.sampler].interpolation
- )
-
- @staticmethod
- def parse_scale_channel(gltf, vnode, obj, bone, channel, animation):
- """Manage scaling animation."""
- blender_path = "pose.bones[" + json.dumps(bone.name) + "].scale"
- group_name = bone.name
-
- keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
- values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
-
- if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
- # TODO manage tangent?
- scale_keyframes = [
- gltf.scale_gltf_to_blender(values[idx * 3 + 1])
- for idx in range(0, len(keys))
- ]
- else:
- scale_keyframes = [gltf.scale_gltf_to_blender(vals) for vals in values]
-
- final_scales = vnode.base_scales_to_final_scales(scale_keyframes)
- pose_scales = final_scales # no change needed
-
- BlenderBoneAnim.fill_fcurves(
- obj.animation_data.action,
- keys,
- pose_scales,
- group_name,
- blender_path,
- animation.samplers[channel.sampler].interpolation
- )
-
- @staticmethod
- def fill_fcurves(action, keys, values, group_name, blender_path, interpolation):
- """Create FCurves from the keyframe-value pairs (one per component)."""
- fps = bpy.context.scene.render.fps
-
- coords = [0] * (2 * len(keys))
- coords[::2] = (key[0] * fps for key in keys)
-
- for i in range(0, len(values[0])):
- coords[1::2] = (vals[i] for vals in values)
- make_fcurve(
- action,
- coords,
- data_path=blender_path,
- index=i,
- group_name=group_name,
- interpolation=interpolation,
- )
-
- @staticmethod
- def anim(gltf, anim_idx, node_idx):
- """Manage animation."""
- node = gltf.data.nodes[node_idx]
- vnode = gltf.vnodes[node_idx]
- obj = gltf.vnodes[vnode.bone_arma].blender_object
- bone = obj.pose.bones[vnode.blender_bone_name]
-
- if anim_idx not in node.animations.keys():
- return
-
- animation = gltf.data.animations[anim_idx]
-
- action = gltf.action_cache.get(obj.name)
- if not action:
- name = animation.track_name + "_" + obj.name
- action = bpy.data.actions.new(name)
- action.id_root = 'OBJECT'
- gltf.needs_stash.append((obj, animation.track_name, action))
- gltf.action_cache[obj.name] = action
-
- if not obj.animation_data:
- obj.animation_data_create()
- obj.animation_data.action = action
-
- for channel_idx in node.animations[anim_idx]:
- channel = animation.channels[channel_idx]
-
- if channel.target.path == "translation":
- BlenderBoneAnim.parse_translation_channel(gltf, vnode, obj, bone, channel, animation)
-
- elif channel.target.path == "rotation":
- BlenderBoneAnim.parse_rotation_channel(gltf, vnode, obj, bone, channel, animation)
-
- elif channel.target.path == "scale":
- BlenderBoneAnim.parse_scale_channel(gltf, vnode, obj, bone, channel, animation)
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_animation_node.py b/io_scene_gltf2/blender/imp/gltf2_blender_animation_node.py
index b6369b8b..d41b7892 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_animation_node.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_animation_node.py
@@ -12,11 +12,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import json
import bpy
from mathutils import Vector
from ...io.imp.gltf2_io_binary import BinaryData
-from .gltf2_blender_animation_utils import simulate_stash, make_fcurve
+from .gltf2_blender_animation_utils import make_fcurve
from .gltf2_blender_vnode import VNode
@@ -27,92 +28,144 @@ class BlenderNodeAnim():
@staticmethod
def anim(gltf, anim_idx, node_idx):
- """Manage animation."""
- node = gltf.data.nodes[node_idx]
- vnode = gltf.vnodes[node_idx]
- obj = vnode.blender_object
- fps = bpy.context.scene.render.fps
-
+ """Manage animation targeting a node's TRS."""
animation = gltf.data.animations[anim_idx]
-
+ node = gltf.data.nodes[node_idx]
if anim_idx not in node.animations.keys():
return
for channel_idx in node.animations[anim_idx]:
channel = animation.channels[channel_idx]
- if channel.target.path in ['translation', 'rotation', 'scale']:
- break
- else:
- return
+ if channel.target.path not in ['translation', 'rotation', 'scale']:
+ continue
+
+ BlenderNodeAnim.do_channel(gltf, anim_idx, node_idx, channel)
+
+ @staticmethod
+ def do_channel(gltf, anim_idx, node_idx, channel):
+ animation = gltf.data.animations[anim_idx]
+ vnode = gltf.vnodes[node_idx]
+ path = channel.target.path
+
+ action = BlenderNodeAnim.get_or_create_action(gltf, node_idx, animation.track_name)
+
+ keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
+ values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
+
+ if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
+ # TODO manage tangent?
+ values = values[1::3]
+
+ # Convert the curve from glTF to Blender.
+
+ if path == "translation":
+ blender_path = "location"
+ group_name = "Location"
+ num_components = 3
+ values = [gltf.loc_gltf_to_blender(vals) for vals in values]
+ values = vnode.base_locs_to_final_locs(values)
+
+ elif path == "rotation":
+ blender_path = "rotation_quaternion"
+ group_name = "Rotation"
+ num_components = 4
+ values = [gltf.quaternion_gltf_to_blender(vals) for vals in values]
+ values = vnode.base_rots_to_final_rots(values)
+
+ elif path == "scale":
+ blender_path = "scale"
+ group_name = "Scale"
+ num_components = 3
+ values = [gltf.scale_gltf_to_blender(vals) for vals in values]
+ values = vnode.base_scales_to_final_scales(values)
+
+ # Objects parented to a bone are translated to the bone tip by default.
+ # Correct for this by translating backwards from the tip to the root.
+ if vnode.type == VNode.Object and path == "translation":
+ if vnode.parent is not None and gltf.vnodes[vnode.parent].type == VNode.Bone:
+ bone_length = gltf.vnodes[vnode.parent].bone_length
+ off = Vector((0, -bone_length, 0))
+ values = [vals + off for vals in values]
+
+ if vnode.type == VNode.Bone:
+ # Need to animate the pose bone when the node is a bone.
+ group_name = vnode.blender_bone_name
+ blender_path = "pose.bones[%s].%s" % (json.dumps(vnode.blender_bone_name), blender_path)
+
+ # We have the final TRS of the bone in values. We need to give
+ # the TRS of the pose bone though, which is relative to the edit
+ # bone.
+ #
+ # Final = EditBone * PoseBone
+ # where
+ # Final = Trans[ft] Rot[fr] Scale[fs]
+ # EditBone = Trans[et] Rot[er]
+ # PoseBone = Trans[pt] Rot[pr] Scale[ps]
+ #
+ # Solving for PoseBone gives
+ #
+ # pt = Rot[er^{-1}] (ft - et)
+ # pr = er^{-1} fr
+ # ps = fs
+
+ if path == 'translation':
+ edit_trans, edit_rot = vnode.editbone_trans, vnode.editbone_rot
+ edit_rot_inv = edit_rot.conjugated()
+ values = [
+ edit_rot_inv @ (trans - edit_trans)
+ for trans in values
+ ]
+
+ elif path == 'rotation':
+ edit_rot = vnode.editbone_rot
+ edit_rot_inv = edit_rot.conjugated()
+ values = [
+ edit_rot_inv @ rot
+ for rot in values
+ ]
+
+ elif path == 'scale':
+ pass # no change needed
+
+ # To ensure rotations always take the shortest path, we flip
+ # adjacent antipodal quaternions.
+ if path == 'rotation':
+ for i in range(1, len(values)):
+ if values[i].dot(values[i-1]) < 0:
+ values[i] = -values[i]
+
+ fps = bpy.context.scene.render.fps
+
+ coords = [0] * (2 * len(keys))
+ coords[::2] = (key[0] * fps for key in keys)
+
+ for i in range(0, num_components):
+ coords[1::2] = (vals[i] for vals in values)
+ make_fcurve(
+ action,
+ coords,
+ data_path=blender_path,
+ index=i,
+ group_name=group_name,
+ interpolation=animation.samplers[channel.sampler].interpolation,
+ )
+
+ @staticmethod
+ def get_or_create_action(gltf, node_idx, anim_name):
+ vnode = gltf.vnodes[node_idx]
+
+ if vnode.type == VNode.Bone:
+ # For bones, the action goes on the armature.
+ vnode = gltf.vnodes[vnode.bone_arma]
+
+ obj = vnode.blender_object
action = gltf.action_cache.get(obj.name)
if not action:
- name = animation.track_name + "_" + obj.name
+ name = anim_name + "_" + obj.name
action = bpy.data.actions.new(name)
action.id_root = 'OBJECT'
- gltf.needs_stash.append((obj, animation.track_name, action))
+ gltf.needs_stash.append((obj, action))
gltf.action_cache[obj.name] = action
- if not obj.animation_data:
- obj.animation_data_create()
- obj.animation_data.action = action
-
- for channel_idx in node.animations[anim_idx]:
- channel = animation.channels[channel_idx]
-
- keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
- values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
-
- if channel.target.path not in ['translation', 'rotation', 'scale']:
- continue
-
- if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
- # TODO manage tangent?
- values = [values[idx * 3 + 1] for idx in range(0, len(keys))]
-
- if channel.target.path == "translation":
- blender_path = "location"
- group_name = "Location"
- num_components = 3
- values = [gltf.loc_gltf_to_blender(vals) for vals in values]
- values = vnode.base_locs_to_final_locs(values)
-
- if vnode.parent is not None and gltf.vnodes[vnode.parent].type == VNode.Bone:
- # Nodes with a bone parent need to be translated
- # backwards from the tip to the root
- bone_length = gltf.vnodes[vnode.parent].bone_length
- off = Vector((0, -bone_length, 0))
- values = [vals + off for vals in values]
-
- elif channel.target.path == "rotation":
- blender_path = "rotation_quaternion"
- group_name = "Rotation"
- num_components = 4
- values = [gltf.quaternion_gltf_to_blender(vals) for vals in values]
- values = vnode.base_rots_to_final_rots(values)
-
- # Manage antipodal quaternions
- for i in range(1, len(values)):
- if values[i].dot(values[i-1]) < 0:
- values[i] = -values[i]
-
- elif channel.target.path == "scale":
- blender_path = "scale"
- group_name = "Scale"
- num_components = 3
- values = [gltf.scale_gltf_to_blender(vals) for vals in values]
- values = vnode.base_scales_to_final_scales(values)
-
- coords = [0] * (2 * len(keys))
- coords[::2] = (key[0] * fps for key in keys)
-
- for i in range(0, num_components):
- coords[1::2] = (vals[i] for vals in values)
- make_fcurve(
- action,
- coords,
- data_path=blender_path,
- index=i,
- group_name=group_name,
- interpolation=animation.samplers[channel.sampler].interpolation,
- )
+ return action
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_animation_utils.py b/io_scene_gltf2/blender/imp/gltf2_blender_animation_utils.py
index 6c933852..2d0d8568 100644
--- a/io_scene_gltf2/blender/imp/gltf2_blender_animation_utils.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_animation_utils.py
@@ -19,16 +19,16 @@ def simulate_stash(obj, track_name, action, start_frame=None):
# * add a track
# * add an action on track
# * lock & mute the track
- # * remove active action from object
+ if not obj.animation_data:
+ obj.animation_data_create()
tracks = obj.animation_data.nla_tracks
new_track = tracks.new(prev=None)
new_track.name = track_name
if start_frame is None:
start_frame = bpy.context.scene.frame_start
- strip = new_track.strips.new(action.name, start_frame, action)
+ _strip = new_track.strips.new(action.name, start_frame, action)
new_track.lock = True
new_track.mute = True
- obj.animation_data.action = None
def restore_animation_on_object(obj, anim_name):
if not getattr(obj, 'animation_data', None):
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_animation_weight.py b/io_scene_gltf2/blender/imp/gltf2_blender_animation_weight.py
index 1329243d..5ce4532e 100644
--- a/io_scene_gltf2/blender/imp/gltf2_blender_animation_weight.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_animation_weight.py
@@ -52,11 +52,7 @@ class BlenderWeightAnim():
name = animation.track_name + "_" + obj.name
action = bpy.data.actions.new(name)
action.id_root = "KEY"
- gltf.needs_stash.append((obj.data.shape_keys, animation.track_name, action))
-
- if not obj.data.shape_keys.animation_data:
- obj.data.shape_keys.animation_data_create()
- obj.data.shape_keys.animation_data.action = action
+ gltf.needs_stash.append((obj.data.shape_keys, action))
keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_scene.py b/io_scene_gltf2/blender/imp/gltf2_blender_scene.py
index 109d6b28..1bc3fe0b 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_scene.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_scene.py
@@ -17,7 +17,6 @@ from math import sqrt
from mathutils import Quaternion
from .gltf2_blender_node import BlenderNode
from .gltf2_blender_animation import BlenderAnimation
-from .gltf2_blender_animation_utils import simulate_stash
from .gltf2_blender_vnode import VNode, compute_vnodes
@@ -51,20 +50,12 @@ class BlenderScene():
def create_animations(gltf):
"""Create animations."""
if gltf.data.animations:
- for anim_idx, anim in enumerate(gltf.data.animations):
- # Caches the action for each object (keyed by object name)
- gltf.action_cache = {}
- # Things we need to stash when we're done.
- gltf.needs_stash = []
-
- BlenderAnimation.anim(gltf, anim_idx, 'root')
-
- for (obj, anim_name, action) in gltf.needs_stash:
- simulate_stash(obj, anim_name, action)
+ for anim_idx, _anim in enumerate(gltf.data.animations):
+ BlenderAnimation.anim(gltf, anim_idx)
# Restore first animation
anim_name = gltf.data.animations[0].track_name
- BlenderAnimation.restore_animation(gltf, 'root', anim_name)
+ BlenderAnimation.restore_animation(gltf, anim_name)
@staticmethod
def set_active_object(gltf):