Writing the behaviour module
First thing to do is create a Create a new class and hinerit from the base Atoms::BehaviourModule class. With a constructor a desctructor and a static creator function used by atoms Atoms to create an isntance of this module.
コード ブロック | ||
---|---|---|
| ||
class FollowTargetModule: public Atoms::BehaviourModule { public: FollowTargetModule() {} virtual ~FollowTargetModule() {} static Atoms::BehaviourModule* creator(const std::string& parameter); }; Atoms::BehaviourModule* FollowTargetModule::creator(const std::string& parameter) { return new FollowTargetModule(); } |
Lets add Add some attributes to our node. In this case we need only a target position. The attributes of the modules module are stored inside a MapMetadata object, and you can add new attribute attributes using the addAttribute function. So lets add Add this attribute inside the constructor.
コード ブロック | ||
---|---|---|
| ||
FollowTargetModule(): Atoms::BehaviourModule() { AtomsCore::Vector3Metadata targetPosition(AtomsCore::Vector3(0.0,0.0,0.0)); // The last argumet specify if this attribute can be override per agent addAttribute("targetPosition", &targerPosition, true); } |
Now we need to compute the new agent direction at each frame before the agent pose is computed, so we need to override the initFrame function.
You can override other function linke the endFrame or initSimulation or agentsCreated but in this case we need only the initFrame.
コード ブロック | ||
---|---|---|
| ||
void initFrame(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup = nullptr) { } |
In the init frame we need to get our initFrame function get the targetPosition value and iterate over each agent to get read the position and set the new direction.
コード ブロック | ||
---|---|---|
| ||
void initFrame(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup = nullptr) { // Get the target position from the moduel attribute AtomsCore::MapMetadata& attributeMap = attributes(); AtomsCore::Vector3& targetPosition = attributeMap.getTypedEntry<AtomsCore::Vector3Metadata>("targetPosition")->get(); // iterate over each agent for(Atoms::Agent* agent: agents) { if (!agent) continue; //get the agent position AtomsPtr<AtomsCore::Vector3Metadata> positionPtr = agent->metadata().getTypedEntry<AtomsCore::Vector3Metadata>("position"); AtomsPtr<AtomsCore::Vector3Metadata> directionPtr = agent->metadata().getTypedEntry<AtomsCore::Vector3Metadata>("direction"); if(!positionPtr || !directionPtr ) continue; // compute the new direction directionPtr->set((targetPosition - positionPtr->get()).normalized()); } } |
コード ブロック | ||
---|---|---|
| ||
void initFrame(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup = nullptr) { // Get the target position from the moduel attribute AtomsCore::MapMetadata& attributeMap = attributes(); AtomsCore::Vector3& targetPosition = attributeMap.getTypedEntry<AtomsCore::Vector3Metadata>("targetPosition")->get(); //get the override map metadata AtomsPtr<AtomsCore::MapMetadata> targetPositionOverride = attributeMap.getTypedEntry<AtomsCore::MapMetadata>("targetPosition_override"); // used to store the groupId as string char groupIdChar[12]; std::string groupIdStr; groupIdStr.reserve(12); // iterate over each agent for(Atoms::Agent* agent: agents) { if (!agent) continue; //get the agent position AtomsPtr<AtomsCore::Vector3Metadata> positionPtr = agent->metadata().getTypedEntry<AtomsCore::Vector3Metadata>("position"); AtomsPtr<AtomsCore::Vector3Metadata> directionPtr = agent->metadata().getTypedEntry<AtomsCore::Vector3Metadata>("direction"); if(!positionPtr || !directionPtr ) continue; // get the agent group id AtomsPtr<AtomsCore::IntMetadata> groupIdPtr = agent->metadata().getTypedEntry<AtomsCore::IntMetadata>("groupId"); if (!groupIdPtr) continue; //convert the groupId to a string since the map metadata use only strings as key sprintf(groupIdChar, "%d", groupIdPtr->value()); groupIdStr = groupIdChar; //check if the agent is inside the override map AtomsPtr<AtomsCore::Vector3Metadata> overrideTargetPos = targetPositionOverride->getTypedEntry<AtomsCore::Vector3Metadata>(groupIdStr); if (overrideTargetPos) { // compute the new direction directionPtr->set((overrideTargetPos->get() - positionPtr->get()).normalized()); } else { // compute the new direction directionPtr->set((targetPosition - positionPtr->get()).normalized()); } } } |
If you want imporve the performance of the module you can add tbb to parallelize the main for loop.
コード ブロック | ||
---|---|---|
| ||
void initFrame(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup = nullptr) { // Get the target position from the moduel attribute AtomsCore::MapMetadata& attributeMap = attributes(); AtomsCore::Vector3& targetPosition = attributeMap.getTypedEntry<AtomsCore::Vector3Metadata>("targetPosition")->get(); //get the override map metadata AtomsPtr<AtomsCore::MapMetadata> targetPositionOverride = attributeMap.getTypedEntry<AtomsCore::MapMetadata>("targetPosition_override"); // iterate over each agent tbb::parallel_for(tbb::blocked_range<unsigned int>(0, agents.size()), [&](const tbb::blocked_range<size_t>& r) { // used to store the groupId as string char groupIdChar[12]; std::string groupIdStr; groupIdStr.reserve(12); for (size_t i = r.begin(); i < r.end(); i++) { Atoms::Agent* agent = agents[i]; if (!agent) continue; //get the agent position AtomsPtr<AtomsCore::Vector3Metadata> positionPtr = agent->metadata().getTypedEntry<AtomsCore::Vector3Metadata>("position"); AtomsPtr<AtomsCore::Vector3Metadata> directionPtr = agent->metadata().getTypedEntry<AtomsCore::Vector3Metadata>("direction"); if(!positionPtr || !directionPtr ) continue; // get the agent group id AtomsPtr<AtomsCore::IntMetadata> groupIdPtr = agent->metadata().getTypedEntry<AtomsCore::IntMetadata>("groupId"); if (!groupIdPtr) continue; //convert the groupId to a string since the map metadata use only strings as key sprintf(groupIdChar, "%d", groupIdPtr->value()); groupIdStr = groupIdChar; //check if the agent is inside the override map AtomsPtr<AtomsCore::Vector3Metadata> overrideTargetPos = targetPositionOverride->getTypedEntry<AtomsCore::Vector3Metadata>(groupIdStr); if (overrideTargetPos) { // compute the new direction directionPtr->set((overrideTargetPos->get() - positionPtr->get()).normalized()); } else { // compute the new direction directionPtr->set((targetPosition - positionPtr->get()).normalized()); } } }); } |
Register the behaviour module
The main module is now ready so we need to register it Now the behaviour module must be added to the behaviour module factory.
コード ブロック | ||
---|---|---|
| ||
extern "C" { ATOMSPLUGIN_EXPORT bool initializePlugin() { Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance(); moduleManager.registerBehaviourModule("SimpleFollowTarget", &FollowTargetModule::creator, Atoms::BehaviourModules::kNative); return true; } ATOMSPLUGIN_EXPORT bool unitializePlugin() { Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance(); moduleManager.deregisterBehaviourModule("SimpleFollowTarget"); return true; } } |
Compile the behaviour module
Windows:
In visual studio create a dll projects, add the atoms, tbb and opendexr openexr includes and add BUILD_ATOMSPLUGIN to the preprocessor definitions.
Linux:
COmpile Compile as a shared object adding the atoms, tbb and opendexr includes and BUILD_ATOMSPLUGIN to the preprocessor definitions.
Use the behaviour module
Add the folder where the plugin is located to the Add to the ATOMS_PLUGINS_PATH environment variable, the folder where the plugin is located. Then the module is automatically loaded when you load atoms.
Final code
コード ブロック | ||
---|---|---|
| ||
#pragma once #include <Atoms/BehaviourModule.h> #include <Atoms/Agent.h> #include <Atoms/AgentGroup.h> #include <AtomsUtils/Logger.h> #include <Atoms/GlobalNames.h> #include <AtomsCore/Metadata/IntMetadata.h> #include <AtomsCore/Metadata/Vector3Metadata.h> #include <tbb/parallel_for.h> #include <algorithm> class FollowTargetModule : public Atoms::BehaviourModule { public: FollowTargetModule(): Atoms::BehaviourModule() { AtomsCore::Vector3Metadata targetPosition(AtomsCore::Vector3(0.0,0.0,0.0)); // The last argumet specify if this attribute can be override per agent addAttribute("targetPosition", &targerPosition, true); } ~FollowTargetModule() { } void initFrame(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup = nullptr) { // Get the target position from the moduel attribute AtomsCore::MapMetadata& attributeMap = attributes(); AtomsCore::Vector3& targetPosition = attributeMap.getTypedEntry<AtomsCore::Vector3Metadata>("targetPosition")->get(); //get the override map metadata AtomsPtr<AtomsCore::MapMetadata> targetPositionOverride = attributeMap.getTypedEntry<AtomsCore::MapMetadata>("targetPosition_override"); // iterate over each agent tbb::parallel_for(tbb::blocked_range<unsigned int>(0, agents.size()), [&](const tbb::blocked_range<size_t>& r) { // used to store the groupId as string char groupIdChar[12]; std::string groupIdStr; groupIdStr.reserve(12); for (size_t i = r.begin(); i < r.end(); i++) { Atoms::Agent* agent = agents[i]; if (!agent) continue; //get the agent position AtomsPtr<AtomsCore::Vector3Metadata> positionPtr = agent->metadata().getTypedEntry<AtomsCore::Vector3Metadata>("position"); AtomsPtr<AtomsCore::Vector3Metadata> directionPtr = agent->metadata().getTypedEntry<AtomsCore::Vector3Metadata>("direction"); if(!positionPtr || !directionPtr ) continue; // get the agent group id AtomsPtr<AtomsCore::IntMetadata> groupIdPtr = agent->metadata().getTypedEntry<AtomsCore::IntMetadata>("groupId"); if (!groupIdPtr) continue; //convert the groupId to a string since the map metadata use only strings as key sprintf(groupIdChar, "%d", groupIdPtr->value()); groupIdStr = groupIdChar; //check if the agent is inside the override map AtomsPtr<AtomsCore::Vector3Metadata> overrideTargetPos = targetPositionOverride->getTypedEntry<AtomsCore::Vector3Metadata>(groupIdStr); if (overrideTargetPos) { // compute the new direction directionPtr->set((overrideTargetPos->get() - positionPtr->get()).normalized()); } else { // compute the new direction directionPtr->set((targetPosition - positionPtr->get()).normalized()); } } }); } static Atoms::BehaviourModule* creator(const std::string& parameter); }; Atoms::BehaviourModule* FollowTargetModule::creator(const std::string& parameter) { return new FollowTargetModule(); } extern "C" { ATOMSPLUGIN_EXPORT bool initializePlugin() { Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance(); moduleManager.registerBehaviourModule("SimpleFollowTarget", &FollowTargetModule::creator, Atoms::BehaviourModules::kNative); return true; } ATOMSPLUGIN_EXPORT bool unitializePlugin() { Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance(); moduleManager.deregisterBehaviourModule("SimpleFollowTarget"); return true; } } |