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.
...
Code Block | ||
---|---|---|
| ||
#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;
};
|
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(""); } |
...