File headers: use SPDX license identifiers
[blender-addons.git] / io_scene_gltf2 / blender / imp / gltf2_blender_animation_weight.py
blob351355fb2e81ef20ec20060f54ea1142b3671278
1 # SPDX-License-Identifier: Apache-2.0
2 # Copyright 2018-2021 The glTF-Blender-IO authors.
4 import bpy
6 from ...io.imp.gltf2_io_binary import BinaryData
7 from .gltf2_blender_animation_utils import make_fcurve
8 from io_scene_gltf2.io.imp.gltf2_io_user_extensions import import_user_extensions
11 class BlenderWeightAnim():
12 """Blender ShapeKey Animation."""
13 def __new__(cls, *args, **kwargs):
14 raise RuntimeError("%s should not be instantiated" % cls)
16 @staticmethod
17 def anim(gltf, anim_idx, vnode_id):
18 """Manage animation."""
19 vnode = gltf.vnodes[vnode_id]
21 node_idx = vnode.mesh_node_idx
23 import_user_extensions('gather_import_animation_weight_before_hook', gltf, vnode, gltf.data.animations[anim_idx])
25 if node_idx is None:
26 return
28 node = gltf.data.nodes[node_idx]
29 obj = vnode.blender_object
30 fps = bpy.context.scene.render.fps
32 animation = gltf.data.animations[anim_idx]
34 if anim_idx not in node.animations.keys():
35 return
37 for channel_idx in node.animations[anim_idx]:
38 channel = animation.channels[channel_idx]
39 if channel.target.path == "weights":
40 break
41 else:
42 return
44 name = animation.track_name + "_" + obj.name
45 action = bpy.data.actions.new(name)
46 action.id_root = "KEY"
47 gltf.needs_stash.append((obj.data.shape_keys, action))
49 keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
50 values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
52 # retrieve number of targets
53 pymesh = gltf.data.meshes[gltf.data.nodes[node_idx].mesh]
54 nb_targets = len(pymesh.shapekey_names)
56 if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
57 offset = nb_targets
58 stride = 3 * nb_targets
59 else:
60 offset = 0
61 stride = nb_targets
63 coords = [0] * (2 * len(keys))
64 coords[::2] = (key[0] * fps for key in keys)
66 for sk in range(nb_targets):
67 if pymesh.shapekey_names[sk] is not None: # Do not animate shapekeys not created
68 coords[1::2] = (values[offset + stride * i + sk][0] for i in range(len(keys)))
69 kb_name = pymesh.shapekey_names[sk]
70 data_path = 'key_blocks["%s"].value' % bpy.utils.escape_identifier(kb_name)
72 make_fcurve(
73 action,
74 coords,
75 data_path=data_path,
76 group_name="ShapeKeys",
77 interpolation=animation.samplers[channel.sampler].interpolation,
80 # Expand weight range if needed
81 kb = obj.data.shape_keys.key_blocks[kb_name]
82 min_weight = min(coords[1:2])
83 max_weight = max(coords[1:2])
84 if min_weight < kb.slider_min: kb.slider_min = min_weight
85 if max_weight > kb.slider_max: kb.slider_max = max_weight
87 import_user_extensions('gather_import_animation_weight_after_hook', gltf, vnode, animation)