def __gather_animation_channel(channels: typing.Tuple[bpy.types.FCurve],
                               blender_object: bpy.types.Object,
                               export_settings,
                               bake_bone: typing.Union[str, None],
                               bake_channel: typing.Union[str, None],
                               bake_range_start,
                               bake_range_end,
                               action_name: str,
                               driver_obj
                               ) -> typing.Union[gltf2_io.AnimationChannel, None]:
    if not __filter_animation_channel(channels, blender_object, export_settings):
        return None

    animation_channel = gltf2_io.AnimationChannel(
        extensions=__gather_extensions(channels, blender_object, export_settings, bake_bone),
        extras=__gather_extras(channels, blender_object, export_settings, bake_bone),
        sampler=__gather_sampler(channels, blender_object, export_settings, bake_bone, bake_channel, bake_range_start, bake_range_end, action_name, driver_obj),
        target=__gather_target(channels, blender_object, export_settings, bake_bone, bake_channel, driver_obj)
    )

    export_user_extensions('gather_animation_channel_hook',
                           export_settings,
                           animation_channel,
                           channels,
                           blender_object,
                           bake_bone,
                           bake_channel,
                           bake_range_start,
                           bake_range_end,
                           action_name)

    return animation_channel
Ejemplo n.º 2
0
def __gather_animation_channel(channels: typing.Tuple[bpy.types.FCurve],
                               blender_object: bpy.types.Object,
                               export_settings
                               ) -> typing.Union[gltf2_io.AnimationChannel, None]:
    if not __filter_animation_channel(channels, blender_object, export_settings):
        return None

    return gltf2_io.AnimationChannel(
        extensions=__gather_extensions(channels, blender_object, export_settings),
        extras=__gather_extras(channels, blender_object, export_settings),
        sampler=__gather_sampler(channels, blender_object, export_settings),
        target=__gather_target(channels, blender_object, export_settings)
    )
def __gather_animation_channel(channels: typing.Tuple[bpy.types.FCurve],
                               blender_object: bpy.types.Object,
                               export_settings,
                               bake_bone: typing.Union[str, None],
                               bake_channel: typing.Union[str, None],
                               bake_range_start,
                               bake_range_end,
                               force_range: bool,
                               action_name: str,
                               driver_obj,
                               node_channel_is_animated: bool
                               ) -> typing.Union[gltf2_io.AnimationChannel, None]:
    if not __filter_animation_channel(channels, blender_object, export_settings):
        return None

    __target= __gather_target(channels, blender_object, export_settings, bake_bone, bake_channel, driver_obj)
    if __target.path is not None:
        sampler = __gather_sampler(channels, blender_object, export_settings, bake_bone, bake_channel, bake_range_start, bake_range_end, force_range, action_name, driver_obj, node_channel_is_animated)

        if sampler is None:
            # After check, no need to animate this node for this channel
            return None


        animation_channel = gltf2_io.AnimationChannel(
            extensions=__gather_extensions(channels, blender_object, export_settings, bake_bone),
            extras=__gather_extras(channels, blender_object, export_settings, bake_bone),
            sampler=sampler,
            target=__target
        )

        export_user_extensions('gather_animation_channel_hook',
                               export_settings,
                               animation_channel,
                               channels,
                               blender_object,
                               bake_bone,
                               bake_channel,
                               bake_range_start,
                               bake_range_end,
                               action_name)

        return animation_channel
    return None
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