PistonDevelopers/skeletal_animation

Name: skeletal_animation

Owner: PistonDevelopers

Description: A Rust library for skeletal animation

Created: 2015-03-01 23:11:11.0

Updated: 2018-05-04 07:54:01.0

Pushed: 2018-04-29 19:56:06.0

Homepage:

Size: 145

Language: Rust

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

skeletal_animation

Build Status

A Rust library for data-driven skeletal animation.

Documentation

Example Demo

Overview

This library allows you to define animation clips, state machines, and blend trees in JSON to be loaded and reloaded at runtime without needing to recompile your Rust project.

Usage
Asset Definition File

Animation assets, which currently include AnimationClips, DifferenceClips, and AnimationControllers are declared in defined in a JSON file with the following format:


"animation_clips": [],
"difference_clips": [],
"animation_controllers": []

At runtime, assets can be loaded from one or more definition files through the AssetManager as follows:

mut asset_manager = AssetManager::<QVTransform>::new(); // To use QVTransforms (Quaternions for rotations, Vector3s for translations)
mut asset_manager = AssetManager::<DualQuaternion<f32>>::new(); // To use DualQuaternions
t_manager.load_animations("assets/animation_assets.json");
t_manager.load_animations("assets/more_animation_assets.json");
Animation Clips

Animation clips are declared as follows:


"animation_clips": [{
    "name": "walk-forward",
    "source": "assets/walk.dae",
}, {
    "name": "run-forward",
    "source": "assets/run.dae",
}]

Difference Clips

Difference Clips are animation clips defined by the difference between two animation clips. They are intended to be used by additive blend nodes, where an additive clip (e.g. head turning to the left) is added to the output of another node (e.g. a walking animation).


"difference_clips": [{
    "name": "head-look-left-additive",
    "source_clip": "head-look-left",
    "reference_clip": "reference-pose"
}]

where:

Animation Controllers

Animation controllers are state machines, which consist of:

An example controller definition:


"animation_controllers": [{

    "name": "human-controller",
    "parameters": [
        "forward-speed",
        "forward-to-strafe",
        "walk-to-run",
        "left-to-right"
    ],

    "states": [ {
        "name": "walking-forward",
        "blend_tree": {
            "type": "LerpNode",
            "param": "forward-to-strafe",
            "inputs": [ {
                "type": "LerpNode",
                "param": "walk-to-run",
                "inputs": [{
                    "type": "ClipNode",
                    "clip_source": "walk-forward"
                }, {
                    "type": "ClipNode",
                    "clip_source": "run-forward"
                }]

            }, {
                "type": "LerpNode",
                "param": "left-to-right",
                "inputs": [{
                    "type": "ClipNode",
                    "clip_source": "walk-left",
                }, {
                    "type": "ClipNode",
                    "clip_source": "walk-right"
                }]
            }]
        },

        "transitions": [ {
            "target_state": "stand-idle",
            "duration": 0.5,
            "condition": {
                "parameter": "forward-speed",
                "operator": "<",
                "value": 0.1
            }
        }]

    }, {
        "name": "stand-idle",
        "blend_tree": {
            "type": "ClipNode",
            "clip_source": "stand-idle"
        },
        "transitions": [ {
            "target_state": "walking-forward",
            "duration": 0.5,
            "condition": {
                "parameter": "forward-speed",
                "operator": ">",
                "value": 0.1
            }
        } ]
    } ],

    "initial_state": "stand-idle"
}]

At runtime, after loading into the AssetManger, an AnimationController can be initialized as follows:

irst, need to load the shared skeleton object(eg from a COLLADA document)
his will become more elegant, i promise :)
skeleton = {
let collada_document = ColladaDocument::from_path(&Path::new("assets/suit_guy.dae")).unwrap();
let skeleton_set = collada_document.get_skeletons().unwrap();
Rc::new(Skeleton::from_collada(&skeleton_set[0]))


reate the AnimationController from the definition, the skeleton, and the clips previously loaded 
y the animation manager
controller_def = asset_manager.controller_defs["human-controller"].clone();
controller = AnimationController::new(controller_def, skeleton.clone(), &asset_manager.animation_clips);

Currently, skeletal_animation assumes a Piston-style event loop, where we have separate update (with delta-time) and render (with extrapolated delta-time since last update) events, so on each update in the game loop we need to:

et any relevant parameters on the controller:
roller.set_param_value("forward-speed", 1.8);

pdate the controller's local clock
roller.update(delta_time);

Then, on render, we can get the current skeletal pose represented with either matrices or dual-quaternions with:

atrices:
mut global_poses: [Matrix4<f32>; 64] = [ mat4_id(); 64 ];
roller.get_output_pose(args.ext_dt, &mut global_poses[0 .. skeleton.joints.len()]);

ualQuaternions:
mut global_poses: [DualQuaternion<f32>; 64] = [ dual_quaternion::id(); 64 ];
roller.get_output_pose(args.ext_dt, &mut global_poses[0 .. skeleton.joints.len()]);

where args.ext_dt is the extrapolated time since the last update. To actually render something with the skeletal pose, you can:

// To use matrices with a Linear Blend Skinning (LBS) shader let skinned_renderer = SkinnedRenderer::<_, _, Matrix4>::from_collada(

factory, // gfx::Factory instance, to be owned by SkinnedRenderer
collada_document, // the parsed Collada document for the rigged mesh
["assets/skin.png", "assets/hair.png", "assets/eyes.png"], // Textures for each submesh in the Collada source

).unwrap();

// To use dual-quaternions with a Dual-Quaternion Linear Blend Skinning (DLB) shader let skinned_renderer = SkinnedRenderer::<_, _, DualQuaternion>::from_collada(

factory, // gfx::Factory instance, to be owned by SkinnedRenderer
collada_document, // the parsed Collada document for the rigged mesh
["assets/skin.png", "assets/hair.png", "assets/eyes.png"], // Textures for each submesh in the Collada source

).unwrap();

// Later in event loop… skinned_renderer.render(

&mut stream, // gfx::Stream
camera_view, // Matrix4<f32>
camera_projection, // <Matrix4<f32>
&global_poses // The output poses from the controller

);

the [example demo](https://github.com/stjahns/skeletal_animation_demo) for a more thorough example of usage.

This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.