def gather_animation_channel_target(
        action_group: bpy.types.ActionGroup, blender_object: bpy.types.Object,
        export_settings) -> gltf2_io.AnimationChannelTarget:
    return gltf2_io.AnimationChannelTarget(
        extensions=__gather_extensions(action_group, blender_object,
                                       export_settings),
        extras=__gather_extras(action_group, blender_object, export_settings),
        node=__gather_node(action_group, blender_object, export_settings),
        path=__gather_path(action_group, blender_object, export_settings))
def gather_animation_channel_target(channels: typing.Tuple[bpy.types.FCurve],
                                    blender_object: bpy.types.Object,
                                    export_settings
                                    ) -> gltf2_io.AnimationChannelTarget:
    return gltf2_io.AnimationChannelTarget(
        extensions=__gather_extensions(channels, blender_object, export_settings),
        extras=__gather_extras(channels, blender_object, export_settings),
        node=__gather_node(channels, blender_object, export_settings),
        path=__gather_path(channels, blender_object, export_settings)
    )
def gather_animation_channel_target(
        channels: typing.Tuple[bpy.types.FCurve],
        blender_object: bpy.types.Object, bake_bone: typing.Union[str, None],
        bake_channel: typing.Union[str, None], driver_obj,
        export_settings) -> gltf2_io.AnimationChannelTarget:

    animation_channel_target = gltf2_io.AnimationChannelTarget(
        extensions=__gather_extensions(channels, blender_object,
                                       export_settings, bake_bone),
        extras=__gather_extras(channels, blender_object, export_settings,
                               bake_bone),
        node=__gather_node(channels, blender_object, export_settings,
                           bake_bone, driver_obj),
        path=__gather_path(channels, blender_object, export_settings,
                           bake_bone, bake_channel))

    export_user_extensions('gather_animation_channel_target_hook',
                           export_settings, animation_channel_target, channels,
                           blender_object, bake_bone, bake_channel)

    return animation_channel_target
def __gather_animation(pre_anim, nodes, export_settings):
    anim_name, (frame_start, frame_end) = pre_anim
    print(f'exporting animation track {anim_name}')

    # Star all the tracks named anim_name. Objects without an anim_name
    # track are considered unanimated. Star the empty temp track for those.
    anim_nodes = []
    for node in nodes:
        if node.__blender_data[0] != 'OBJECT' and node.__blender_data[
                0] != 'BONE':
            continue
        ob = node.__blender_data[1]
        if not ob.animation_data:
            continue
        for track in ob.animation_data.nla_tracks:
            if track.name == anim_name:
                track.is_solo = True
                if ob.type == 'ARMATURE' and node.__blender_data[0] == 'BONE':
                    # only append bones that are animated in current anim
                    actions = __get_blender_actions(ob)
                    for action in actions:
                        if action[1] == anim_name:
                            for fcurve in action[0].fcurves:
                                bone_path = fcurve.data_path.rpartition('.')[0]
                                bone = ob.path_resolve(bone_path)
                                if node.name == bone.name:
                                    if node not in anim_nodes:
                                        anim_nodes.append(node)
                else:
                    anim_nodes.append(node)
                break
        else:
            if node.__blender_data[0] == 'OBJECT':
                node.__temp_nla_track.is_solo = True

    f_start = math.floor(frame_start)
    f_end = math.ceil(frame_end) + 1
    f_step = export_settings['gltf_frame_step']

    # Stores TRS values for each node at each frame
    data = {}
    data['translation'] = [[] for _node in nodes]
    data['rotation'] = [[] for _node in nodes]
    data['scale'] = [[] for _node in nodes]

    for f in range(f_start, f_end, f_step):
        bpy.context.scene.frame_set(f)
        for i, node in enumerate(anim_nodes):
            if node.__blender_data[0] == 'OBJECT':
                t, r, s = __get_gltf_trs_from_object(node.__blender_data[1],
                                                     export_settings)
            elif node.__blender_data[0] == 'BONE':
                arma_ob = node.__blender_data[1]
                pbone = arma_ob.pose.bones[node.__blender_data[2]]
                t, r, s = __get_gltf_trs_from_bone(pbone, export_settings)
            else:
                assert False
            data['translation'][i].append(t)
            data['rotation'][i].append(r)
            data['scale'][i].append(s)

    # Put it all together to get the glTF animation

    channels = []
    samplers = []

    for i, node in enumerate(anim_nodes):
        # Get paths used in the NLA track
        actions = __get_blender_actions(node.__blender_data[1])
        paths = []

        pathTypes = {
            'delta_location': 'translation',
            'delta_rotation_euler': 'rotation',
            'location': 'translation',
            'rotation_axis_angle': 'rotation',
            'rotation_euler': 'rotation',
            'rotation_quaternion': 'rotation',
            'scale': 'scale'
        }

        for action in actions:
            if action[1] == anim_name:
                for fcurve in action[0].fcurves:
                    data_path = fcurve.data_path
                    if node.__blender_data[0] == 'OBJECT':
                        paths.append(pathTypes.get(data_path))
                    else:  # for armatures
                        paths.append(
                            pathTypes.get(data_path.rpartition('.')[2]))

        for path in ['translation', 'rotation', 'scale']:
            if path in paths:
                sampler = gltf2_io.AnimationSampler(
                    input=__get_keyframe_accessor(f_start, f_end, f_step),
                    output=__encode_output_accessor(data[path][i], path),
                    interpolation='LINEAR',
                    extensions=None,
                    extras=None,
                )
                samplers.append(sampler)
                channel = gltf2_io.AnimationChannel(
                    sampler=len(samplers) - 1,
                    target=gltf2_io.AnimationChannelTarget(
                        node=node,
                        path=path,
                        extensions=None,
                        extras=None,
                    ),
                    extensions=None,
                    extras=None,
                )
                channels.append(channel)

    animation = gltf2_io.Animation(
        name=anim_name,
        channels=channels,
        samplers=samplers,
        extensions=None,
        extras=None,
    )

    return animation