Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

In this section we are going to create a new behaviour module. This behaviour module is a simple follow target module.


Writing the behaviour module

Create a new class and inherit from the base Atoms::BehaviourModule class. Define a a constructor, a destructor and a static creator function (needed by Atoms to create an instance of this module).


Code Block
languagecpp
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();
}


For this module we'll need only a target position attribute. The attributes of the module are stored inside a MapMetadata object, you can add new attributes using the addAttribute function. Attributes should always be added inside the constructor.

The third attribute of the addAttribute method defines if the attribute is overridable per agent or not. In this example we'll make it overridable.


Code Block
languagecpp
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", &targerPositiontargetPosition, true);
}


Now we need to compute the new agent direction at each frame before the agent pose is computed. This will be done inside the initFrame method.

For this example we won't need to override any other method.



Code Block
languagecpp
void initFrame(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup = nullptr)
{
}


In the initFrame function get the targetPosition value, iterate over each agent to read the position and set their new direction.


Code Block
languagecpp
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()); 
	}
}


The target position attribute is overridable per agent, but the code to handle it isn't there yet. When you override an attribute, a new map metadata named "AttributeName_override" is created. The keys of this map metadata are the agent group ids, but they will be present only when the user specifies an override from inside his 3D application.

In order to know if an agent has an override, please check the metadata map. If it's not there, please use the global attribute.



Code Block
languagecpp
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> groupIdPtrconst std::string& groupIdStr = agent->metadata>groupIdStr().getTypedEntry<AtomsCore::IntMetadata>("groupId"->get();
		if
(!groupIdPtr)
			continue;

		//convertcheck if the groupIdagent tois ainside stringthe since theoverride 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);
				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 improve the performance of the module you can add tbb to parallelize the main for loop.


Code Block
languagecpp
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
    AtomsUtils::parallel_for(tbbAtomsUtils::blocked_range<unsigned int>ParallelForRange(0, agents.size()),
		         [&](const tbbAtomsUtils::blocked_range<size_t>ParallelForRange& r TASK_PARTITION_EXTRA_ARGS)
	
         {
		// 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> /* You can also access the direction ad position metadata direcly
			AtomsPtr<AtomsCore::Vector3Metadata>& positionPtr = agent->position();
			AtomsPtr<AtomsCore::Vector3Metadata>& directionPtr = agent->direction();
			*/
			AtomsPtr<AtomsCore::Vector3Metadata> positionPtr = agent->metadata().getTypedEntry<AtomsCore::Vector3Metadata>("position");
			AtomsPtr<AtomsCore::Vector3Metadata> directionPtr = agent->metadata().getTypedEntry<AtomsCore::Vector3Metadata>("direction");
			if(!positionPtr || !directionPtr )
				continue;

			// getconst std::string& groupIdStr = agent->groupIdStr()->get();
	
			//check if the agent group id is inside the override map
			AtomsPtr<AtomsCore::IntMetadata>Vector3Metadata> groupIdPtroverrideTargetPos = agent->metadata().getTypedEntry<AtomsCoretargetPositionOverride->getTypedEntry<AtomsCore::IntMetadata>Vector3Metadata>("groupId"groupIdStr);
			if (!groupIdPtroverrideTargetPos)
				continue;{
	
			//convert compute the groupIdnew to a string since the map metadata use only strings as key
			sprintf(groupIdChar, "%d", groupIdPtr->valuedirection
				directionPtr->set((overrideTargetPos->get() - positionPtr->get()).normalized()); 
			groupIdStr = groupIdChar;}
			else
			{
	
			//check ifcompute the agentnew is inside the override map
			AtomsPtr<AtomsCore::Vector3Metadata> overrideTargetPos = targetPositionOverride->getTypedEntry<AtomsCore::Vector3Metadata>(groupIdStr);
			if (overrideTargetPos)
			{
				// compute the new direction
				direction
				directionPtr->set((overrideTargetPos->get()targetPosition - positionPtr->get()).normalized()); 
			}
			else
			{
				// compute the new direction
				directionPtr->set((targetPosition - positionPtr->get()).normalized()); 
			}
		}
	});
}}
	});
}


Add visual debugging options

Lets implement a the draw function to visually debug the direction vector. Add a std::vector<AtomsCore::Vector3> m_drawLines to the class to store the lines data.

Inside the preDraw function you can collect the data form the agentse because it is called only if the time changes.

Then inside the draw function you can finally call the draw lines function to draw some lines.


Code Block
languagecpp
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);
}


Register the behaviour module

Now the behaviour module must be added to the behaviour module factory.


