Internal Animation Format
Overview
From a programming perspective, there are several steps to uploading an animation from a BVH (BioVision Hierarchy) file:
- Read and parse the BVH file, creating an LLKeyframeMotion object containing the motion data.
- Gather input from the user (via the upload preview floater) for things like animation priority, facial expression, and looping; these settings are stored in the LLKeyframeMotion object.
- Serialize the LLKeyframeMotion object as LLSD.
- Upload the serialized data to the asset server.
Before other viewers can play an animation, they must:
- Download the serialized data from the asset server.
- Deserialize it to an LLKeyframeMotion object.
Relevant source files:
- linden/indra/llcharacter/llbvhloader.cpp
- linden/indra/llcharacter/llkeyframemotion.cpp.
Header
The first part of the animation data is a header describing various details about the animation as a whole. The elements, in order, are:
| field name | description | LLSD type | C++ type | Note |
|---|---|---|---|---|
| version | ||||
| sub_version | ||||
| base_priority | ||||
| duration | ||||
| emote_name | ||||
| loop_in_point | ||||
| loop_out_point | ||||
| loop | ||||
| ease_in_duration | ||||
| ease_out_duration | ||||
| hand_pose | ||||
| num_joints |
Joint Data
After the header is data for each joint in the skeleton:
| field name | description | LLSD type | C++ type | Note |
|---|---|---|---|---|
| joint_name | ||||
| joint_priority |
Joint Rotation Keys
At the start of the rotation data is the total number of rotation keys:
| field name | description | LLSD type | C++ type | Note |
|---|---|---|---|---|
| num_rot_keys |
Then, for each rotation key:
| field name | description | LLSD type | C++ type | Note |
|---|---|---|---|---|
| time | ||||
| rot_angle_x | ||||
| rot_angle_y | ||||
| rot_angle_z |
Joint Position Keys
At the start of the position data is the total number of position keys:
| field name | description | LLSD type | C++ type | Note |
|---|---|---|---|---|
| num_pos_keys |
Then, for each position key:
| field name | description | LLSD type | C++ type | Note |
|---|---|---|---|---|
| time | ||||
| pos_x | ||||
| pos_y | ||||
| pos_z |
Constraints
After the joint data are a number of entries for joint constraints (whatever that means):
| field name | description | LLSD type | C++ type | Note |
|---|---|---|---|---|
| num_pos_keys |
Then, for each joint constraint:
| field name | description | LLSD type | C++ type | Note |
|---|---|---|---|---|
| chain_length | ||||
| constraint_type | ||||
| source_volume | ||||
| source_offset | ||||
| target_volume | ||||
| target_offset | ||||
| target_dir | ||||
| ease_in_start | ||||
| ease_in_stop | ||||
| ease_out_start | ||||
| ease_out_stop |