Difference between revisions of "Internal Animation Format"
Tapple Gao (talk | contribs) m (Added links to the source code references) |
m (misc improvements) |
||
Line 17: | Line 17: | ||
* ''[https://bitbucket.org/lindenlab/viewer-release/src/8579cefad3049e139efaa1b40a94f0357fcd0274/indra/llcharacter/llbvhloader.cpp linden/indra/llcharacter/llkeyframemotion.cpp]''. | * ''[https://bitbucket.org/lindenlab/viewer-release/src/8579cefad3049e139efaa1b40a94f0357fcd0274/indra/llcharacter/llbvhloader.cpp linden/indra/llcharacter/llkeyframemotion.cpp]''. | ||
Note: binary file | Note: the binary file is little Endian. | ||
==Header== | ==Header== | ||
Line 28: | Line 28: | ||
{{LLSD Field Entry|name=base_priority|llsd=integer|cpp=S32}} | {{LLSD Field Entry|name=base_priority|llsd=integer|cpp=S32}} | ||
{{LLSD Field Entry|name=duration|llsd=real|cpp=F32}} | {{LLSD Field Entry|name=duration|llsd=real|cpp=F32}} | ||
{{LLSD Field Entry|name=emote_name|llsd=string|cpp= | {{LLSD Field Entry|name=emote_name|llsd=string|cpp=char *|note=NULL-terminated character sequence}} | ||
{{LLSD Field Entry|name=loop_in_point|llsd=real|cpp=F32}} | {{LLSD Field Entry|name=loop_in_point|llsd=real|cpp=F32}} | ||
{{LLSD Field Entry|name=loop_out_point|llsd=real|cpp=F32}} | {{LLSD Field Entry|name=loop_out_point|llsd=real|cpp=F32}} | ||
Line 34: | Line 34: | ||
{{LLSD Field Entry|name=ease_in_duration|llsd=real|cpp=F32}} | {{LLSD Field Entry|name=ease_in_duration|llsd=real|cpp=F32}} | ||
{{LLSD Field Entry|name=ease_out_duration|llsd=real|cpp=F32}} | {{LLSD Field Entry|name=ease_out_duration|llsd=real|cpp=F32}} | ||
{{LLSD Field Entry|name=hand_pose|llsd=integer|cpp=U32}} | {{LLSD Field Entry|name=hand_pose|llsd=integer|cpp=U32|note=Enum defined in [https://bitbucket.org/lindenlab/viewer-release/src/536fef12ab37/indra/llcharacter/llhandmotion.h?at=default#llhandmotion.h-45]}} | ||
{{LLSD Field Entry|name=num_joints|llsd=integer|cpp=U32}} | {{LLSD Field Entry|name=num_joints|llsd=integer|cpp=U32}} | ||
|} | |} | ||
Line 44: | Line 44: | ||
{|{{LLSD Field Table}} | {|{{LLSD Field Table}} | ||
{{LLSD Field Entry|name=joint_name|llsd=string|cpp= | {{LLSD Field Entry|name=joint_name|llsd=string|cpp=char *|note=NULL-terminated character sequence}} | ||
{{LLSD Field Entry|name=joint_priority|llsd=integer|cpp=S32}} | {{LLSD Field Entry|name=joint_priority|llsd=integer|cpp=S32}} | ||
|} | |} | ||
Line 63: | Line 63: | ||
{|{{LLSD Field Table}} | {|{{LLSD Field Table}} | ||
{{LLSD Field Entry|name=time|llsd=integer|cpp=U16|note=0: first frame, 65535: last frame}} | {{LLSD Field Entry|name=time|llsd=integer|cpp=U16|note=0: first frame, 65535: last frame}} | ||
{{LLSD Field Entry|name= | {{LLSD Field Entry|name=rot_x|llsd=integer|cpp=U16|note= 0:-1, 32767:0, 65535:+1 }} | ||
{{LLSD Field Entry|name= | {{LLSD Field Entry|name=rot_y|llsd=integer|cpp=U16}} | ||
{{LLSD Field Entry|name= | {{LLSD Field Entry|name=rot_z|llsd=integer|cpp=U16}} | ||
|} | |} | ||
Line 84: | Line 84: | ||
{|{{LLSD Field Table}} | {|{{LLSD Field Table}} | ||
{{LLSD Field Entry|name=time|llsd=integer|cpp=U16|note=0: first frame, 65535: last frame}} | {{LLSD Field Entry|name=time|llsd=integer|cpp=U16|note=0: first frame, 65535: last frame}} | ||
{{LLSD Field Entry|name=pos_x|llsd=integer|cpp=U16|note=0: - | {{LLSD Field Entry|name=pos_x|llsd=integer|cpp=U16|desc=position measured from avatar root, not joint offset|note=0:-5m, 32767:0m, 65535:+5m (m for metres)}} | ||
{{LLSD Field Entry|name=pos_y|llsd=integer|cpp=U16 | {{LLSD Field Entry|name=pos_y|llsd=integer|cpp=U16}} | ||
{{LLSD Field Entry|name=pos_z|llsd=integer|cpp=U16}} | {{LLSD Field Entry|name=pos_z|llsd=integer|cpp=U16}} | ||
|} | |} | ||
Line 91: | Line 91: | ||
==Constraints== | ==Constraints== | ||
After the joint data are a number of entries for joint constraints. Constraints can target an avatar's parts in relation to each other or the ground. | After the joint data are a number of entries for joint constraints. Constraints can target an avatar's parts in relation to each other or the ground (IK). | ||
{|{{LLSD Field Table}} | {|{{LLSD Field Table}} | ||
Line 102: | Line 102: | ||
{{LLSD Field Entry|name=chain_length|llsd=integer|cpp=U8|note=number of attached joints to include}} | {{LLSD Field Entry|name=chain_length|llsd=integer|cpp=U8|note=number of attached joints to include}} | ||
{{LLSD Field Entry|name=constraint_type|llsd=integer|cpp=U8|note=0: point, 1: plane}} | {{LLSD Field Entry|name=constraint_type|llsd=integer|cpp=U8|note=0: point, 1: plane}} | ||
{{LLSD Field Entry|name=source_volume|llsd=string |cpp= | {{LLSD Field Entry|name=source_volume|llsd=string |cpp=char[16]|desc=skeleton collision volume name|note=Always 16 bytes, but if shorter, it's interpreted as NULL-terminated and the remaining bytes ignored.}} | ||
{{LLSD Field Entry|name=source_offset|llsd=string (?)|cpp=LLVector3}} | {{LLSD Field Entry|name=source_offset|llsd=string (?)|cpp=LLVector3}} | ||
{{LLSD Field Entry|name=target_volume|llsd=string|cpp= | {{LLSD Field Entry|name=target_volume|llsd=string|cpp=char[16]|desc=skeleton collision volume name|note=Always 16 bytes, but if shorter, it's interpreted as NULL-terminated and the remaining bytes ignored.}} | ||
{{LLSD Field Entry|name=target_offset|llsd=string (?)|cpp=LLVector3}} | {{LLSD Field Entry|name=target_offset|llsd=string (?)|cpp=LLVector3}} | ||
{{LLSD Field Entry|name=target_dir|llsd=string (?)|cpp=LLVector3|note=value is currently ignored}} | {{LLSD Field Entry|name=target_dir|llsd=string (?)|cpp=LLVector3|note=value is currently ignored}} |
Revision as of 06:56, 13 August 2018
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:
Note: the binary file is little Endian.
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 | integer | U16 | ||
sub_version | integer | U16 | ||
base_priority | integer | S32 | ||
duration | real | F32 | ||
emote_name | string | char * | NULL-terminated character sequence | |
loop_in_point | real | F32 | ||
loop_out_point | real | F32 | ||
loop | integer | S32 | 0: not looped, 1: looped | |
ease_in_duration | real | F32 | ||
ease_out_duration | real | F32 | ||
hand_pose | integer | U32 | Enum defined in [1] | |
num_joints | integer | U32 |
Joint Data
After the header is data for each joint in the skeleton: Note: Unused bones need not be included in the file.
field name | description | LLSD type | C++ type | Note |
---|---|---|---|---|
joint_name | string | char * | NULL-terminated character sequence | |
joint_priority | integer | S32 |
Joint Rotation Keys
At the start of the rotation data for each bone is the total number of rotation keys: If the bone has no rotation based keyframes, this value must be 0.
field name | description | LLSD type | C++ type | Note |
---|---|---|---|---|
num_rot_keys | integer | S32 |
Then, for each rotation key:
Note: These three values X Y Z appear to be the first three values of a truncated quaternion with the W term being calculated afterwards. Since a quaternion is X2 + Y2 + Z2 + W2 = 1 as long as you assume the W term has a consistent sign the X Y Z terms will be accurate.
field name | description | LLSD type | C++ type | Note |
---|---|---|---|---|
time | integer | U16 | 0: first frame, 65535: last frame | |
rot_x | integer | U16 | 0:-1, 32767:0, 65535:+1 | |
rot_y | integer | U16 | ||
rot_z | integer | U16 |
Joint Position Keys
At the start of the position data is the total number of position keys: If the bone has no position based animations, this value must be 0.
field name | description | LLSD type | C++ type | Note |
---|---|---|---|---|
num_pos_keys | integer | S32 |
Then, for each position key, position data is measured from Avatar Center ( mPelvis ), not joint resting position
( IE [0,0,0] is not joint resting position, it'll be the bone's position in parent coordinate space)
with the exception of the mPelvis bone which is stored in world space coordinates.:
field name | description | LLSD type | C++ type | Note |
---|---|---|---|---|
time | integer | U16 | 0: first frame, 65535: last frame | |
pos_x | position measured from avatar root, not joint offset | integer | U16 | 0:-5m, 32767:0m, 65535:+5m (m for metres) |
pos_y | integer | U16 | ||
pos_z | integer | U16 |
Constraints
After the joint data are a number of entries for joint constraints. Constraints can target an avatar's parts in relation to each other or the ground (IK).
field name | description | LLSD type | C++ type | Note |
---|---|---|---|---|
num_constraints | integer | S32 |
Then, for each joint constraint:
field name | description | LLSD type | C++ type | Note |
---|---|---|---|---|
chain_length | integer | U8 | number of attached joints to include | |
constraint_type | integer | U8 | 0: point, 1: plane | |
source_volume | skeleton collision volume name | string | char[16] | Always 16 bytes, but if shorter, it's interpreted as NULL-terminated and the remaining bytes ignored. |
source_offset | string (?) | LLVector3 | ||
target_volume | skeleton collision volume name | string | char[16] | Always 16 bytes, but if shorter, it's interpreted as NULL-terminated and the remaining bytes ignored. |
target_offset | string (?) | LLVector3 | ||
target_dir | string (?) | LLVector3 | value is currently ignored | |
ease_in_start | real | F32 | ||
ease_in_stop | real | F32 | ||
ease_out_start | real | F32 | ||
ease_out_stop | real | F32 |