Code Block
languagecpp
extern "C"
{
	    ATOMSPLUGIN_EXPORT bool initializePlugin()
	{ 		Atoms::BehaviourModules& moduleManager = Atoms {
        AtomsUtils::BehaviourModulesLogger::instanceinfo();
moduleManager.registerBehaviourModule("SimpleFollowTarget", &FollowTargetModule::creator, Atoms::BehaviourModules::kNative);
		 << "Loading atoms test plugin";
        return true;
	}    }

    	ATOMSPLUGIN_EXPORT bool unitializePluginuninitializePlugin()
	{
		Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance();
		moduleManager.deregisterBehaviourModule("SimpleFollowTarget");
		    {
        AtomsUtils::Logger::info() << "Unloading atoms test plugin";
        return true;
	    }
}

Compile the behaviour module

Use this cmake file as template, change the project name and the source files and set the ATOMS_MAYA_FOLDER or ATOMS_HOUDINI_FOLDER env.

Code Blockcmake_minimum_required (VERSION 3.17) project ("MyAtomsPlugin") if (MSVC) cmake_policy(SET CMP0091 NEW) endif() enable_language(CXX) set(CMAKE_CXX_STANDARD 14) add_definitions(-DBUILD_ATOMSPLUGIN) add_definitions(-DTBB_USE_DEBUG=0) add_definitions(-D__TBB_LIB_NAME=tbb) add_definitions(-DNOMINMAX) add_definitions(-DBOOST_ALL_NO_LIB) if (UNIX) add_definitions(-DLINUX) add_definitions(-DPIC) add_definitions(-D_FILE_OFFSET_BITS=64) add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) add_compile_options(-std=c++14 -ffloat-store -fvisibility=hidden -fPIC) endif() if(DEFINED ATOMS_MAYA_FOLDER) include_directories(${ATOMS_MAYA_FOLDER}/include) link_directories(${ATOMS_MAYA_FOLDER}/lib/${MAYA_MAJOR_VERSION}) set(ATOMS_CUSTOM_PLUGINS_FOLDER ${ATOMS_MAYA_FOLDER}/plugins/${MAYA_MAJOR_VERSION}) endif() if(DEFINED ATOMS_HOUDINI_FOLDER) include_directories(${ATOMS_HOUDINI_FOLDER}/include) link_directories(${ATOMS_HOUDINI_FOLDER}/lib) set(ATOMS_CUSTOM_PLUGINS_FOLDER ${ATOMS_HOUDINI_FOLDER}/plugins) endif() include_directories(include) set(SOURCES "MyAtomsPlugin.cpp") add_library(${PROJECT_NAME} SHARED ${SOURCES}) if (MSVC) set_property(TARGET ${PROJECT_NAME} PROPERTY

    ATOMSPLUGIN_EXPORT bool initializeScene()
    {
        AtomsUtils::Logger::info() << "Loading atoms test scene plugin";
        Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance();
        moduleManager.registerBehaviourModule("SimpleFollowTarget", &FollowTargetModule::creator, Atoms::BehaviourModules::kNative,true, "MyCategory");

        return true;
    }

    ATOMSPLUGIN_EXPORT bool uninitializeScene()
    {
        Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance();
        moduleManager.deregisterBehaviourModule("SimpleFollowTarget");
        return true;
    }

}


Compile the behaviour module

Use this cmake file as template, change the project name and the source files and set the ATOMS_MAYA_FOLDER or ATOMS_HOUDINI_FOLDER env.




Code Block
cmake_minimum_required (VERSION 3.17)

project ("MyAtomsPlugin")


if (MSVC)
cmake_policy(SET CMP0091 NEW)
endif()

enable_language(CXX)
set(CMAKE_CXX_STANDARD 14)

add_definitions(-DBUILD_ATOMSPLUGIN)
add_definitions(-DTBB_USE_DEBUG=0)
add_definitions(-D__TBB_LIB_NAME=tbb)
add_definitions(-DNOMINMAX)
add_definitions(-DBOOST_ALL_NO_LIB)

if (UNIX)
add_definitions(-DLINUX)
add_definitions(-DPIC)
add_definitions(-D_FILE_OFFSET_BITS=64)
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
add_compile_options(-std=c++14 -ffloat-store -fvisibility=hidden -fPIC)
endif()


if(DEFINED ATOMS_MAYA_FOLDER)
include_directories(${ATOMS_MAYA_FOLDER}/include)
link_directories(${ATOMS_MAYA_FOLDER}/lib/${MAYA_MAJOR_VERSION})
set(ATOMS_CUSTOM_PLUGINS_FOLDER ${ATOMS_MAYA_FOLDER}/plugins/${MAYA_MAJOR_VERSION})
endif()

