/
Writing an Atoms operator
Writing an Atoms operator
An Atoms operator is a specialized Atoms graph node having a built-in out pose port and specific functions to access the owner agent.
This example operator adds an offset to a joint transform.
#include <AtomsGraph/Ports.h>
#include <Atoms/Globals.h>
#include <Atoms/Graph/Operator.h>
class JointOffsetOperator : public Atoms::Operator
{
public:
NODE_STANDARD_MEMBERS
JointOffsetOperator();
virtual ~JointOffsetOperator();
virtual bool compute(const AtomsGraph::ComputeData* computeData) override;
virtual void reset() override;
private:
AtomsGraph::PosePort* m_inPose;
AtomsGraph::StringPort *m_jointName;
AtomsGraph::MatrixPort *m_offsetMatrix;
AtomsGraph::BooleanPort *m_worldSpace;
int m_jointId;
bool m_first;
};
// this must be unique
#define JOINT_OFFSET_OPERATOR_ID 9999991
NODE_STANDARD_MEMBERS_IMPL(JointOffsetOperator)
unsigned int JointOffsetOperator::staticTypeId() { return JOINT_OFFSET_OPERATOR_ID; }
std::string JointOffsetOperator::staticTypeStr() { return std::string("JointOffsetOperator"); }
JointOffsetOperator::JointOffsetOperator() : Operator()
{
m_jointName= new AtomsGraph::StringPort("jointName");
m_jointName->set("");
addInputPort(m_jointName);
m_offsetMatrix = new AtomsGraph::MatrixPort("offsetMatrix");
addInputPort(m_offsetMatrix);
m_inPose = new AtomsGraph::PosePort("inPose");
addInputPort(m_inPose);
m_worldSpace = new AtomsGraph::BooleanPort("worldSpace");
m_worldSpace->set(false);
addInputPort(m_worldSpace );
m_jointId= -1;
m_first = true;
}
JointConstraintOperator::~JointConstraintOperator()
{
}
bool JointConstraintOperator::compute(const AtomsGraph::ComputeData* computeData)
{
AtomsCore::Pose &inPose = m_inPose->getRef();
if (inPose.numJoints() == 0)
{
AtomsUtils::Logger::warning() << "Empty input pose";
return false;
}
AtomsCore::Pose &outPose = m_outPose->getRef();
// Copy the input pose to the out pose port
outPose = inPose;
// Check if the agent and the agent type are valid
if (!m_agent)
{
AtomsUtils::Logger::error() << "Invalid agent type";
return false;
}
if(!m_agent->agentType())
{
AtomsUtils::Logger::error() << "Invalid agent type";
return false;
}
// Get the skeleton from the agent type
const AtomsCore::Skeleton& skeleton = m_agent->agentType()->skeleton();
if (m_first)
{
m_jointId = skeleton.jointId(m_targetJoint->getRef());
}
if (m_jointId == -1)
{
Logger::error() << "Could not find " << m_targetJoint->getRef() << "joint.";
return false;
}
if (worldSpace->get())
{
// Compute the offset in world space
AtomsCore::Poser poser(&skeleton);
AtomsCore::Matrix currentMtx = poser.getWorldMatrix(pose, jointId);
poser.setWorldMatrix(pose, m_offsetMatrix->getRef()* currentMtx, jointIdTmp);
}
else
{
// Compute the offset in local space
AtomsCore::JointPose& jp = outPose.jointPose(m_jointId);
jp.setMatrix(m_offsetMatrix->getRef() * jp.matrix());
}
return true;
}
void JointConstraintOperator::reset()
{
Operator::reset();
m_jointName->set("");
m_worldSpace->set(false);
m_jointId= -1;
m_first = true;
}
The operator can be added by this custom behaviour module.
#include <Atoms/BehaviourModule.h>
class JointOffsetModule : public Atoms::BehaviourModule
{
public:
JointOffsetModule ();
virtual ~JointOffsetModule ();
void agentsCreated(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup = nullptr);
static Atoms::BehaviourModule* creator(const std::string& parameter);
};
Atoms::BehaviourModule* JointOffsetModule::creator(const std::string& parameter)
{
return new JointOffsetModule();
}
JointOffsetModule::JointOffsetModule() :
Atoms::BehaviourModule()
{
AtomsCore::StringMetadata jointName("");
addAttribute("jointName", &jointName, false);
AtomsCore::MatrixMetadata offsetMatrix;
addAttribute("offsetMatrix", &offsetMatrix, true);
AtomsCore::BoolMetadata worldSpace(false);
addAttribute("worldSpace", &worldSpace);
}
JointOffsetModule::~JointOffsetModule()
{
}
void JointOffsetModule::agentsCreated(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup)
{
AtomsCore::MapMetadata& metadata = attributes();
const std::string& jointName= metadata.getTypedEntry<AtomsCore::StringMetadata>("jointName")->get();
bool worldSpace = metadata.getTypedEntry<AtomsCore::BoolMetadata>("worldSpace")->get();
AtomsCore::Matrix& offsetMatrix = metadata.getTypedEntry<AtomsCore::MatrixMetadata>("offsetMatrix")->get();
AtomsPtr<AtomsCore::MapMetadata> offsetMatrixOverrideMap = metadata.getTypedEntry<AtomsCore::MapMetadata>("offsetMatrix_override");
tbb::parallel_for(tbb::blocked_range<unsigned int>(0, agents.size()),
[&](const tbb::blocked_range<unsigned int>& r)
{
char groupIdChar[12];
std::string groupIdStr;
groupIdStr.reserve(12);
for (unsigned int i = r.begin(); i < r.end(); i++)
{
Atoms::Agent* agent = agents[i];
// Get the agent dg network
Atoms::AgentBehaviourNetwork& network = agent->network();
// Get the last operator fron the dg
Atoms::Operator* endOperator = network.buildPoseNode();
// Create the joint offset operator
Atoms::JointOffsetOperator* jointOffset = static_cast<Atoms::JointOffsetOperator*>(network.manager().createNode(Atoms::JointOffsetOperator::staticTypeStr(), "jointOffset"));
jointOffset->setAgent(agent);
// Connect the last operator to the joint offset operator
network.manager().connectAttr(endOperator->name(), "outPose", jointOffset ->name(), "inPose");
// Set the operator parameters
jointOffset->getInputPort<AtomsGraph::StringPort>("jointName")->set(jointName);
jointOffset->getInputPort<AtomsGraph::BooleanPort>("worldSpace")->set(worldSpace );
AtomsCore::Matrix agentOffsetMatrix = offsetMatrix;
// Check if the offset matrix is overridden
AtomsPtr<AtomsCore::IntMetadata> groupIdPtr = agent->metadata().getTypedEntry<AtomsCore::IntMetadata>(ATOMS_AGENT_GROUPID);
if (groupIdPtr)
{
sprintf(groupIdChar, "%d", groupIdPtr->value());
groupIdStr = groupIdChar;
if (offsetMatrixOverrideMap)
{
AtomsPtr<AtomsCore::MatrixMetadata> offsetMatrixAgentMeta = offsetMatrixOverrideMap->getTypedEntry<AtomsCore::MatrixMetadata>(groupIdStr);
if (offsetMatrixAgentMeta)
offsetMatrix = offsetMatrixAgentMeta->get();
}
}
jointOffset->getInputPort<AtomsGraph::MatrixPort>("offsetMatrix")->set(offsetMatrix);
// Set the joint offset operator as the last operator to compute
network.setBuildPoseNode(jointOffset);
}
});
}
extern "C"
{
ATOMSPLUGIN_EXPORT bool initializePlugin()
{
AtomsUtils::Logger::info() << "Loading Joint offset plugin";
// Register the node to the factory
AtomsGraph::NodeFactory& manager = AtomsGraph::NodeFactory::instance();
manager.registerNode(JointConstraintOperator::staticTypeStr(), &JointConstraintOperator::creator);
Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance();
moduleManager.registerBehaviourModule("SimpleJointOffset", &JointOffsetModule::creator, Atoms::JointOffsetModule::kNative);
return true;
}
ATOMSPLUGIN_EXPORT bool unitializePlugin()
{
AtomsUtils::Logger::info() << "Unloading Joint offset plugin";
// Deregister the node from the node factory
AtomsGraph::NodeFactory& manager = AtomsGraph::NodeFactory::instance();
manager.deregisterNode(JointConstraintOperator::staticTypeStr());
Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance();
moduleManager.deregisterBehaviourModule("SimpleJointOffset");
return true;
}
}
, multiple selections available,
Related content
Writing an Atoms operator (AtomsUnreal)
Writing an Atoms operator (AtomsUnreal)
More like this
Writing an Atoms graph node
Writing an Atoms graph node
More like this
Writing an Atoms graph node (AtomsUnreal)
Writing an Atoms graph node (AtomsUnreal)
More like this
Access agent data (AtomsUnreal)
Access agent data (AtomsUnreal)
More like this
Operators
Operators
More like this
Writing a Metadata Replicator module
Writing a Metadata Replicator module
More like this
Copyright © 2017, Toolchefs LTD.