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.