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.