diff options
author | Julien Duroure <julien.duroure@gmail.com> | 2019-09-17 23:18:19 +0300 |
---|---|---|
committer | Julien Duroure <julien.duroure@gmail.com> | 2019-09-17 23:18:43 +0300 |
commit | 87ffe55fd5f704fd981b678f94f3570268025955 (patch) | |
tree | 54bba434df051de9b6de58683443978e394af784 /io_scene_gltf2/blender/imp/gltf2_blender_animation_node.py | |
parent | 12c0374e16ebe0dc0953bfad720b3d8202c71c7f (diff) |
glTF importer: better multi-object animation management
Diffstat (limited to 'io_scene_gltf2/blender/imp/gltf2_blender_animation_node.py')
-rwxr-xr-x | io_scene_gltf2/blender/imp/gltf2_blender_animation_node.py | 203 |
1 files changed, 72 insertions, 131 deletions
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 cf570a20..0b020567 100755 --- a/io_scene_gltf2/blender/imp/gltf2_blender_animation_node.py +++ b/io_scene_gltf2/blender/imp/gltf2_blender_animation_node.py @@ -18,7 +18,7 @@ from mathutils import Vector from ..com.gltf2_blender_conversion import loc_gltf_to_blender, quaternion_gltf_to_blender, scale_gltf_to_blender from ..com.gltf2_blender_conversion import correction_rotation from ...io.imp.gltf2_io_binary import BinaryData -from .gltf2_blender_animation_utils import simulate_stash, restore_last_action +from .gltf2_blender_animation_utils import simulate_stash class BlenderNodeAnim(): @@ -41,62 +41,31 @@ class BlenderNodeAnim(): kf.interpolation = 'LINEAR' @staticmethod - def stash_action(gltf, anim_idx, node_idx, action_name): - node = gltf.data.nodes[node_idx] - obj = bpy.data.objects[node.blender_object] - - if anim_idx not in node.animations.keys(): - return - - if (obj.name, action_name) in gltf.actions_stashed.keys(): - return - - start_frame = bpy.context.scene.frame_start - - animation_name = gltf.data.animations[anim_idx].name - simulate_stash(obj, animation_name, bpy.data.actions[action_name], start_frame) - - gltf.actions_stashed[(obj.name, action_name)] = True - - @staticmethod - def restore_last_action(gltf, node_idx): - node = gltf.data.nodes[node_idx] - obj = bpy.data.objects[node.blender_object] - - restore_last_action(obj) - - @staticmethod def anim(gltf, anim_idx, node_idx): """Manage animation.""" node = gltf.data.nodes[node_idx] obj = bpy.data.objects[node.blender_object] fps = bpy.context.scene.render.fps + animation = gltf.data.animations[anim_idx] + if anim_idx not in node.animations.keys(): return - animation = gltf.data.animations[anim_idx] - - if animation.name: - name = animation.name + "_" + obj.name + for channel_idx in node.animations[anim_idx]: + channel = animation.channels[channel_idx] + if channel.target.path in ['translation', 'rotation', 'scale']: + break else: - name = "Animation_" + str(anim_idx) + "_" + obj.name - if len(name) >= 63: - # Name is too long to be kept, we are going to keep only animation name for now - name = animation.name - if len(name) >= 63: - # Very long name! - name = "Animation_" + str(anim_idx) + return + + name = animation.track_name + "_" + obj.name action = bpy.data.actions.new(name) - # Check if this action has some users. - # If no user (only 1 indeed), that means that this action must be deleted - # (is an action from a deleted object) - if action.users == 1: - bpy.data.actions.remove(action) - action = bpy.data.actions.new(name) + gltf.needs_stash.append((obj, animation.track_name, action)) + if not obj.animation_data: obj.animation_data_create() - obj.animation_data.action = bpy.data.actions[action.name] + obj.animation_data.action = action for channel_idx in node.animations[anim_idx]: channel = animation.channels[channel_idx] @@ -104,92 +73,64 @@ class BlenderNodeAnim(): 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 in ['translation', 'rotation', 'scale']: - - # There is an animation on object - # We can't remove Yup2Zup object - gltf.animation_object = True - - 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 = [loc_gltf_to_blender(vals) for vals in values] - - elif channel.target.path == "rotation": - blender_path = "rotation_quaternion" - group_name = "Rotation" - num_components = 4 - if node.correction_needed is True: - values = [ - (quaternion_gltf_to_blender(vals).to_matrix().to_4x4() @ correction_rotation()).to_quaternion() - for vals in values - ] - else: - values = [quaternion_gltf_to_blender(vals) for vals in 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 = [scale_gltf_to_blender(vals) for vals in values] - - coords = [0] * (2 * len(keys)) - coords[::2] = (key[0] * fps for key in keys) - - if group_name not in action.groups: - action.groups.new(group_name) - group = action.groups[group_name] - - for i in range(0, num_components): - fcurve = action.fcurves.new(data_path=blender_path, index=i) - fcurve.group = group - - fcurve.keyframe_points.add(len(keys)) - coords[1::2] = (vals[i] for vals in values) - fcurve.keyframe_points.foreach_set('co', coords) - - # Setting interpolation - for kf in fcurve.keyframe_points: - BlenderNodeAnim.set_interpolation(animation.samplers[channel.sampler].interpolation, kf) - fcurve.update() # force updating tangents (this may change when tangent will be managed) - - elif channel.target.path == 'weights': - - # retrieve number of targets - nb_targets = 0 - for prim in gltf.data.meshes[gltf.data.nodes[node_idx].mesh].primitives: - if prim.targets: - if len(prim.targets) > nb_targets: - nb_targets = len(prim.targets) - - if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE": - factor = 3 - delta = nb_targets + if channel.target.path not in ['translation', 'rotation', 'scale']: + continue + + # There is an animation on object + # We can't remove Yup2Zup object + gltf.animation_object = True + + 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 = [loc_gltf_to_blender(vals) for vals in values] + + elif channel.target.path == "rotation": + blender_path = "rotation_quaternion" + group_name = "Rotation" + num_components = 4 + if node.correction_needed is True: + values = [ + (quaternion_gltf_to_blender(vals).to_matrix().to_4x4() @ correction_rotation()).to_quaternion() + for vals in values + ] else: - factor = 1 - delta = 0 - - for idx, key in enumerate(keys): - for sk in range(nb_targets): - if gltf.shapekeys[sk] is not None: # Do not animate shapekeys not created - obj.data.shape_keys.key_blocks[gltf.shapekeys[sk]].value = values[factor * idx * nb_targets + delta + sk][0] - obj.data.shape_keys.key_blocks[gltf.shapekeys[sk]].keyframe_insert( - "value", - frame=key[0] * fps, - group='ShapeKeys' - ) - - if action.name not in gltf.current_animation_names.keys(): - gltf.current_animation_names[name] = action.name + values = [quaternion_gltf_to_blender(vals) for vals in 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 = [scale_gltf_to_blender(vals) for vals in values] + + coords = [0] * (2 * len(keys)) + coords[::2] = (key[0] * fps for key in keys) + + if group_name not in action.groups: + action.groups.new(group_name) + group = action.groups[group_name] + + for i in range(0, num_components): + fcurve = action.fcurves.new(data_path=blender_path, index=i) + fcurve.group = group + + fcurve.keyframe_points.add(len(keys)) + coords[1::2] = (vals[i] for vals in values) + fcurve.keyframe_points.foreach_set('co', coords) + + # Setting interpolation + for kf in fcurve.keyframe_points: + BlenderNodeAnim.set_interpolation(animation.samplers[channel.sampler].interpolation, kf) + fcurve.update() # force updating tangents (this may change when tangent will be managed) |