Atoms Character file format
"version": IntMetadata(1)
"root": StringMetadata
"jointRotation": MapMetadata,
"root": QuaternionMetadata,
"spine1": QuaternionMetadata,
"spine2": QuaternionMetadata,
...
"jointWorldMatrix": MapMetadata,
"root": MatrixMetadata,
"spine1": MatrixMetadata,
"spine2": MatrixMetadata,
...,
"chains": ArrayMetadata,
0: MapMetadata,
"name": StringMetadata
Must use a strict naming convention; {type}{sub_type}{horizontal}{vertical}{depth}{index:02}
For the horizontal/vertial/depth use only the first character converted to upper case like: L for left, C for Center and so on...
Example: spineCTC00, limbmiddleLCC01, limbmiddleLCC02
,
"fullName": StringMetadata
It must follow the naming convetion fullName = name + (len(index) == 1 ? "0" : "")
,
"type": StringMetadata (valid values are "root", "spine", "clavicle", "pelvis", "limb", "effector"),
"sub_type": StringMetadata
( valid values for type limb:
"arm", "leg", "foot", "neck", "head", "tail"
valid values for type effector:
"thumb", "index", "middle", "ring", "pinky", "jaw", "eye", "ear", "nose"
for other types use ""
)
,
"horizontal": StringMetadata (valid values are "left", "center", "center"),
"vertical": StringMetadata (valid values are "top", "center", "bottom"),
"depth": StringMetadata (valid values are "front", "center", "back"),
"index": UIntMetadata,
"jointList": StringArrayMetadata,
"jointFullNameList": StringArrayMetadata,
"isRoot": BoolMetadata,
"isSpine": BoolMetadata,
"isLimb": BoolMetadata,
"isEffector": BoolMetadata,
"isCenter": BoolMetadata,
1: ...
This is an example of code used in atoms unreal to generate the character file:
void addRetargetJointsChain(
AtomsPtr<AtomsCore::ArrayMetadata>& chains,
const std::string& depth,
const std::string& fullName,
const std::string& horizontal,
unsigned int index,
bool isCenter,
bool isEffector,
bool isLimb,
bool isRoot,
bool isSpine,
const std::vector<std::string>& jointList,
const std::string& name,
const std::string& sub_type,
const std::string& type,
const std::string& vertical)
{
AtomsPtr<AtomsCore::MapMetadata> chain(new AtomsCore::MapMetadata);
AtomsCore::StringMetadata depthM(depth); chain->addEntry("depth", &depthM);
AtomsCore::StringMetadata fullNameM(fullName); chain->addEntry("fullName", &fullNameM);
AtomsCore::StringMetadata horizontalM(horizontal); chain->addEntry("horizontal", &horizontalM);
AtomsCore::StringArrayMetadata jointListM(jointList); chain->addEntry("jointList", &jointListM);
AtomsCore::StringMetadata nameM(name); chain->addEntry("name", &nameM);
AtomsCore::StringMetadata sub_typeM(sub_type); chain->addEntry("sub_type", &sub_typeM);
AtomsCore::StringMetadata typeM(type); chain->addEntry("type", &typeM);
AtomsCore::StringMetadata verticalM(vertical); chain->addEntry("vertical", &verticalM);
AtomsCore::UIntMetadata indexM(index); chain->addEntry("index", &indexM);
AtomsCore::BoolMetadata isCenterM(isCenter); chain->addEntry("isCenter", &isCenterM);
AtomsCore::BoolMetadata isEffectorM(isEffector); chain->addEntry("isEffector", &isEffectorM);
AtomsCore::BoolMetadata isLimbM(isLimb); chain->addEntry("isLimb", &isLimbM);
AtomsCore::BoolMetadata isRootM(isRoot); chain->addEntry("isRoot", &isRootM);
AtomsCore::BoolMetadata isSpineM(isSpine); chain->addEntry("isSpine", &isSpineM);
chains->push_back(chain);
}
AtomsPtr<AtomsCore::MapMetadata> buildAtomsSkeletonRetargetData(USkeleton* Skeleton, USkeletalMesh* previewMesh, UAtomsCharacterAsset* CharacterAsset)
{
AtomsPtr<AtomsCore::MapMetadata> characterization(new AtomsCore::MapMetadata);
AtomsCore::IntMetadata version(1);
characterization->addEntry("version", &version);
if (CharacterAsset)
{
AtomsCore::StringMetadata rootName(TCHAR_TO_UTF8(*CharacterAsset->RootBone));
characterization->addEntry("root", &rootName);
AtomsPtr<AtomsCore::ArrayMetadata> chains(new AtomsCore::ArrayMetadata);
characterization->insertEntry("chains", chains);
for (int32 i = 0; i < CharacterAsset->Chains.Num(); ++i)
{
auto& UnrealChain = CharacterAsset->Chains[i];
AtomsPtr<AtomsCore::MapMetadata> chain(new AtomsCore::MapMetadata);
AtomsCore::StringMetadata typeM("none");
switch (UnrealChain.Type)
{
case EAtomsCharacterType::Clavicle:
{
typeM.set("clavicle");
break;
}
case EAtomsCharacterType::Effector:
{
typeM.set("effector");
break;
}
case EAtomsCharacterType::Limb:
{
typeM.set("limb");
break;
}
case EAtomsCharacterType::Pelvis:
{
typeM.set("pelvis");
break;
}
case EAtomsCharacterType::Root:
{
typeM.set("root");
break;
}
case EAtomsCharacterType::Spine:
{
typeM.set("spine");
break;
}
default:
break;
}
chain->addEntry("type", &typeM);
AtomsCore::StringMetadata sub_typeM("none");
if (UnrealChain.Type == EAtomsCharacterType::Limb)
{
switch (UnrealChain.LimbType)
{
case EAtomsCharacterLimbType::Arm:
{
sub_typeM.set("arm");
break;
}
case EAtomsCharacterLimbType::Foot:
{
sub_typeM.set("foot");
break;
}
case EAtomsCharacterLimbType::Head:
{
sub_typeM.set("head");
break;
}
case EAtomsCharacterLimbType::Leg:
{
sub_typeM.set("leg");
break;
}
case EAtomsCharacterLimbType::Neck:
{
sub_typeM.set("neck");
break;
}
case EAtomsCharacterLimbType::Tail:
{
sub_typeM.set("tail");
break;
}
default:
sub_typeM.set("none");
break;
}
}
else if (UnrealChain.Type == EAtomsCharacterType::Effector)
{
switch (UnrealChain.EffectorType)
{
case EAtomsCharacterEffectorType::Index:
{
sub_typeM.set("index");
break;
}
case EAtomsCharacterEffectorType::Middle:
{
sub_typeM.set("middle");
break;
}
case EAtomsCharacterEffectorType::Pinky:
{
sub_typeM.set("pinky");
break;
}
case EAtomsCharacterEffectorType::Ring:
{
sub_typeM.set("ring");
break;
}
case EAtomsCharacterEffectorType::Thumb:
{
sub_typeM.set("thumb");
break;
}
default:
sub_typeM.set("none");
break;
}
}
chain->addEntry("sub_type", &sub_typeM);
bool isCenter = false;
AtomsCore::StringMetadata horizontalM("center");
switch (UnrealChain.Horizontal)
{
case EAtomsCharacterHorizontal::Center:
{
horizontalM.set("center");
isCenter = true;
break;
}
case EAtomsCharacterHorizontal::Left:
{
horizontalM.set("left");
break;
}
case EAtomsCharacterHorizontal::Right:
{
horizontalM.set("right");
break;
}
default:
break;
}
chain->addEntry("horizontal", &horizontalM);
AtomsCore::StringMetadata verticalM("center");
switch (UnrealChain.Vertical)
{
case EAtomsCharacterVertical::Center:
{
verticalM.set("center");
break;
}
case EAtomsCharacterVertical::Bottom:
{
verticalM.set("bottom");
break;
}
case EAtomsCharacterVertical::Top:
{
verticalM.set("top");
break;
}
default:
break;
}
chain->addEntry("vertical", &verticalM);
AtomsCore::StringMetadata depthM("center");
switch (UnrealChain.Depth)
{
case EAtomsCharacterDepth::Center:
{
depthM.set("center");
break;
}
case EAtomsCharacterDepth::Back:
{
depthM.set("back");
break;
}
case EAtomsCharacterDepth::Front:
{
depthM.set("front");
break;
}
default:
break;
}
chain->addEntry("depth", &depthM);
AtomsCore::UIntMetadata indexM(UnrealChain.Index);
chain->addEntry("index", &indexM);
AtomsCore::BoolMetadata isCenterM(isCenter);
chain->addEntry("isCenter", &isCenterM);
AtomsCore::BoolMetadata isEffectorM(UnrealChain.Type == EAtomsCharacterType::Effector);
chain->addEntry("isEffector", &isEffectorM);
AtomsCore::BoolMetadata isLimbM(UnrealChain.Type == EAtomsCharacterType::Limb);
chain->addEntry("isLimb", &isLimbM);
AtomsCore::BoolMetadata isRootM(UnrealChain.Type == EAtomsCharacterType::Root);
chain->addEntry("isRoot", &isRootM);
AtomsCore::BoolMetadata isSpineM(UnrealChain.Type == EAtomsCharacterType::Spine);
chain->addEntry("isSpine", &isSpineM);
AtomsCore::StringArrayMetadata jointListM;
for (auto& BoneName : UnrealChain.Bones)
{
jointListM.get().push_back(TCHAR_TO_UTF8(*BoneName));
}
chain->addEntry("jointList", &jointListM);
/*
name = "{type}{sub_type}{x}{y}{z}{index:02}".format(
type = data[CH_KEYS.CHAIN_TYPE],
sub_type = data[CH_KEYS.CHAIN_SUB_TYPE] if data[CH_KEYS.CHAIN_SUB_TYPE] != "none" else "",
x = CH_KEYS.CHAIN_POS_CODES[data[CH_KEYS.CHAIN_HORIZONTAL]],
y = CH_KEYS.CHAIN_POS_CODES[data[CH_KEYS.CHAIN_VERTICAL]],
z = CH_KEYS.CHAIN_POS_CODES[data[CH_KEYS.CHAIN_DEPTH]],
index = data[CH_KEYS.CHAIN_INDEX],
)
*/
std::string fullName = typeM.get();
if (sub_typeM.get() != "none")
fullName += sub_typeM.get();
std::map<std::string, std::string> CHAIN_POS_CODES;
CHAIN_POS_CODES.emplace("center", "C");
CHAIN_POS_CODES.emplace("left", "L");
CHAIN_POS_CODES.emplace("right", "R");
CHAIN_POS_CODES.emplace("top", "T");
CHAIN_POS_CODES.emplace("bottom", "B");
CHAIN_POS_CODES.emplace("front", "F");
CHAIN_POS_CODES.emplace("back", "B");
fullName += CHAIN_POS_CODES[horizontalM.get()];
fullName += CHAIN_POS_CODES[verticalM.get()];
fullName += CHAIN_POS_CODES[depthM.get()];
AtomsCore::StringMetadata nameM(fullName);
chain->addEntry("name", &nameM);
auto indexStr = std::to_string(indexM.value());
if (indexStr.length() == 1)
fullName += "0";
fullName += indexStr;
AtomsCore::StringMetadata fullNameM(fullName);
chain->addEntry("fullName", &fullNameM);
chains->push_back(chain);
}
}
}
Copyright © 2017, Toolchefs LTD.