Writing the behaviour module
新しいクラスを作成して、ベースから継承します。
Atoms :: Behaviourモジュールクラス。コンストラクタ、デストラクタ、およびスタティッククリエータ関数(こちらのモジュールのインスタンスを作成するために、Atomsが必要とする)を定義します。
コード ブロック | ||
---|---|---|
| ||
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();
} |
このモジュールでは、Target Positionアトリビュートのみが必要になります。モジュールのアトリビュートは、MapMetadataオブジェクト、FollowTargetModule()内に格納されます。addAttribute関数を使用して新しいアトリビュートを追加できます。
アトリビュートは、常に、コンストラクタ内に追加する必要があります。
addAttributeメソッドの3番目のアトリビュートは、そのアトリビュートがエージェント毎に、オーバーライドが可能かどうかを定義します。こちらの例では、オーバーライドを可能にします。
コード ブロック | ||
---|---|---|
| ||
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);
} |
今度は、エージェントのポーズが計算される前に、各フレームで新しいエージェントの方向を計算する必要があります。これは、initFrameメソッド内で行われます。
こちらの例では、他のメソッドをオーバーライドする必要はありません。
コード ブロック | ||
---|---|---|
| ||
void initFrame(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup = nullptr)
{
} |
initFrame関数より、targetPosition値を取得し、各エージェントを繰り返し処理します。
位置を読み取り、新しい方向を設定します。
コード ブロック | ||
---|---|---|
| ||
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());
}
} |
target positionアトリビュートは、エージェント毎にオーバーライドを実施することができますが、それを処理するコードはまだありません。アトリビュートを上書きすると、 "AttributeName_override"という名前の新しいmapmetadataが作成されます。このmapmetadataのキーは、エージェントグループIDですが、ユーザーが自分の3Dアプリケーション内からオーバーライドを指定した場合にのみ表示されます。
エージェントにオーバライドがあるかどうかを把握するためには、メタデータのマップを確認する必要があります。エージェントにオーバライドがない場合は、globalアトリビュートを使用してください。
コード ブロック | ||
---|---|---|
| ||
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());
}
}
} |
コード ブロック | ||
---|---|---|
| ||
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());
}
}
});
} |
Visual Debuggingオプションの追加
directionベクトルを視覚的にデバッグするためのdraw関数を実装しましょう。ラインデータを格納するためにstd :: vector <AtomsCore :: Vector 3> m_drawLinesをクラスに追加します。
preDraw関数の内部では、時間が変わった場合にのみ呼び出されるため、agentseからデータを収集できます。
そしてdraw関数の中で、最後にdraw lines関数を呼び出して、いくつかのラインを引くことができます。
コード ブロック | ||
---|---|---|
| ||
void preDraw(Atoms::DrawContext* context, const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup)
{
// The pre draw function is called only on time or attribute change,
// so it's safe to collect the data from the agents here
m_drawLines.resize(agents.size()*2);
for (size_t i = 0; i < agents.size(); i++)
{
Atoms::Agent* agent = agents[i];
//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;
m_drawLines[i*2] = positionPtr->get();
m_drawLines[i*2 + 1] = positionPtr->get() + directionPtr0>get();
}
}
void draw(Atoms::DrawContext* context, const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup)
{
// the draw function is called when the dcc update the viewports
context->lines(m_drawLines);
} |
Behaviour モジュールを登録する
Behaviourモジュールを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;
}
}
|
Behaviour モジュールをコンパイルする
Windows:
Visual Studioでdllプロジェクトを作成し、atom、tbb、openexr includeを追加して、BUILD_ATOMSPLUGINをプリプロセッサ定義に追加します。
Linux:
Atoms、tbbおよびopendexr includesとBUILD_ATOMSPLUGINをプリプロセッサ定義に追加して、共有オブジェクトとしてコンパイルします。
Behaviour モジュールを使用する
ATOMS_PLUGINS_PATH環境変数に、プラグインが配置されているフォルダーを追加します。その後、Atomsをロードするとモジュールが自動的にロードされます。
最終コード
コード ブロック | ||
---|---|---|
| ||
#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());
}
}
});
}
void preDraw(Atoms::DrawContext* context, const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup)
{
// The pre draw function is called only when the time is changed or some attribute is changed so
// we can collect the data from the agents here
m_drawLines.resize(agents.size()*2);
for (size_t i = 0; i < agents.size(); i++)
{
Atoms::Agent* agent = agents[i];
//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;
m_drawLines[i*2] = positionPtr->get();
m_drawLines[i*2 + 1] = positionPtr->get() + directionPtr0>get();
}
}
void draw(Atoms::DrawContext* context, const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup)
{
// the draw function is called when the dcc update the viewports
context->lines(m_drawLines);
}
static Atoms::BehaviourModule* creator(const std::string& parameter);
private:
std::vector<AtomsCore::Vector3> m_drawLines;
};
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;
}
}
|