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.