...
This example operator adds an offset to a joint transform.
Code Block | ||
---|---|---|
| ||
#pragma once #include <AtomsGraph/Ports.h> #include <Atoms/Globals.h> #include <Atoms/Graph/Operator.h> class JointOffsetOperatorMyJointTransformOperator : public Atoms::Operator { public: NODE_STANDARD_MEMBERS JointOffsetOperatorMyJointTransformOperator(); virtual ~JointOffsetOperator~MyJointTransformOperator(); virtual bool compute() compute(const AtomsGraph::ComputeData* computeData) override; virtual void reset() override; private: AtomsGraph::PosePort* m_inPose; AtomsGraph::StringPort *m_jointNameinJointName; AtomsGraph::MatrixPortLongPort *m_offsetMatrixinRotationOrder; AtomsGraph::BooleanPort *m_worldSpaceinWorldSpace; AtomsGraph::BooleanPort *m_inOffset; intAtomsGraph::VectorPort *m_jointIdinTranslate; boolAtomsGraph::VectorPort *m_firstinRotate; }; // 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() { 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; } |
The operator can be added by this custom behaviour module.
Code Block | ||
---|---|---|
| ||
#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); } }); } void FAtomsDemoGameModule::StartupModule() { AtomsUtils::Logger::info() << "Loading Joint offset plugin"; // Register the node to the factory AtomsGraph::VectorPort *m_inScale; AtomsGraph::DoublePort *m_inWeight; int m_jointId; bool m_first; }; |
Code Block | ||
---|---|---|
| ||
#include "MyJointTransformOperator.h"
#include <Atoms/Graph/Operators/OperatorIds.h>
#include <Atoms/AgentTypes.h>
#include <Atoms/Agent.h>
#include <AtomsCore/Metadata/StringMetadata.h>
#include <AtomsCore/Poser.h>
using namespace Atoms;
using namespace AtomsGraph;
#define MY_JOINT_TRANSFORM_OPERATOR_ID 9999991
NODE_STANDARD_MEMBERS_IMPL(MyJointTransformOperator)
unsigned int MyJointTransformOperator::staticTypeId() { return JOINT_TRANSFORM_OPERATOR_ID; }
std::string MyJointTransformOperator::staticTypeStr() { return std::string("MyJointTransformOperator"); }
AtomsCore::Euler::Order jtOpConvertRotateOrderToEulerRot(int value)
{
AtomsCore::Euler::Order returnOrder;
switch (value)
{
case 0:
returnOrder = AtomsCore::Euler::XYZ;
break;
case 1:
returnOrder = AtomsCore::Euler::YZX;
break;
case 2:
returnOrder = AtomsCore::Euler::ZXY;
break;
case 3:
returnOrder = AtomsCore::Euler::XZY;
break;
case 4:
returnOrder = AtomsCore::Euler::YXZ;
break;
case 5:
returnOrder = AtomsCore::Euler::ZYX;
break;
default:
returnOrder = AtomsCore::Euler::XYZ;
break;
}
return returnOrder;
}
MyJointTransformOperator::MyJointTransformOperator() : Operator()
{
m_inJointName = new AtomsGraph::StringPort("jointName");
m_inJointName->set("");
addInputPort(m_inJointName);
m_inOffset = new AtomsGraph::BooleanPort("offset");
addInputPort(m_inOffset);
m_inRotationOrder = new AtomsGraph::LongPort("rotationOrder");
addInputPort(m_inRotationOrder);
m_inWorldSpace = new AtomsGraph::BooleanPort("worldSpace");
addInputPort(m_inWorldSpace);
m_inTranslate = new AtomsGraph::VectorPort("translate");
m_inTranslate->set(AtomsCore::Vector3(0, 0, 0));
addInputPort(m_inTranslate);
m_inRotate = new AtomsGraph::VectorPort("rotate");
m_inRotate->set(AtomsCore::Vector3(0, 0, 0));
addInputPort(m_inRotate);
m_inScale = new AtomsGraph::VectorPort("scale");
m_inScale->set(AtomsCore::Vector3(1, 1, 1));
addInputPort(m_inScale);
m_inPose = new AtomsGraph::PosePort("inPose");
addInputPort(m_inPose);
m_inWeight = new AtomsGraph::DoublePort("weight");
addInputPort(m_inWeight);
m_jointId = -1;
m_first = true;
}
MyJointTransformOperator::~MyJointTransformOperator()
{
}
bool MyJointTransformOperator::compute(const AtomsGraph::ComputeData* computeData)
{
AtomsCore::Pose &inPose = m_inPose->getRef();
if (inPose.numJoints() == 0)
{
Logger::warning() << "Empty input pose";
return false;
}
AtomsCore::Pose &outPose = m_outPose->getRef();
outPose = inPose;
if (!m_agent || !m_agent->agentType())
{
AtomsUtils::Logger::error() << "Invalid agent type";
return false;
}
const AtomsCore::Skeleton& skeleton = m_agent->agentType()->skeleton();
if (m_first)
{
m_jointId = skeleton.jointId(m_inJointName->getRef());
}
if (m_jointId == -1)
{
Logger::error() << "Could not find joint.";
return false;
}
double weight = m_inWeight->get();
if (weight < 0.0001)
return true;
bool offset = m_inOffset->get();
bool worldSpace = m_inWorldSpace->get();
AtomsCore::Vector3 translate = m_inTranslate->get();
AtomsCore::Vector3 rotate = m_inRotate->get();
AtomsCore::Vector3 scale = m_inScale->get();
int rotationOrder = m_inRotationOrder->get();
AtomsCore::Poser poser(&skeleton);
if (worldSpace)
{
AtomsCore::Matrix jointMtx;
if (!offset)
{
AtomsCore::Matrix currentMtx = poser.getWorldMatrix(outPose, m_jointId);
AtomsCore::Euler currEulerRotation;
AtomsCore::Vector3 currScale(1.0, 1.0, 1.0);
AtomsCore::Vector3 shear(0.0, 0.0, 0.0);
AtomsCore::Vector3 currTranslation(0.0, 0.0, 0.0);
AtomsMath::extractSHRT(currentMtx, currScale, shear, currEulerRotation, currTranslation);
AtomsCore::Quaternion currRotation = currEulerRotation.toQuat();
scale = currScale * (1.0 - weight) + scale * weight;
translate = currTranslation * (1.0 - weight) + translate * weight;
AtomsCore::Euler rotation(rotate.x * M_PI / 180.0, rotate.y * M_PI / 180.0, rotate.z * M_PI / 180.0, jtOpConvertRotateOrderToEulerRot(rotationOrder));
AtomsCore::Quaternion quatTmp = AtomsMath::slerp(currRotation, rotation.toQuat(), weight);
jointMtx.makeIdentity();
jointMtx.translate(translate);
jointMtx = quatTmp.toMatrix44() * jointMtx;
jointMtx.scale(scale);
poser.setWorldMatrix(outPose, jointMtx, m_jointId);
}
else
{
AtomsCore::Vector3 currScale(1.0, 1.0, 1.0);
AtomsCore::Vector3 currTranslation(0.0, 0.0, 0.0);
AtomsCore::Quaternion currRotation;
scale = currScale * (1.0 - weight) + scale * weight;
translate = currTranslation * (1.0 - weight) + translate * weight;
AtomsCore::Euler rotation(rotate.x * M_PI / 180.0, rotate.y * M_PI / 180.0, rotate.z * M_PI / 180.0, jtOpConvertRotateOrderToEulerRot(rotationOrder));
AtomsCore::Quaternion quatTmp = AtomsMath::slerp(currRotation, rotation.toQuat(), weight);
jointMtx.makeIdentity();
jointMtx.translate(translate);
jointMtx = quatTmp.toMatrix44() * jointMtx;
jointMtx.scale(scale);
AtomsCore::Matrix currentMtx = poser.getWorldMatrix(outPose, m_jointId);
poser.setWorldMatrix(outPose, jointMtx * currentMtx, m_jointId);
}
}
else
{
if (!offset)
{
auto& jPose = outPose.jointPose(m_jointId);
AtomsCore::Vector3& currScale = jPose.scale;
AtomsCore::Vector3& currTranslation = jPose.translation;
AtomsCore::Quaternion& currRotation = jPose.rotation;
AtomsCore::Euler rotation(rotate.x * M_PI / 180.0, rotate.y * M_PI / 180.0, rotate.z * M_PI / 180.0, jtOpConvertRotateOrderToEulerRot(rotationOrder));
jPose.rotation = AtomsMath::slerp(currRotation, rotation.toQuat(), weight);
jPose.scale = currScale * (1.0 - weight) + scale * weight;
jPose.translation = currTranslation * (1.0 - weight) + translate * weight;
}
else
{
auto& jPose = outPose.jointPose(m_jointId);
AtomsCore::Vector3 currScale(1.0, 1.0, 1.0);
AtomsCore::Vector3 currTranslation(0.0, 0.0, 0.0);
AtomsCore::Quaternion currRotation;
AtomsCore::Euler rotation(rotate.x * M_PI / 180.0, rotate.y * M_PI / 180.0, rotate.z * M_PI / 180.0, jtOpConvertRotateOrderToEulerRot(rotationOrder));
AtomsCore::Quaternion quatTmp = AtomsMath::slerp(currRotation, rotation.toQuat(), weight);
jPose.scale.x *= currScale.x * (1.0 - weight) + scale.x * weight;
jPose.scale.y *= currScale.y * (1.0 - weight) + scale.y * weight;
jPose.scale.z *= currScale.z * (1.0 - weight) + scale.z * weight;
jPose.translation += currTranslation * (1.0 - weight) + translate * weight;
jPose.rotation = jPose.rotation * quatTmp;
}
}
return true;
}
void MyJointTransformOperator::reset()
{
Operator::reset();
m_first = true;
m_jointId = -1;
m_inScale->set(AtomsCore::Vector3(1, 1, 1));
m_inRotate->set(AtomsCore::Vector3(0, 0, 0));
m_inJointName->set("");
}
|
The operator can be added by this custom behaviour module.
Code Block | ||
---|---|---|
| ||
#pragma once
#include <Atoms/BehaviourModule.h>
class MyJointTransformModule : public Atoms::BehaviourModule
{
public:
MyJointTransformModule();
virtual ~MyJointTransformModule();
void agentsCreated(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup);
void initFrame(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup);
static Atoms::BehaviourModule* creator(const std::string& parameter);
};
|
Code Block |
---|
#include "MyJointTransformModule.h"
#include "MyJointTransformOperator.h"
#include <AtomsCore/Metadata/IntMetadata.h>
#include <AtomsCore/Metadata/BoolMetadata.h>
#include <AtomsCore/Metadata/Vector3Metadata.h>
#include <AtomsCore/Metadata/DoubleMetadata.h>
#include <AtomsCore/Metadata/StringMetadata.h>
#include <AtomsCore/Metadata/MatrixMetadata.h>
#include <AtomsCore/Metadata/StringArrayMetadata.h>
#include <Atoms/GlobalNames.h>
#include <Atoms/Agent.h>
#include <AtomsCore/Poser.h>
#include <AtomsUtils/TaskScheduler.h>
AtomsCore::Euler::Order jtmConvertRotateOrderToEulerRot(int value)
{
AtomsCore::Euler::Order returnOrder;
switch (value)
{
case 0:
returnOrder = AtomsCore::Euler::XYZ;
break;
case 1:
returnOrder = AtomsCore::Euler::YZX;
break;
case 2:
returnOrder = AtomsCore::Euler::ZXY;
break;
case 3:
returnOrder = AtomsCore::Euler::XZY;
break;
case 4:
returnOrder = AtomsCore::Euler::YXZ;
break;
case 5:
returnOrder = AtomsCore::Euler::ZYX;
break;
default:
returnOrder = AtomsCore::Euler::XYZ;
break;
}
return returnOrder;
}
MyJointTransformModule::MyJointTransformModule() : Atoms::BehaviourModule()
{
AtomsCore::StringMetadata jointName;
addAttribute("jointName", &jointName, true);
AtomsCore::StringMetadata tooltipJointName("The joint name");
addAttributeProperty("jointName", ATOMS_BEHAVIOUR_TOOLTIP, &tooltipJointName);
AtomsCore::StringMetadata jointNameConstructor(Atoms::GlobalNameKeys::ATOMS_BEHAVIOUR_HARD_CONSTRUCTOR_JOINT_NAME_KEY);
addAttributeProperty("jointName", Atoms::GlobalNameKeys::ATOMS_BEHAVIOUR_HARD_CONSTRUCTOR_KEY, &jointNameConstructor);
AtomsCore::IntMetadata order(0);
addAttribute("rotationOrder", &order, true);
AtomsCore::StringMetadata tooltipOrder("The rotation order");
addAttributeProperty("rotationOrder", ATOMS_BEHAVIOUR_TOOLTIP, &tooltipOrder);
AtomsCore::BoolMetadata worldSpace(false);
addAttribute("worldSpace", &worldSpace, true);
AtomsCore::StringMetadata tooltipWorldSpace("Apply the transformation in world space");
addAttributeProperty("worldSpace", ATOMS_BEHAVIOUR_TOOLTIP, &tooltipWorldSpace);
AtomsCore::BoolMetadata add(true);
addAttribute("offset", &add, true);
AtomsCore::StringMetadata tooltipOffset("Apply the transformation as an offset to the current one");
addAttributeProperty("offset", ATOMS_BEHAVIOUR_TOOLTIP, &tooltipOffset);
AtomsCore::Vector3Metadata rotate(AtomsCore::Vector3(0.0, 0.0, 0.0));
addAttribute("rotate", &rotate, true);
AtomsCore::StringMetadata tooltipRotate("Rotation value in degrees");
addAttributeProperty("rotate", ATOMS_BEHAVIOUR_TOOLTIP, &tooltipRotate);
AtomsCore::Vector3Metadata scale(AtomsCore::Vector3(1.0, 1.0, 1.0));
addAttribute("scale", &scale, true);
AtomsCore::StringMetadata tooltipScale("Scale value");
addAttributeProperty("scale", ATOMS_BEHAVIOUR_TOOLTIP, &tooltipScale);
AtomsCore::Vector3Metadata translate(AtomsCore::Vector3(0.0, 0.0, 0.0));
addAttribute("translate", &translate, true);
AtomsCore::StringMetadata tooltipTranslate("Translation value");
addAttributeProperty("translate", ATOMS_BEHAVIOUR_TOOLTIP, &tooltipTranslate);
AtomsCore::DoubleMetadata weight(1.0);
addAttribute("weight", &weight, true);
AtomsCore::StringMetadata tooltipWeight("The weight");
addAttributeProperty("weight", ATOMS_BEHAVIOUR_TOOLTIP, &tooltipWeight);
AtomsCore::DoubleMetadata minWeight(0.0);
addAttributeProperty("weight", ATOMS_BEHAVIOUR_MIN_VALUE, &minWeight);
AtomsCore::DoubleMetadata maxWeight(1.0);
addAttributeProperty("weight", ATOMS_BEHAVIOUR_MAX_VALUE, &maxWeight);
AtomsCore::BoolMetadata useOperator(false);
addAttribute("useOperator", &useOperator, true);
AtomsCore::StringMetadata tooltipUseOperator(
"If true, the transformation will be applied by an operator instead of the module itself at the endFrame stage.\n"
"This option should be enabled when a joint transform module is used on an agent group using other modules\n"
"actively modifying the pose with an operator and not at the endFrame stage(i.e.Sync)");
addAttributeProperty("useOperator", ATOMS_BEHAVIOUR_TOOLTIP, &tooltipUseOperator);
// Display order
std::vector<std::string> displayOrderVector{
"jointName", "offset", "translate", "rotate", "scale", "rotationOrder",
"worldSpace", "useOperator", "weight" };
AtomsCore::StringArrayMetadata displayOrder(displayOrderVector);
addAttributeProperty(ATOMS_BEHAVIOUR_MODULE_PROPERTIES, ATOMS_BEHAVIOUR_MODULE_DISPLAY_ORDER, &displayOrder);
}
MyJointTransformModule::~MyJointTransformModule()
{
}
void MyJointTransformModule::agentsCreated(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup)
{
auto& attribs = attributes();
bool add = attribs.getTypedEntry<AtomsCore::BoolMetadata>("offset")->value();
bool worldSpace = attribs.getTypedEntry<AtomsCore::BoolMetadata>("worldSpace")->value();
const std::string& jointName = attribs.getTypedEntry<AtomsCore::StringMetadata>("jointName")->value();
int rotationOrder = attribs.getTypedEntry<AtomsCore::IntMetadata>("rotationOrder")->value();
AtomsPtr<AtomsCore::MapMetadata> jointNameOverrideMap = attribs.getTypedEntry<AtomsCore::MapMetadata>("jointName_override");
AtomsPtr<AtomsCore::MapMetadata> rotationOrderOverrideMap = attribs.getTypedEntry<AtomsCore::MapMetadata>("rotationOrder_override");
AtomsPtr<AtomsCore::MapMetadata> addOverrideMap = attribs.getTypedEntry<AtomsCore::MapMetadata>("offset_override");
AtomsPtr<AtomsCore::MapMetadata> worldSpaceOverrideMap = attribs.getTypedEntry<AtomsCore::MapMetadata>("worldSpace_override");
const std::string jointNameOverrideName = name() + "@jointName";
const std::string rotationOrderOverrideName = name() + "@rotationOrder";
const std::string offsetOverrideName = name() + "@offset";
const std::string worldSpaceOverrideName = name() + "@worldSpace";
std::string operatorName = name() + "Op";
AtomsUtils::parallel_for(AtomsUtils::ParallelForRange(0, agents.size()),
[&](const AtomsUtils::ParallelForRange& r TASK_PARTITION_EXTRA_ARGS)
{
for (unsigned int i = r.begin(); i < r.end(); i++)
{
Atoms::Agent* agent = agents[i];
std::string jointNameTmp = jointName;
int rotationOrderTmp = rotationOrder;
bool worldSpaceTmp = worldSpace;
bool addTmp = add;
auto& groupIdStr = agent->groupIdStr()->get();
jointNameTmp = getAttributePerAgent(jointName, jointNameOverrideMap.get(), groupIdStr, agent->metadata(), jointNameOverrideName);
rotationOrderTmp = getAttributePerAgent(rotationOrder, rotationOrderOverrideMap.get(), groupIdStr, agent->metadata(), rotationOrderOverrideName);
addTmp = getAttributePerAgent(add, addOverrideMap.get(), groupIdStr, agent->metadata(), offsetOverrideName);
worldSpaceTmp = getAttributePerAgent(worldSpace, worldSpaceOverrideMap.get(), groupIdStr, agent->metadata(), worldSpaceOverrideName);
if (jointNameTmp.empty())
continue;
Atoms::AgentBehaviourNetwork& network = agent->network();
Atoms::Operator* endOperator = network.buildPoseNode();
MyJointTransformOperator* jointTransform = static_cast<MyJointTransformOperator*>(network.manager().createNode(MyJointTransformOperator::staticTypeStr(), "jointTransform"));
jointTransform->setAgent(agent);
network.manager().connectAttr(endOperator->name(), "outPose", jointTransform->name(), "inPose");
AtomsCore::StringMetadata bm(jointTransform->name());
agent->metadata().addEntry(operatorName, &bm);
jointTransform->getInputPort<AtomsGraph::StringPort>("jointName")->set(jointNameTmp);
jointTransform->getInputPort<AtomsGraph::LongPort>("rotationOrder")->set(rotationOrderTmp);
jointTransform->getInputPort<AtomsGraph::BooleanPort>("offset")->set(addTmp);
jointTransform->getInputPort<AtomsGraph::BooleanPort>("worldSpace")->set(worldSpaceTmp);
network.setBuildPoseNode(jointTransform);
}
});
}
void MyJointTransformModule::initFrame(const std::vector<Atoms::Agent*>& agents, Atoms::AgentGroup* agentGroup)
{
auto& attribs = attributes();
double weight = attribs.getTypedEntry<AtomsCore::DoubleMetadata>("weight")->value();
AtomsCore::Vector3 rotate = attribs.getTypedEntry<AtomsCore::Vector3Metadata>("rotate")->value();
AtomsCore::Vector3 scale = attribs.getTypedEntry<AtomsCore::Vector3Metadata>("scale")->value();
AtomsCore::Vector3 translate = attribs.getTypedEntry<AtomsCore::Vector3Metadata>("translate")->value();
AtomsPtr<AtomsCore::MapMetadata> rotateOverrideMap = attribs.getTypedEntry<AtomsCore::MapMetadata>("rotate_override");
AtomsPtr<AtomsCore::MapMetadata> scaleOverrideMap = attribs.getTypedEntry<AtomsCore::MapMetadata>("scale_override");
AtomsPtr<AtomsCore::MapMetadata> translateOverrideMap = attribs.getTypedEntry<AtomsCore::MapMetadata>("translate_override");
AtomsPtr<AtomsCore::MapMetadata> weightOverrideMap = attribs.getTypedEntry<AtomsCore::MapMetadata>("weight_override");
const std::string rotateOverrideName = name() + "@rotate";
const std::string scaleOverrideName = name() + "@scale";
const std::string translateOverrideName = name() + "@translate";
const std::string weightOverrideName = name() + "@weight";
const std::string operatorName = name() + "Op";
AtomsUtils::parallel_for(AtomsUtils::ParallelForRange(0, agents.size()),
[&](const AtomsUtils::ParallelForRange& r TASK_PARTITION_EXTRA_ARGS)
{
for (unsigned int i = r.begin(); i < r.end(); i++)
{
Atoms::Agent* agent = agents[i];
if (!agent)
continue;
AtomsPtr<AtomsCore::StringMetadata> jointTransformOperatorNamePtr = agent->metadata().getTypedEntry<AtomsCore::StringMetadata>(operatorName);
if (!jointTransformOperatorNamePtr)
{
continue;
}
AtomsGraph::Node *node = agent->network().manager().getNode(jointTransformOperatorNamePtr->get());
if (node == nullptr)
{
AtomsUtils::Logger::warning() << "Could not find joint transform operator";
continue;
}
auto agent_type = agent->agentType();
if (!agent_type)
continue;
auto& skeleton = agent_type->skeleton();
double weightTmp = getAttributePerAgent(weight, weightOverrideMap.get(), agent->groupIdStr()->get(), agent->metadata(), weightOverrideName);
AtomsCore::Vector3 rotateTmp = getAttributePerAgent(rotate, rotateOverrideMap.get(), agent->groupIdStr()->get(), agent->metadata(), rotateOverrideName);
AtomsCore::Vector3 scaleTmp = getAttributePerAgent(scale, scaleOverrideMap.get(), agent->groupIdStr()->get(), agent->metadata(), scaleOverrideName);
AtomsCore::Vector3 translateTmp = getAttributePerAgent(translate, translateOverrideMap.get(), agent->groupIdStr()->get(), agent->metadata(), translateOverrideName);
node->getInputPort<AtomsGraph::VectorPort>("translate")->set(translateTmp);
node->getInputPort<AtomsGraph::VectorPort>("rotate")->set(rotateTmp);
node->getInputPort<AtomsGraph::VectorPort>("scale")->set(scaleTmp);
node->getInputPort<AtomsGraph::DoublePort>("weight")->set(weightTmp);
}
}
);
}
Atoms::BehaviourModule* MyJointTransformModule::creator(const std::string& parameter)
{
return new MyJointTransformModule();
}
|
And the module is exposed to Unreal by a custom component
Code Block | ||
---|---|---|
| ||
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/AtomsBehaviourComponent.h"
#include "AtomsUnrealUtils.h"
#include "MyJointTransformComponent.generated.h"
/**
*
*/
UCLASS(ClassGroup = (AtomsBehaviours), meta = (BlueprintSpawnableComponent))
class UMyJointTransformComponent : public UAtomsBehaviourComponent
{
GENERATED_BODY()
public:
/** The joint name */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
FName jointName;
/** The joint name */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
TMap<int32, FName> jointNameOverride;
/** Apply the transformation as an offset to the current one */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
bool offset;
/** Apply the transformation as an offset to the current one */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
TMap<int32, bool> offsetOverride;
/** Translation value */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
FVector translate;
/** Translation value */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
TMap<int32, FVector> translateOverride;
/** Rotation value in degrees */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
FVector rotate;
/** Rotation value in degrees */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
TMap<int32, FVector> rotateOverride;
/** Scale value */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
FVector scale;
/** Scale value */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
TMap<int32, FVector> scaleOverride;
/** The rotation order */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
int32 rotationOrder;
/** The rotation order */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
TMap<int32, int32> rotationOrderOverride;
/** Apply the transformation in world space */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
bool worldSpace;
/** Apply the transformation in world space */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
TMap<int32, bool> worldSpaceOverride;
/** The weight */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour", meta = (UIMin = "0.00", UIMax = "1.00"))
float weight;
/** The weight */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Interp, Category = "Behaviour")
TMap<int32, float> weightOverride;
UMyJointTransformComponent();
~UMyJointTransformComponent();
virtual void GetAtomsAttributes(AtomsPtr<AtomsCore::MapMetadata>& attributes) override;
/** The joint name */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetJointName(const FName& Value);
/** The joint name */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetJointNameOverride(const FName& Value, const int32 AgentId);
/** Remove agent override */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void RemoveJointNameOverride(const int32 AgentId);
/** Apply the transformation as an offset to the current one */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetOffset(const bool Value);
/** Apply the transformation as an offset to the current one */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetOffsetOverride(const bool Value, const int32 AgentId);
/** Remove agent override */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void RemoveOffsetOverride(const int32 AgentId);
/** Translation value */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetTranslate(const FVector& Value);
/** Translation value */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetTranslateOverride(const FVector& Value, const int32 AgentId);
/** Remove agent override */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void RemoveTranslateOverride(const int32 AgentId);
/** Rotation value in degrees */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetRotate(const FVector& Value);
/** Rotation value in degrees */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetRotateOverride(const FVector& Value, const int32 AgentId);
/** Remove agent override */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void RemoveRotateOverride(const int32 AgentId);
/** Scale value */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetScale(const FVector& Value);
/** Scale value */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetScaleOverride(const FVector& Value, const int32 AgentId);
/** Remove agent override */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void RemoveScaleOverride(const int32 AgentId);
/** The rotation order */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetRotationOrder(const int32 Value);
/** The rotation order */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetRotationOrderOverride(const int32 Value, const int32 AgentId);
/** Remove agent override */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void RemoveRotationOrderOverride(const int32 AgentId);
/** Apply the transformation in world space */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetWorldSpace(const bool Value);
/** Apply the transformation in world space */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetWorldSpaceOverride(const bool Value, const int32 AgentId);
/** Remove agent override */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void RemoveWorldSpaceOverride(const int32 AgentId);
/** The weight */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetWeight(const float Value);
/** The weight */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void SetWeightOverride(const float Value, const int32 AgentId);
/** Remove agent override */
UFUNCTION(BlueprintCallable, Category = "JointTransformBehaviourComponent", meta = (CallInEditor = "true"))
void RemoveWeightOverride(const int32 AgentId);
#if WITH_EDITOR
virtual void PreEditChange(UnrealProperty * PropertyAboutToChange) override;
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& e) override;
#endif
};
|
Code Block | ||
---|---|---|
| ||
#include "MyJointTransformComponent.h"
#include "Actors/AtomsAgentGroup.h"
#include "AtomsModuleGeneratorUtils.h"
#include "AtomsAttributeUtils.h"
UMyJointTransformComponent::UMyJointTransformComponent() : UAtomsBehaviourComponent()
{
AtomsBehaviourModule = "MyJointTransform";
jointName = "";
offset = true;
translate = FVector(0.0, 0.0, 0.0);
rotate = FVector(0.0, 0.0, 0.0);
scale = FVector(1.0, 1.0, 1.0);
rotationOrder = 0;
worldSpace = false;
weight = 1.0;
}
UMyJointTransformComponent::~UMyJointTransformComponent()
{
}
void UMyJointTransformComponent::GetAtomsAttributes(AtomsPtr<AtomsCore::MapMetadata>& attributes)
{
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(jointName, AtomsCore::StringMetadata, UAtomsAttributeUtils::ToString);
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META_OVERRIDE(jointName_override, jointNameOverride, AtomsCore::StringMetadata, UAtomsAttributeUtils::ToString);
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(offset, AtomsCore::BoolMetadata, );
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META_OVERRIDE(offset_override, offsetOverride, AtomsCore::BoolMetadata, );
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(translate, AtomsCore::Vector3Metadata, AtomsConverter::ToVector3);
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META_OVERRIDE(translate_override, translateOverride, AtomsCore::Vector3Metadata, AtomsConverter::ToVector3);
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(rotate, AtomsCore::Vector3Metadata, AtomsConverter::ToVector3);
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META_OVERRIDE(rotate_override, rotateOverride, AtomsCore::Vector3Metadata, AtomsConverter::ToVector3);
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(scale, AtomsCore::Vector3Metadata, AtomsConverter::ToVector3);
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META_OVERRIDE(scale_override, scaleOverride, AtomsCore::Vector3Metadata, AtomsConverter::ToVector3);
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(rotationOrder, AtomsCore::IntMetadata, );
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META_OVERRIDE(rotationOrder_override, rotationOrderOverride, AtomsCore::IntMetadata, );
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(worldSpace, AtomsCore::BoolMetadata, );
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META_OVERRIDE(worldSpace_override, worldSpaceOverride, AtomsCore::BoolMetadata, );
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(weight, AtomsCore::DoubleMetadata, );
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META_OVERRIDE(weight_override, weightOverride, AtomsCore::DoubleMetadata, );
}
#if WITH_EDITOR
void UMyJointTransformComponent::PreEditChange(UnrealProperty * PropertyAboutToChange)
{
if (!PropertyAboutToChange)
return;
Super::PreEditChange(PropertyAboutToChange);
auto PropertyName = (PropertyAboutToChange != NULL) ? PropertyAboutToChange->GetFName() : NAME_None;
}
void UMyJointTransformComponent::PostEditChangeProperty(FPropertyChangedEvent & e)
{
auto PropertyName = (e.Property != NULL) ? e.Property->GetFName() : NAME_None;
Super::PostEditChangeProperty(e);
}
#endif
void UMyJointTransformComponent::SetJointName(const FName& Value)
{
jointName = Value;
ATOMS_BEHAVIOUR_COMPONENT_GET_ATTRIBUTES()
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(jointName, AtomsCore::StringMetadata, UAtomsAttributeUtils::ToString);
}
void UMyJointTransformComponent::SetJointNameOverride(const FName& Value, const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_SET_META_OVERRIDE(jointName_override, jointNameOverride, AtomsCore::StringMetadata, UAtomsAttributeUtils::ToString, AgentId);
}
void UMyJointTransformComponent::RemoveJointNameOverride(const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_REMOVE_OVERRIDE(jointName_override, jointNameOverride, AgentId);
}
void UMyJointTransformComponent::SetOffset(const bool Value)
{
offset = Value;
ATOMS_BEHAVIOUR_COMPONENT_GET_ATTRIBUTES()
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(offset, AtomsCore::BoolMetadata, );
}
void UMyJointTransformComponent::SetOffsetOverride(const bool Value, const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_SET_META_OVERRIDE(offset_override, offsetOverride, AtomsCore::BoolMetadata, , AgentId);
}
void UMyJointTransformComponent::RemoveOffsetOverride(const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_REMOVE_OVERRIDE(offset_override, offsetOverride, AgentId);
}
void UMyJointTransformComponent::SetTranslate(const FVector& Value)
{
translate = Value;
ATOMS_BEHAVIOUR_COMPONENT_GET_ATTRIBUTES()
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(translate, AtomsCore::Vector3Metadata, AtomsConverter::ToVector3);
}
void UMyJointTransformComponent::SetTranslateOverride(const FVector& Value, const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_SET_META_OVERRIDE(translate_override, translateOverride, AtomsCore::Vector3Metadata, AtomsConverter::ToVector3, AgentId);
}
void UMyJointTransformComponent::RemoveTranslateOverride(const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_REMOVE_OVERRIDE(translate_override, translateOverride, AgentId);
}
void UMyJointTransformComponent::SetRotate(const FVector& Value)
{
rotate = Value;
ATOMS_BEHAVIOUR_COMPONENT_GET_ATTRIBUTES()
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(rotate, AtomsCore::Vector3Metadata, AtomsConverter::ToVector3);
}
void UMyJointTransformComponent::SetRotateOverride(const FVector& Value, const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_SET_META_OVERRIDE(rotate_override, rotateOverride, AtomsCore::Vector3Metadata, AtomsConverter::ToVector3, AgentId);
}
void UMyJointTransformComponent::RemoveRotateOverride(const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_REMOVE_OVERRIDE(rotate_override, rotateOverride, AgentId);
}
void UMyJointTransformComponent::SetScale(const FVector& Value)
{
scale = Value;
ATOMS_BEHAVIOUR_COMPONENT_GET_ATTRIBUTES()
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(scale, AtomsCore::Vector3Metadata, AtomsConverter::ToVector3);
}
void UMyJointTransformComponent::SetScaleOverride(const FVector& Value, const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_SET_META_OVERRIDE(scale_override, scaleOverride, AtomsCore::Vector3Metadata, AtomsConverter::ToVector3, AgentId);
}
void UMyJointTransformComponent::RemoveScaleOverride(const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_REMOVE_OVERRIDE(scale_override, scaleOverride, AgentId);
}
void UMyJointTransformComponent::SetRotationOrder(const int32 Value)
{
rotationOrder = Value;
ATOMS_BEHAVIOUR_COMPONENT_GET_ATTRIBUTES()
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(rotationOrder, AtomsCore::IntMetadata, );
}
void UMyJointTransformComponent::SetRotationOrderOverride(const int32 Value, const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_SET_META_OVERRIDE(rotationOrder_override, rotationOrderOverride, AtomsCore::IntMetadata, , AgentId);
}
void UMyJointTransformComponent::RemoveRotationOrderOverride(const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_REMOVE_OVERRIDE(rotationOrder_override, rotationOrderOverride, AgentId);
}
void UMyJointTransformComponent::SetWorldSpace(const bool Value)
{
worldSpace = Value;
ATOMS_BEHAVIOUR_COMPONENT_GET_ATTRIBUTES()
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(worldSpace, AtomsCore::BoolMetadata, );
}
void UMyJointTransformComponent::SetWorldSpaceOverride(const bool Value, const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_SET_META_OVERRIDE(worldSpace_override, worldSpaceOverride, AtomsCore::BoolMetadata, , AgentId);
}
void UMyJointTransformComponent::RemoveWorldSpaceOverride(const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_REMOVE_OVERRIDE(worldSpace_override, worldSpaceOverride, AgentId);
}
void UMyJointTransformComponent::SetWeight(const float Value)
{
weight = Value;
ATOMS_BEHAVIOUR_COMPONENT_GET_ATTRIBUTES()
ATOMS_BEHAVIOUR_COMPONENT_CONVERT_META(weight, AtomsCore::DoubleMetadata, );
}
void UMyJointTransformComponent::SetWeightOverride(const float Value, const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_SET_META_OVERRIDE(weight_override, weightOverride, AtomsCore::DoubleMetadata, , AgentId);
}
void UMyJointTransformComponent::RemoveWeightOverride(const int32 AgentId)
{
ATOMS_BEHAVIOUR_COMPONENT_REMOVE_OVERRIDE(weight_override, weightOverride, AgentId);
} |
Finally, the operator and the module is registered to Atoms
Code Block | ||
---|---|---|
| ||
#include "MyJointTransformModule.h" #include "MyJointTransformOperator.h" #include <AtomsGraph/NodeFactory.h> #include <Atoms/BehaviourModules.h> void FAtomsUnrealTestGameModule::StartupModule() { AtomsGraph::NodeFactory& manager = AtomsGraph::NodeFactory::instance(); manager.registerNode(JointConstraintOperatorMyJointTransformOperator::staticTypeStr(), &JointConstraintOperatorMyJointTransformOperator::creator); Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance(); moduleManager.registerBehaviourModule("SimpleJointOffsetMyJointTransform", &JointOffsetModuleMyJointTransformModule::creator, Atoms::JointOffsetModuleBehaviourModules::kNative); return true; } void FAtomsDemoGameModuleFAtomsUnrealTestGameModule::ShutdownModule() { AtomsUtils::Logger::info() << "Unloading Joint offset plugin"; // Deregister the node from the node factory AtomsGraph::NodeFactory& manager = AtomsGraph::NodeFactory::instance(); manager.deregisterNode(JointConstraintOperatorMyJointTransformOperator::staticTypeStr()); Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance(); moduleManager.deregisterBehaviourModule("SimpleJointOffsetMyJointTransform"); return true; } |