Skip to content

Instantly share code, notes, and snippets.

@williewillus
Last active June 13, 2017 08:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save williewillus/2f02eb0fe2849657623111706bedebb6 to your computer and use it in GitHub Desktop.
Save williewillus/2f02eb0fe2849657623111706bedebb6 to your computer and use it in GitHub Desktop.
animation api grokking
/*
- Properties.StaticProperty (PropertyBool)
- when true, show the static parts of the model (the non animated ones)
- when false, show the animated parts
- Properties.AnimationProperty (IUnlistedProperty<IModelState>)
- The model is animated by rebaking it using the value of this property
What is a joint?
- basically, part of a model that you'd like to treat as 1 single unit for animation purposes
What is a clip?
- in short, (joint -> (float -> model transform)). the float -> model transform is the important part
What is an ITimeValue
- function (float -> float)
- can be specified from json (where they are called parameters), or bound to code objects
- not necessarily time! though the very first input to the system is the world time, with partial ticks
*/
animation state machine json (IAnimationStateMachine):
{
"parameters": { "name": <time_value>, ... }, // specify any ITimeValue's to be used by clips. any unbound time values used in this json must be provided by code loading the ASM
"clips": { "<clip_name>": <clip>, ... },
"states": [ "<clip_name>", ... ],
"transitions": { "<clip_name>": "<clip_name>", ... },
"start_state": "<clip_name>"
}
<time_value> ::=
<number> // result = number; Constant value.
"#identity" // result = input; Value that returns its input.
"#name" // result = name(input); Reference to another value defined in "parameters" block.
[ "compose" <time_value> <time_value> ] // result = value1(value2(input)); Value composition.
[ regex("[+\\-*/mMrRfF]+"), <time_value>* ] // Simple arithmetic operation, see below.
// example: [ "+*-", <foo>, <bar>, <baz> ]: (((input + foo) * bar) - baz)
<clip> ::=
"#identity" // Identity clip, does nothing to the model.
"#name" // Reference to another clip defined in "clips" block.
"domain:model#variant@clip" // reference to a clip loaded by the model loader. Variant is optional.
[ "apply", <clip>, <time_value> ] // call clip, but instead of passing the input directly in, run it through time_value first. clip(time_value(input))
[ "slerp", <clip_from>, <clip_to>, <time_value_input>, <time_value_progress> ] // spherical linear blend between 2 clips; result = (1 - progress) * clip_from(input) + progress * clip_to(input).
// calls the clips foo and bar, but slerping the TRSRTransformation returned by the two using the ITimeValue tv_progress. Input is run through the ITimeValue tv_input before calling.
[ "trigger_positive", <clip>, <time_value>, "name" ] // clip that fires an additional event when specified time_value switches from negative to positive.
Simple arithmetic operation time value expects 1 time value for each character in the operand string,
and applies operands in order to the input value.
Arithmetic operations:
"+": output = input + arg;
"-": output = input - arg;
"*": output = input * arg;
"/": output = input / arg;
"m": output = min(input, arg);
"M": output = max(input, arg);
"r": output = floor(input / arg) * arg;
"R": output = ceil(input / arg) * arg;
"f": output = input - floor(input / arg) * arg; // <- this one's modulus!!
"F": output = ceil(input / arg) * arg - input;
how are clips defined on json models? (armature file):
{
// break this model down into joints
"joints": {
"<joint_name>": {
// key: index into elements array in model json
// value: floats? meaning unknown
"0": [ 1.0 ],
"1": [ 1.0 ],
...
}
},
// clips of this model overall. this is the outer layer of (joint -> (float -> model transform)) described in "what is a clip?" above
"clips": {
"<clip_name>": {
"loop": <bool>, // should the clip automatically restart from the beginning when it reaches the end (?)
// clips for individual joints within this model clip
"joint_clips": {
"<joint_name>": [
// each element in this array defines a (float -> model transform)
// the transforms are interpolated independently, then added together to form one TRSR to put in AnimationProperty
{
"variable": "offset_[xyz]"|"axis_[xyz]"|"angle"|"scale"|"scale_[xyz]", // the thing to transform. this maps to the respective part of TRSR
"type": "uniform", // only option at the moment
"interpolation": "linear"|"nearest", // interpolation style
"samples": [ <float>... ]
// array of samples. we will scale the input time to this clip to the array length then use it as an index
// this implies the input time should be a value between 0 and 1, set that up in your asm json appropriately
// if the scaled value is "in between" two of the samples then we interpolate between the two using the style above
// these samples are the direct input to "variable". as in offset_x with sample 0.5 means "offset this joint 0.5 east"
},
...
]
},
"events": {
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment