Atoms Cacheの読み込み/書き込み

Atomsは、Agent Cacheのための独自の内部フォーマットを保有しています。どのファイルが作成されているかについての詳細を確認する場合は、Referenceをチェックしてください。


Cache Header

Cache Headerは、次のキーと値のペアを含むMapMetadataです。

  • agentIds:すべてのエージェントを含むIntArrayMetadata ID
  • cacheType:内部使用のみを目的としたStringMetadata。Value"dynamic"を格納する必要があります。
  • endFrame:終了フレームを含むIntMetadata
  • startFrame:開始フレームを含むIntMetadata

このファイルは、次の名前拡張子を持つ必要があります。

atoms(すなわちtest_cache.atoms)


Agent Types

キャッシュの移植性を高めるために、すべてのAgent TypeファイルはCacheファイルの横にある "agentTypes"サブフォルダに保存されています。
エージェントタイプは、バイナリ形式でシリアル化されています。

Atoms::AgentTypePtr agentType = agent->agentType();
AtomsCore::Archive agentTypeArchive(agentType->memSize());
agentType->serialize(agentTypeArchive);
agentTypeArchive->writeToFile("myAgentType.agentType")

 

エージェントタイプをAtoms UI内で表示可能にするために、Event Simulationのpythonラッパースクリプトが同じフォルダーにエクスポートされます。

std::string cachePath = "/atomsDemo/cache/";
std::string agentType = agent->agentType().name();

Atoms::AgentTypePtr agentTypePtr = agent->agentType();
AtomsCore::Archive agentTypeArchive(agentTypePtr->memSize());
agentTypePtr->serialize(agentTypeArchive);
agentTypeArchive->writeToFile(cachePath + "/agentTypes/"  + agentType + ".agentType")


//store the python event wrapper
	const std::string pythonEvent =	
	"import AtomsCore\n"
	"import Atoms\n"
	"import imath\n"
	"\n"
	"class "+ agentType +"Cached(Atoms.SimulationEvent):\n"
	"\tagentTypeFile = r'" + agentTypePath + "'\n"
	"\teventName = '" + agentType + "Cached'\n"
	"\tagentTypeName = '+ agentType + '\n"
	"\tgeoPath = ''\n"
	"\tskinPath = ''\n"
	"\tstateMachine = ''\n"
	"\n"
	"\tdef __init__(self):\n"
	"\t\tAtoms.SimulationEvent.__init__(self)\n"
	"\t\tself.setName(self.eventName)\n"
	"\n"
	"\tdef load(self):\n"
	"\t\taType = Atoms.AgentType()\n"
	"\t\taTypeArchive = AtomsCore.Archive()\n"
	"\t\tif aTypeArchive.readFromFile(self.agentTypeFile):\n"
	"\t\t\taType.deserialise(aTypeArchive)\n"
	"\t\telse:\n"
	"\t\t\treturn\n"
	"\n"
	"\t\tif self.geoPath:\n"
	"\t\t\tmeshMap = AtomsCore.MapMetadata()\n"
	"\t\t\ttypeArchive = AtomsCore.Archive()\n"
	"\t\t\tif typeArchive.readFromFile(self.geoPath):\n"
	"\t\t\t\tmeshMap.deserialise(typeArchive)\n"
	"\t\t\t\taType.metadata()["lowGeo"] = meshMap\n"
	"\n"
	"\t\tif self.skinPath:\n"
	"\t\t\tskinMap = AtomsCore.MapMetadata()\n"
	"\t\t\tskinArchive = AtomsCore.Archive()\n"
	"\t\t\tif skinArchive.readFromFile(self.skinPath):\n"
	"\t\t\t\tskinMap.deserialise(skinArchive)\n"
	"\t\t\t\taType.metadata()["skinGeo"] = skinMap\n"
	"\n"
	"\t\taType.metadata()["stateMachine"] = AtomsCore.StringMetadata(self.stateMachine)\n"
	"\n"
	"\t\tAtoms.AgentTypes.instance().addAgentType(self.agentTypeName, aType)\n";

	std::string agentTypeWrapperPath = cachePath  + "/agenTypes/" + agentType + ".py";
	std::ofstream out(agentTypeWrapperPath);
    out << pythonEvent;
    out.close();
CACHED_AGENT_TYPE_SCRIPT = '''
import AtomsCore
import Atoms

class AgentTypeEvent$(Atoms.SimulationEvent):
\tagentTypeFile = r'agentTypeFile$'
\teventName = 'agentType$'
\tagentTypeName = 'agentTypeName$'
\tgeoPath = ''
\tskinPath = ''
\tstateMachine = ''

\tdef __init__(self):
\t\tAtoms.SimulationEvent.__init__(self)
\t\tself.setName(self.eventName)

\tdef load(self):
\t\taType = Atoms.AgentType()
\t\taTypeArchive = AtomsCore.Archive()
\t\tif aTypeArchive.readFromFile(self.agentTypeFile):
\t\t\taType.deserialise(aTypeArchive)
\t\telse:
\t\t\treturn

\t\tif self.geoPath:
\t\t\tmeshMap = AtomsCore.MapMetadata()
\t\t\ttypeArchive = AtomsCore.Archive()
\t\t\tif typeArchive.readFromFile(self.geoPath):
\t\t\t\tmeshMap.deserialise(typeArchive)
\t\t\t\taType.metadata()["lowGeo"] = meshMap

\t\tif self.skinPath:
\t\t\tskinMap = AtomsCore.MapMetadata()
\t\t\tskinArchive = AtomsCore.Archive()
\t\t\tif skinArchive.readFromFile(self.skinPath):
\t\t\t\tskinMap.deserialise(skinArchive)
\t\t\t\taType.metadata()["skinGeo"] = skinMap

\t\taType.metadata()["stateMachine"] = AtomsCore.StringMetadata(self.stateMachine)

\t\tAtoms.AgentTypes.instance().addAgentType(self.agentTypeName, aType)
'''

agentType = "atomsRobot"

# This serialize the agent type in python
aType = Atoms.AgentTypes.instance().agentType(agentType)
if aType:
  atArchive = AtomsCore.Archive(aType.memSize())
  aType.serialise(atArchive)
  atArchive.writeToFile(os.path.join(agentTypesPath, "%s.agentType" %
                                               (agentType)))

agentTypesPath = "/atomsDemo/cache/test_cache/agentTypes/"

agentTypeScript = CACHED_AGENT_TYPE_SCRIPT

af = os.path.normpath(os.path.join(agentTypesPath, "%s.agentType" %
                                               (agentType)))

agentTypeScript = agentTypeScript.replace("agentTypeFile$", af)
agentTypeScript = agentTypeScript.replace("agentType$","%sCached" %
                                                      agentType)
agentTypeScript = agentTypeScript.replace("agentTypeName$",
                                                      agentType)
agentTypeScript = agentTypeScript.replace("AgentTypeEvent$",
                                                      "%sCached" % (agentType))

with open(os.path.join(agentTypesPath, "%s.py" % (agentType)), "w") as pyFile:
	pyFile.write(agentTypeScript)
	pyFile.close()

Frame files

キャッシュには、フレームごとに次の4つのファイルがあります。

  • header:現在のフレームのエージェント数、作成されたエージェントの数、削除されたエージェントの数などの基本情報
  • frame:エージェントの種類、位置、速度、bbox、バリエーションなどのエージェントデータ
  • meta:agents metadata
  • pose:agent skeleton data

Header file

Cache Frame Headerは、次のキーと値のペアを含むMapMetadataです。

  • agents:すべてのエージェントIDを含むIntArrayMetadata
  • agentsCreated:このフレームで作成されたエージェントのIDを含むIntArrayMetadata
  • agentsDeleted:このフレームで削除されたエージェントのIDを含むIntArrayMetadata
  • box:現在のフレームのバウンディングボックスを含むBoxMetadata


このファイルの拡張子は次のとおりです。

$ FRAME.header.atoms(つまりtest_cache.0010.header.atoms)


Frame file

CacheフレームはMapMetadataです。このマップの各エントリは、エージェントIDをキーとして使用し、値は次のキーと値のペアを含む別のMapMetadataです。

  • agentType:エージェントタイプ名を含むStringMetadata
  • box:エージェントバウンディングボックスを含むBoxMetadata
  • position:エージェントの位置を含むVector3Metadata
  • variation:エージェントバリエーションを含むStringMetadata
  • velocity:エージェントの速度を含むVector3Metadata

これは、フレームデータの例です。

  • "0":

- "agentType": StringMetadata("atomsRobot")

- "box": BoxMetadata(AtomsCore::Box(AtomsCore::Vector3(-10,-10,-10),AtomsCore::Vector3( 10, 10, 10)))

- "position": Vector3Metadata(AtomsCore::Vector3(0,0,0))

- "velocity": Vector3Metadata(AtomsCore::Vector3(1.4354,0.234,0.54433))

  • "1":

- "agentType": StringMetadata("atomsRobot")

- "box": BoxMetadata(AtomsCore::Box(AtomsCore::Vector3(-50,-10,-50),AtomsCore::Vector3(-40, 10, -40)))

- "position": Vector3Metadata(AtomsCore::Vector3(-45,0,0))

- "velocity": Vector3Metadata(AtomsCore::Vector3(1.5464,0.124,0.76433))

  • "5":

- "agentType": StringMetadata("atomsRobot")

- "box": BoxMetadata(...)

- "position": Vector3Metadata(...)

- "velocity": Vector3Metadata(...)

  • ...

このファイルの拡張子は以下のとおりです。

$ FRAME.frame.atoms(つまりtest_cache.0010.frame.atoms)


Metafile

Cache MetaファイルはMapMetadataです。このマップの各エントリは、エージェントIDをキーとして使用し、値はエージェントのすべてのメタデータを含む別のMapMetadataです。

これは一例です。

  • "0":
    - "position": Vector3Metadata(...)
    - "direction": Vector3Metadata(...)
    - "state": IntMetadata(...)
    - ...
  • "1":

    - "position": Vector3Metadata(...)
    - "direction": Vector3Metadata(...)
    - "state": IntMetadata(...)
    - ...

  • "1":

    - "position": Vector3Metadata(...)
    - "direction": Vector3Metadata(...)
    - "state": IntMetadata(...)
    - ...

  • ...

このファイルの拡張子は次のとおりです。

$ FRAME.meta.atoms(つまりtest_cache.0010.meta.atoms)


Pose file

Cache Pose fileは、MapMetadataです。このマップの各エントリは、エージェントIDをキーとして使用し、値はエージェントのポーズを格納するPoseMetadataです。
このファイルの拡張子は以下のとおりです。

$ FRAME.pose.atoms(つまりtest_cache.0010.pose.atoms)


Atoms Cacheの書き込み

AtomsCache :: exportCacheFrame()関数を使用して、Atoms Cacheをエクスポートできます。この関数は、フレームファイルだけをエクスポートします。HeaderとAgent Typeは、別々にエクスポートする必要があります。

#include <Atoms/AtomsCache

std::string cachePath = "/atomsDemo/cache/";
std::string cacheName = "cache_test";
int startFrame = 1;
int endFrame = 2;

// list of agents groups to export
std::vector<AtomsPtr<Atoms::AgentGroup>> agentGroups;

// if you are in maya or houdini you can get the agent groups from the agents simulation
auto sims = Atoms::AgentsSimulations::instance()
auto sim = sims.begin().second;
for(unsigned int i=0; i < sim.numAgentGroups(); i++)
{
	agentGroups.push_back(sim.agentGroup(i));
}

// This maps the agent global id with the cache id 
std::unordered_map<size_t, size_t> cacheIdMap;

std::set<std::string> agentTypes;

// Add compression and use multithread 
size_t tags = AtomsCore::Archive::kRandomAccessCompress | AtomsCore::Archive::kMultithread;


for (unsigned int frame = startFrame; frame < endFrame; frame++)
{
	AtomsCache::exportCacheFrame(cachePath, cacheName, frame, agentGroups, cacheIdMap, agentTypes, tags);
}

// save the agent types
Atoms::AgentTypes& agentTypes = Atoms::AgentTypes::instance();
for(const std::string agentType: agentTypes)
{
	auto agentTypePtr = agentTypes->agentType(agentType);
	if (!agentTypePtr)
		continue;
	AtomsCore::Archive agentTypeArchive(agentTypePtr->memSize());
	agentType->serialize(agentTypeArchive);
	std::string agentTypePath = cachePath  + "/agenTypes/" + agentType + ".agentType";
	agentTypeArchive->writeToFile(agentTypePath);

	//store the python event wrapper
	const std::string pythonEvent =	
	"import AtomsCore\n"
	"import Atoms\n"
	"import imath\n"
	"\n"
	"class "+ agentType +"Cached(Atoms.SimulationEvent):\n"
	"\tagentTypeFile = r'" + agentTypePath + "'\n"
	"\teventName = '" + agentType + "Cached'\n"
	"\tagentTypeName = '+ agentType + '\n"
	"\tgeoPath = ''\n"
	"\tskinPath = ''\n"
	"\tstateMachine = ''\n"
	"\n"
	"\tdef __init__(self):\n"
	"\t\tAtoms.SimulationEvent.__init__(self)\n"
	"\t\tself.setName(self.eventName)\n"
	"\n"
	"\tdef load(self):\n"
	"\t\taType = Atoms.AgentType()\n"
	"\t\taTypeArchive = AtomsCore.Archive()\n"
	"\t\tif aTypeArchive.readFromFile(self.agentTypeFile):\n"
	"\t\t\taType.deserialise(aTypeArchive)\n"
	"\t\telse:\n"
	"\t\t\treturn\n"
	"\n"
	"\t\tif self.geoPath:\n"
	"\t\t\tmeshMap = AtomsCore.MapMetadata()\n"
	"\t\t\ttypeArchive = AtomsCore.Archive()\n"
	"\t\t\tif typeArchive.readFromFile(self.geoPath):\n"
	"\t\t\t\tmeshMap.deserialise(typeArchive)\n"
	"\t\t\t\taType.metadata()["lowGeo"] = meshMap\n"
	"\n"
	"\t\tif self.skinPath:\n"
	"\t\t\tskinMap = AtomsCore.MapMetadata()\n"
	"\t\t\tskinArchive = AtomsCore.Archive()\n"
	"\t\t\tif skinArchive.readFromFile(self.skinPath):\n"
	"\t\t\t\tskinMap.deserialise(skinArchive)\n"
	"\t\t\t\taType.metadata()["skinGeo"] = skinMap\n"
	"\n"
	"\t\taType.metadata()["stateMachine"] = AtomsCore.StringMetadata(self.stateMachine)\n"
	"\n"
	"\t\tAtoms.AgentTypes.instance().addAgentType(self.agentTypeName, aType)\n";

	std::string agentTypeWrapperPath = cachePath  + "/agenTypes/" + agentType + ".py";
	std::ofstream out(agentTypeWrapperPath);
    out << pythonEvent;
    out.close();
}


// write the cache header
AtomsCore::IntArrayMetadata agentIdsMeta;
std::vector<int>& agentIdsVec = agentIdsMeta.get();
agentIdsVec.reserve(cacheIdMap.size());
for (auto it=cacheIdMap.begin(); it != cacheIdMap.end(); it++)
{
	agentIdsVec.pushBack(it->second);
}

std::sort(agentIdsVec.begin(), agentIdsVec.end());

AtomsCore::MapMetadata cacheHeader;
cacheHeader.addEntry("startFrame", &AtomsCore::IntMetadata(startFrame));
cacheHeader.addEntry("endFrame", &AtomsCore::IntMetadata(endFrame));
cacheHeader.addEntry("cacheType", &AtomsCore::StringMetadata("dynamic"));
cacheHeader.addEntry("agentIds", &agentIdsMeta);

Atoms Cacheの読み込み

Atoms Cacheは、様々なシリアル化されたMapMetadataで構成されているため、Atoms Serialization Systemを使用してそれらを読み取ることができます。
シミュレーション中に、異なるキャッシュフレームを複数回Queryする場合は、Cache Managerを使用して、パフォーマンスを向上させることができます。

Copyright © 2017, Toolchefs LTD.