if(DEFINED ATOMS_HOUDINI_FOLDER)
include_directories(${ATOMS_HOUDINI_FOLDER}/include)
link_directories(${ATOMS_HOUDINI_FOLDER}/lib)
set(ATOMS_CUSTOM_PLUGINS_FOLDER ${ATOMS_HOUDINI_FOLDER}/plugins)
endif()

include_directories(include)


set(SOURCES
   "MyAtomsPlugin.cpp")

add_library(${PROJECT_NAME} SHARED ${SOURCES})

if (MSVC)
set_property(TARGET ${PROJECT_NAME} PROPERTY
             MSVC_RUNTIME_LIBRARY MultiThreadedDLL)
endif()

set_target_properties(${PROJECT_NAME}
        PROPERTIES
        INSTALL_RPATH_USE_LINK_PATH True)

target_link_libraries(${PROJECT_NAME}
        PUBLIC Atoms AtomsCore AtomsGraph AtomsUtils AtomsMath
        )

install(TARGETS ${PROJECT_NAME} DESTINATION ${ATOMS_CUSTOM_PLUGINS_FOLDER})


Use the behaviour module

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

Code Block
languagecpp
#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 <Atoms/BehaviourModules.h>
#include <Atoms/DrawContext.h>
#include <AtomsUtils/TaskScheduler.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", &targetPosition, 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
        AtomsUtils::parallel_for(AtomsUtils::ParallelForRange(0, agents.size()),
         [&](const AtomsUtils::ParallelForRange& r TASK_PARTITION_EXTRA_ARGS)
         {
              for (size_t i = r.begin(); i < r.end(); i++)
              {
                  Atoms::Agent* agent = agents[i];

                  if (!agent)
                      continue;
                  //get the agent position
                  /* You can also access the direction ad position metadata direcly with
			AtomsPtr<AtomsCore::Vector3Metadata>& positionPtr = agent->position();
			AtomsPtr<AtomsCore::Vector3Metadata>& directionPtr = agent->direction();
		  */
                  AtomsPtr<AtomsCore::Vector3Metadata> positionPtr = agent->metadata().getTypedEntry<AtomsCore::Vector3Metadata>("position");
                  AtomsPtr<AtomsCore::Vector3Metadata> directionPtr = agent->metadata().getTypedEntry<AtomsCore::Vector3Metadata>("direction");
                  if(!positionPtr || !directionPtr )
                      continue;

                  //convert the groupId to a string since the map metadata use only strings as key
                  const std::string& groupIdStr = agent->groupIdStr()->get();

                  //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
              
MSVC_RUNTIME_LIBRARY
 
MultiThreadedDLL)
 
endif()
  
set_target_properties($
{
PROJECT_NAME}

        
PROPERTIES
         
INSTALL_RPATH_USE_LINK_PATH
 
True)
  
target_link_libraries(${PROJECT_NAME}
  // compute the new direction
  
PUBLIC
 
Atoms
 
AtomsCore
 
AtomsGraph
 
AtomsUtils
 
AtomsMath
         
)
  
install(TARGETS
 
${PROJECT_NAME}
 
DESTINATION
 
${ATOMS_CUSTOM_PLUGINS_FOLDER})

Use the behaviour module

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

Code Block
languagecpp
#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(
 directionPtr->set((targetPosition - positionPtr->get()).normalized());
                  }
              }
          });
    }

    void preDraw(Atoms::DrawContext* context, 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);

        // 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 =
r.begin
 0; i < agents.size(); 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");
"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() {
 m_drawLines[i*2] = positionPtr->get();
            m_drawLines[i*2 + 1] = positionPtr->get() + directionPtr->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()
    {
        AtomsUtils::Logger::info() << "Loading atoms plugin";
        return true;
    }

    ATOMSPLUGIN_EXPORT bool uninitializePlugin()
    {
        AtomsUtils::Logger::info() << "Unloading atoms plugin";
        return true;
    }

    ATOMSPLUGIN_EXPORT bool initializeScene()
    {
        AtomsUtils::Logger::info() << "Loading atoms scene plugin";
        Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance(
);
);
        moduleManager.registerBehaviourModule("SimpleFollowTarget", &FollowTargetModule::creator, Atoms::BehaviourModules::kNative,true, "MyCategory");

        return true;
}
    }

   
 ATOMSPLUGIN_EXPORT bool 
unitializePlugin
uninitializeScene()
    
{

        Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance();
        moduleManager.deregisterBehaviourModule("SimpleFollowTarget");

        return true;
    }

}