/
Writing an Atoms operator (AtomsUnreal)
Writing an Atoms operator (AtomsUnreal)
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 operator adds an offset to a joint.
#pragma once
#include <AtomsGraph/Ports.h>
#include <Atoms/Globals.h>
#include <Atoms/Graph/Operator.h>
class MyJointTransformOperator : public Atoms::Operator
{
public:
NODE_STANDARD_MEMBERS
MyJointTransformOperator();
virtual ~MyJointTransformOperator();
virtual bool compute(const AtomsGraph::ComputeData* computeData) override;
virtual void reset() override;
private:
AtomsGraph::PosePort* m_inPose;
AtomsGraph::StringPort *m_inJointName;
AtomsGraph::LongPort *m_inRotationOrder;
AtomsGraph::BooleanPort *m_inWorldSpace;
AtomsGraph::BooleanPort *m_inOffset;
AtomsGraph::VectorPort *m_inTranslate;
AtomsGraph::VectorPort *m_inRotate;
AtomsGraph::VectorPort *m_inScale;
AtomsGraph::DoublePort *m_inWeight;
int m_jointId;
bool m_first;
};
#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.
#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);
};
#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
// 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
};
#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
#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(MyJointTransformOperator::staticTypeStr(), &MyJointTransformOperator::creator);
Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance();
moduleManager.registerBehaviourModule("MyJointTransform", &MyJointTransformModule::creator, Atoms::BehaviourModules::kNative);
}
void FAtomsUnrealTestGameModule::ShutdownModule()
{
// Deregister the node from the node factory
AtomsGraph::NodeFactory& manager = AtomsGraph::NodeFactory::instance();
manager.deregisterNode(MyJointTransformOperator::staticTypeStr());
Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance();
moduleManager.deregisterBehaviourModule("MyJointTransform");
}
, multiple selections available,
Related content
Writing an Atoms operator
Writing an Atoms operator
More like this
Writing an Atoms graph node (AtomsUnreal)
Writing an Atoms graph node (AtomsUnreal)
More like this
Writing an Atoms graph node
Writing an Atoms graph node
More like this
Operators
Operators
More like this
Access agent data (AtomsUnreal)
Access agent data (AtomsUnreal)
More like this
Writing a Metadata Replicator module
Writing a Metadata Replicator module
More like this
Copyright © 2017, Toolchefs LTD.