Advertisement
Guest User

Untitled

a guest
Dec 26th, 2020
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 22.33 KB | None | 0 0
  1. #include "GameProject_precompiled.h"
  2. ////#pragma optimize("", off)
  3.  
  4. #include <AzCore/Serialization/EditContext.h>
  5. #include <AzCore/Serialization/SerializeContext.h>
  6. #include <EMotionFX/Source/ActorInstance.h>
  7. #include <EMotionFX/Source/AnimGraph.h>
  8. #include <EMotionFX/Source/AnimGraphManager.h>
  9. #include <EMotionFX/Source/Parameter/Parameter.h>
  10. #include <EMotionFX/Source/Parameter/FloatParameter.h>
  11. #include <EMotionFX/Source/Parameter/DefaultValueParameter.h>
  12. #include <EMotionFX/Source/Parameter/FloatSliderParameter.h>
  13.  
  14.  
  15.  
  16.  
  17. #include <EMotionFX/Source/ConstraintTransformRotationAngles.h>
  18. #include <EMotionFX/Source/DebugDraw.h>
  19. #include <EMotionFX/Source/EMotionFXConfig.h>
  20. #include <EMotionFX/Source/EventManager.h>
  21. #include <EMotionFX/Source/Node.h>
  22. #include <EMotionFX/Source/TransformData.h>
  23. #include <MCore/Source/AttributeVector2.h>
  24. #include <MCore/Source/AzCoreConversions.h>
  25. #include <MCore/Source/Compare.h>
  26.  
  27. #include "MyEFXNode.h"
  28.  
  29. namespace EMotionFX
  30. {
  31.  
  32.     AZ_CLASS_ALLOCATOR_IMPL(MyEFXNode, AnimGraphAllocator, 0)
  33.         AZ_CLASS_ALLOCATOR_IMPL(MyEFXNode::UniqueData, AnimGraphObjectUniqueDataAllocator, 0)
  34.  
  35.         MyEFXNode::MyEFXNode()
  36.         : AnimGraphNode()
  37.         , m_constraintRotation(AZ::Quaternion::CreateIdentity())
  38.         , m_postRotation(AZ::Quaternion::CreateIdentity())
  39.         , m_limitMin(-90.0f, -50.0f)
  40.         , m_limitMax(90.0f, 30.0f)
  41.         , m_followSpeed(0.75f)
  42.         , m_twistAxis(ConstraintTransformRotationAngles::AXIS_Y)
  43.         , m_limitsEnabled(false)
  44.         , m_smoothing(true)
  45.         , m_worldPos(AZ::Vector3::CreateZero())
  46.     {
  47.         // setup the input ports
  48.         InitInputPorts(4);
  49.         SetupInputPort("Pose", INPUTPORT_POSE, AttributePose::TYPE_ID, PORTID_INPUT_POSE);
  50.         SetupInputPortAsVector3("Goal Pos", INPUTPORT_GOALPOS, PORTID_INPUT_GOALPOS);
  51.         SetupInputPortAsNumber("Weight", INPUTPORT_WEIGHT, PORTID_INPUT_WEIGHT);
  52.         SetupInputPortAsVector3("DebugVec3", INPUTPORT_DEBUGVEC, PORTID_INPUT_DEBUGVEC);
  53.         // setup the output ports
  54.         InitOutputPorts(1);
  55.         SetupOutputPortAsPose("Output Pose", OUTPUTPORT_POSE, PORTID_OUTPUT_POSE);
  56.     }
  57.  
  58.     MyEFXNode::~MyEFXNode()
  59.     {
  60.     }
  61.  
  62.     void MyEFXNode::Reinit()
  63.     {
  64.         // add include #include <EMotionFX/Source/Parameter/FloatSliderParameter.h>
  65.         // add var def to class header EMotionFX::FloatSliderParameter fParam;
  66.  
  67.         // everytime then this node reinits it add param to theirs anim graph
  68.         // you can add a bunch of params here.
  69.         // and make a special dummy efx node what only fill graph with some sets of params
  70.         fParam.SetName("auto_parameter");
  71.         fParam.SetDescription("description");
  72.         fParam.SetDefaultValue(3.14f);
  73.         fParam.SetMaxValue(10.f);
  74.         fParam.SetMinValue(0.f);
  75.  
  76.    
  77.         mAnimGraph->AddParameter(&fParam);
  78.  
  79.         const size_t numAnimGraphInstances = mAnimGraph->GetNumAnimGraphInstances();
  80.         for (size_t i = 0; i < numAnimGraphInstances; ++i)
  81.         {
  82.             AnimGraphInstance* animGraphInstance = mAnimGraph->GetAnimGraphInstance(i);
  83.  
  84.             UniqueData* uniqueData = static_cast<UniqueData*>(FindUniqueNodeData(animGraphInstance));
  85.             if (uniqueData)
  86.             {
  87.                 uniqueData->mMustUpdate = true;
  88.             }
  89.  
  90.             OnUpdateUniqueData(animGraphInstance);
  91.         }
  92.  
  93.         AnimGraphNode::Reinit();
  94.     }
  95.  
  96.     bool MyEFXNode::InitAfterLoading(AnimGraph* animGraph)
  97.     {
  98.         if (!AnimGraphNode::InitAfterLoading(animGraph))
  99.         {
  100.             return false;
  101.         }
  102.  
  103.         InitInternalAttributesForAllInstances();
  104.  
  105.         Reinit();
  106.         return true;
  107.     }
  108.  
  109.     // get the palette name
  110.     const char* MyEFXNode::GetPaletteName() const
  111.     {
  112.         return "MyEFXNode";
  113.     }
  114.  
  115.     // get the category
  116.     AnimGraphObject::ECategory MyEFXNode::GetPaletteCategory() const
  117.     {
  118.         return AnimGraphObject::CATEGORY_CONTROLLERS;
  119.     }
  120.  
  121.     // pre-create unique data object
  122.     void MyEFXNode::OnUpdateUniqueData(AnimGraphInstance* animGraphInstance)
  123.     {
  124.         // find the unique data for this node, if it doesn't exist yet, create it
  125.         UniqueData* uniqueData = static_cast<UniqueData*>(animGraphInstance->FindUniqueObjectData(this));
  126.         if (uniqueData == nullptr)
  127.         {
  128.             uniqueData = aznew UniqueData(this, animGraphInstance);
  129.             animGraphInstance->RegisterUniqueObjectData(uniqueData);
  130.         }
  131.  
  132.         uniqueData->mMustUpdate = true;
  133.         UpdateUniqueData(animGraphInstance, uniqueData);
  134.     }
  135.  
  136.     // the main process method of the final node
  137.     void MyEFXNode::Output(AnimGraphInstance* animGraphInstance)
  138.     {
  139.         AnimGraphPose* outputPose;
  140.  
  141.        
  142.  
  143.             //bool AnimGraph::AddParameter(Parameter* parameter, const GroupParameter* parentGroup)
  144.  
  145.         // make sure we have at least an input pose, otherwise output the bind pose
  146.         if (GetInputPort(INPUTPORT_POSE).mConnection == nullptr)
  147.         {
  148.             RequestPoses(animGraphInstance);
  149.             outputPose = GetOutputPose(animGraphInstance, OUTPUTPORT_POSE)->GetValue();
  150.             ActorInstance* actorInstance = animGraphInstance->GetActorInstance();
  151.             outputPose->InitFromBindPose(actorInstance);
  152.             return;
  153.         }
  154.  
  155.         // get the weight
  156.         float weight = 1.0f;
  157.         if (GetInputPort(INPUTPORT_WEIGHT).mConnection)
  158.         {
  159.             OutputIncomingNode(animGraphInstance, GetInputNode(INPUTPORT_WEIGHT));
  160.             weight = GetInputNumberAsFloat(animGraphInstance, INPUTPORT_WEIGHT);
  161.             weight = MCore::Clamp<float>(weight, 0.0f, 1.0f);
  162.         }
  163.  
  164.         // if the weight is near zero, we can skip all calculations and act like a pass-trough node
  165.         if (weight < MCore::Math::epsilon || mDisabled)
  166.         {
  167.             OutputIncomingNode(animGraphInstance, GetInputNode(INPUTPORT_POSE));
  168.             RequestPoses(animGraphInstance);
  169.             outputPose = GetOutputPose(animGraphInstance, OUTPUTPORT_POSE)->GetValue();
  170.             const AnimGraphPose* inputPose = GetInputPose(animGraphInstance, INPUTPORT_POSE)->GetValue();
  171.             *outputPose = *inputPose;
  172.             UniqueData* uniqueData = static_cast<UniqueData*>(FindUniqueNodeData(animGraphInstance));
  173.             UpdateUniqueData(animGraphInstance, uniqueData); // update the unique data (lookup node indices when something changed)
  174.             uniqueData->mFirstUpdate = true;
  175.             return;
  176.         }
  177.  
  178.         // get the input pose and copy it over to the output pose
  179.         OutputIncomingNode(animGraphInstance, GetInputNode(INPUTPORT_POSE));
  180.         RequestPoses(animGraphInstance);
  181.         outputPose = GetOutputPose(animGraphInstance, OUTPUTPORT_POSE)->GetValue();
  182.         const AnimGraphPose* inputPose = GetInputPose(animGraphInstance, INPUTPORT_POSE)->GetValue();
  183.         *outputPose = *inputPose;
  184.  
  185.         //------------------------------------
  186.         // get the node indices to work on
  187.         //------------------------------------
  188.         UniqueData* uniqueData = static_cast<UniqueData*>(FindUniqueNodeData(animGraphInstance));
  189.         UpdateUniqueData(animGraphInstance, uniqueData); // update the unique data (lookup node indices when something changed)
  190.         if (uniqueData->mIsValid == false)
  191.         {
  192.             if (GetEMotionFX().GetIsInEditorMode())
  193.             {
  194.                 uniqueData->mMustUpdate = true;
  195.                 UpdateUniqueData(animGraphInstance, uniqueData);
  196.  
  197.                 if (uniqueData->mIsValid == false)
  198.                 {
  199.                     SetHasError(animGraphInstance, true);
  200.                 }
  201.             }
  202.             return;
  203.         }
  204.  
  205.         // there is no error
  206.         if (GetEMotionFX().GetIsInEditorMode())
  207.         {
  208.             SetHasError(animGraphInstance, false);
  209.         }
  210.  
  211.         // get the goal
  212.         OutputIncomingNode(animGraphInstance, GetInputNode(INPUTPORT_GOALPOS));
  213.         AZ::Vector3 goal = AZ::Vector3::CreateZero();
  214.         TryGetInputVector3(animGraphInstance, INPUTPORT_GOALPOS, goal);
  215.  
  216.         // get the debug vec
  217.         OutputIncomingNode(animGraphInstance, GetInputNode(INPUTPORT_DEBUGVEC));
  218.         AZ::Vector3 debugvec = AZ::Vector3::CreateZero();
  219.         TryGetInputVector3(animGraphInstance, INPUTPORT_DEBUGVEC, debugvec);
  220.  
  221.         ActorInstance* actorInstance = animGraphInstance->GetActorInstance();
  222.  
  223.         // get a shortcut to the local transform object
  224.         const uint32 nodeIndex = uniqueData->mNodeIndex;
  225.         // get start and end
  226.         const uint32 startNodeIndex = uniqueData->mStartNodeIndex;
  227.         const uint32 endNodeIndex = uniqueData->mEndNodeIndex;
  228.  
  229.         Pose& outTransformPose = outputPose->GetPose();
  230.         Transform globalTransform = outTransformPose.GetWorldSpaceTransform(nodeIndex);
  231.  
  232.         // get global start and end
  233.         Transform startGlobalTransform = outTransformPose.GetWorldSpaceTransform(startNodeIndex);
  234.         Transform endGlobalTransform = outTransformPose.GetWorldSpaceTransform(endNodeIndex);
  235.  
  236.         globalTransform = startGlobalTransform.Blend(endGlobalTransform, weight);
  237.         outTransformPose.SetWorldSpaceTransform(nodeIndex, globalTransform);
  238.         Skeleton* skeleton = actorInstance->GetActor()->GetSkeleton();
  239.  
  240.         //// Prevent invalid float values inside the LookAt matrix construction when both position and goal are the same
  241.         //const AZ::Vector3 diff = globalTransform.mPosition - goal;
  242.         //if (diff.GetLengthSq() < AZ::g_fltEps)
  243.         //{
  244.         //  goal += AZ::Vector3(0.0f, 0.000001f, 0.0f);
  245.         //}
  246.  
  247.         //// calculate the lookat transform
  248.         //// TODO: a quaternion lookat function would be nicer, so that there are no matrix operations involved
  249.         //MCore::Matrix lookAt;
  250.         //lookAt.LookAt(globalTransform.mPosition, goal, AZ::Vector3(0.0f, 0.0f, 1.0f));
  251.         //MCore::Quaternion destRotation = lookAt.Transposed(); // implicit matrix to quat conversion
  252.  
  253.         //                                                    // apply the post rotation
  254.         //MCore::Quaternion postRotation = MCore::AzQuatToEmfxQuat(m_postRotation);
  255.         //destRotation = destRotation * postRotation;
  256.  
  257.         //// get the constraint rotation
  258.         //const MCore::Quaternion constraintRotation = MCore::AzQuatToEmfxQuat(m_constraintRotation);
  259.  
  260.         //if (m_limitsEnabled)
  261.         //{
  262.         //  // calculate the delta between the bind pose rotation and current target rotation and constraint that to our limits
  263.         //  const uint32 parentIndex = skeleton->GetNode(nodeIndex)->GetParentIndex();
  264.         //  MCore::Quaternion parentRotationGlobal;
  265.         //  MCore::Quaternion bindRotationLocal;
  266.         //  if (parentIndex != MCORE_INVALIDINDEX32)
  267.         //  {
  268.         //      parentRotationGlobal = inputPose->GetPose().GetWorldSpaceTransform(parentIndex).mRotation;
  269.         //      bindRotationLocal = actorInstance->GetTransformData()->GetBindPose()->GetLocalSpaceTransform(parentIndex).mRotation;
  270.         //  }
  271.         //  else
  272.         //  {
  273.         //      parentRotationGlobal.Identity();
  274.         //      bindRotationLocal.Identity();
  275.         //  }
  276.  
  277.         //  const MCore::Quaternion destRotationLocal = destRotation * parentRotationGlobal.Conjugated();
  278.         //  const MCore::Quaternion deltaRotLocal = destRotationLocal * bindRotationLocal.Conjugated();
  279.  
  280.         //  // setup the constraint and execute it
  281.         //  // the limits are relative to the bind pose in local space
  282.         //  ConstraintTransformRotationAngles constraint; // TODO: place this inside the unique data? would be faster, but takes more memory, or modify the constraint to support internal modification of a transform directly
  283.         //  constraint.SetMinRotationAngles(m_limitMin);
  284.         //  constraint.SetMaxRotationAngles(m_limitMax);
  285.         //  constraint.SetMinTwistAngle(0.0f);
  286.         //  constraint.SetMaxTwistAngle(0.0f);
  287.         //  constraint.SetTwistAxis(m_twistAxis);
  288.         //  constraint.GetTransform().mRotation = (deltaRotLocal * constraintRotation.Conjugated());
  289.         //  constraint.Execute();
  290.  
  291.         //  if (GetEMotionFX().GetIsInEditorMode() && GetCanVisualize(animGraphInstance))
  292.         //  {
  293.         //      MCore::Matrix offset = (postRotation.Inversed() * bindRotationLocal * constraintRotation * parentRotationGlobal).ToMatrix();
  294.         //      offset.SetTranslation(globalTransform.mPosition);
  295.         //      constraint.DebugDraw(actorInstance, offset, GetVisualizeColor(), 0.5f);
  296.         //  }
  297.  
  298.         //  // convert back into world space
  299.         //  destRotation = (bindRotationLocal * (constraint.GetTransform().mRotation * constraintRotation)) * parentRotationGlobal;
  300.         //}
  301.  
  302.         //// init the rotation quaternion to the initial rotation
  303.         //if (uniqueData->mFirstUpdate)
  304.         //{
  305.         //  uniqueData->mRotationQuat = destRotation;
  306.         //  uniqueData->mFirstUpdate = false;
  307.         //}
  308.  
  309.         //// interpolate between the current rotation and the destination rotation
  310.         //if (m_smoothing)
  311.         //{
  312.         //  const float speed = m_followSpeed * uniqueData->mTimeDelta * 10.0f;
  313.         //  if (speed < 1.0f)
  314.         //  {
  315.         //      uniqueData->mRotationQuat = uniqueData->mRotationQuat.Slerp(destRotation, speed);
  316.         //  }
  317.         //  else
  318.         //  {
  319.         //      uniqueData->mRotationQuat = destRotation;
  320.         //  }
  321.         //}
  322.         //else
  323.         //{
  324.         //  uniqueData->mRotationQuat = destRotation;
  325.         //}
  326.  
  327.         //uniqueData->mRotationQuat.Normalize();
  328.         //globalTransform.mRotation = uniqueData->mRotationQuat;
  329.  
  330.         //// only blend when needed
  331.         //if (weight < 0.999f)
  332.         //{
  333.         //  outTransformPose.SetWorldSpaceTransform(nodeIndex, globalTransform);
  334.  
  335.         //  const Pose& inputTransformPose = inputPose->GetPose();
  336.         //  Transform finalTransform = inputTransformPose.GetLocalSpac eTransform(nodeIndex);
  337.         //  finalTransform.Blend(outTransformPose.GetLocalSpaceTransform(nodeIndex), weight);
  338.  
  339.         //  outTransformPose.SetLocalSpaceTransform(nodeIndex, finalTransform);
  340.         //}
  341.         //else
  342.         //{
  343.         //  outTransformPose.SetWorldSpaceTransform(nodeIndex, globalTransform);
  344.         //}
  345.  
  346.         // perform some debug rendering
  347.         //if (GetEMotionFX().GetIsInEditorMode() && GetCanVisualize(animGraphInstance))
  348.         if (GetEMotionFX().GetIsInEditorMode() && GetCanVisualize(animGraphInstance))
  349.         {
  350.             const float s = animGraphInstance->GetVisualizeScale() * actorInstance->GetVisualizeScale();
  351.  
  352.             DebugDraw& debugDraw = GetDebugDraw();
  353.             DebugDraw::ActorInstanceData* drawData = debugDraw.GetActorInstanceData(animGraphInstance->GetActorInstance());
  354.  
  355.             drawData->Lock();
  356.             drawData->Clear();
  357.             drawData->DrawLine(goal - AZ::Vector3(s, 0, 0), goal + AZ::Vector3(s, 0, 0), mVisualizeColor);
  358.             drawData->DrawLine(goal - AZ::Vector3(0, s, 0), goal + AZ::Vector3(0, s, 0), mVisualizeColor);
  359.             drawData->DrawLine(goal - AZ::Vector3(0, 0, s), goal + AZ::Vector3(0, 0, s), mVisualizeColor);
  360.             drawData->DrawLine(globalTransform.mPosition, goal, mVisualizeColor);
  361.             drawData->DrawLine(globalTransform.mPosition, globalTransform.mPosition + globalTransform.mRotation.CalcUpAxis() * s * 50.0f, AZ::Color(0.0f, 0.0f, 1.0f, 1.0f));
  362.             drawData->DrawWireframeSphere(debugvec, s * 1.0f, AZ::Color(1.0f, 1.0f, 1.0f, 1.0f), AZ::Quaternion::CreateIdentity());
  363.             drawData->Unlock();
  364.         }
  365.     }
  366.  
  367.     // update the unique data
  368.     void MyEFXNode::UpdateUniqueData(AnimGraphInstance* animGraphInstance, UniqueData* uniqueData)
  369.     {
  370.         // update the unique data if needed
  371.         if (uniqueData->mMustUpdate)
  372.         {
  373.             ActorInstance* actorInstance = animGraphInstance->GetActorInstance();
  374.             Actor* actor = actorInstance->GetActor();
  375.  
  376.             // don't update the next time again
  377.             uniqueData->mMustUpdate = false;
  378.  
  379.             // get the node
  380.             uniqueData->mNodeIndex = MCORE_INVALIDINDEX32;
  381.             uniqueData->mIsValid = false;
  382.  
  383.             if (m_targetNodeName.empty())
  384.             {
  385.                 return;
  386.             }
  387.  
  388.             if (m_startNodeName.empty())
  389.             {
  390.                 return;
  391.             }
  392.  
  393.             if (m_endNodeName.empty())
  394.             {
  395.                 return;
  396.             }
  397.  
  398.             const Node* targetNode = actor->GetSkeleton()->FindNodeByName(m_targetNodeName.c_str());
  399.             if (!targetNode)
  400.             {
  401.                 return;
  402.             }
  403.  
  404.             const Node* startNode = actor->GetSkeleton()->FindNodeByName(m_startNodeName.c_str());
  405.             if (!startNode)
  406.             {
  407.                 return;
  408.             }
  409.  
  410.             const Node* endNode = actor->GetSkeleton()->FindNodeByName(m_endNodeName.c_str());
  411.             if (!endNode)
  412.             {
  413.                 return;
  414.             }
  415.  
  416.  
  417.             uniqueData->mNodeIndex = targetNode->GetNodeIndex();
  418.             uniqueData->mStartNodeIndex = startNode->GetNodeIndex();
  419.             uniqueData->mEndNodeIndex = endNode->GetNodeIndex();
  420.  
  421.  
  422.             uniqueData->mIsValid = true;
  423.         }
  424.     }
  425.  
  426.     // update
  427.     void MyEFXNode::Update(AnimGraphInstance* animGraphInstance, float timePassedInSeconds)
  428.     {
  429.         // update the weight node
  430.         AnimGraphNode* weightNode = GetInputNode(INPUTPORT_WEIGHT);
  431.         if (weightNode)
  432.         {
  433.             UpdateIncomingNode(animGraphInstance, weightNode, timePassedInSeconds);
  434.         }
  435.  
  436.         // update the goal node
  437.         AnimGraphNode* goalNode = GetInputNode(INPUTPORT_GOALPOS);
  438.         if (goalNode)
  439.         {
  440.             UpdateIncomingNode(animGraphInstance, goalNode, timePassedInSeconds);
  441.         }
  442.  
  443.         // update the debugvec
  444.         AnimGraphNode* debugvecNode = GetInputNode(INPUTPORT_DEBUGVEC);
  445.         if (debugvecNode)
  446.         {
  447.             UpdateIncomingNode(animGraphInstance, debugvecNode, timePassedInSeconds);
  448.         }
  449.  
  450.         // update the pose node
  451.         UniqueData* uniqueData = static_cast<UniqueData*>(animGraphInstance->FindUniqueObjectData(this));
  452.         AnimGraphNode* inputNode = GetInputNode(INPUTPORT_POSE);
  453.         if (inputNode)
  454.         {
  455.             UpdateIncomingNode(animGraphInstance, inputNode, timePassedInSeconds);
  456.  
  457.             // update the sync track
  458.             uniqueData->Init(animGraphInstance, inputNode);
  459.         }
  460.         else
  461.         {
  462.             uniqueData->Clear();
  463.         }
  464.  
  465.         uniqueData->mTimeDelta = timePassedInSeconds;
  466.     }
  467.  
  468.     AZ::Crc32 MyEFXNode::GetLimitWidgetsVisibility() const
  469.     {
  470.         return m_limitsEnabled ? AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
  471.     }
  472.  
  473.     AZ::Crc32 MyEFXNode::GetFollowSpeedVisibility() const
  474.     {
  475.         return m_smoothing ? AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
  476.     }
  477.  
  478.     void MyEFXNode::SetTargetNodeName(const AZStd::string& targetNodeName)
  479.     {
  480.         m_targetNodeName = targetNodeName;
  481.     }
  482.  
  483.     void MyEFXNode::SetStartNodeName(const AZStd::string& startNodeName)
  484.     {
  485.         m_startNodeName = startNodeName;
  486.     }
  487.  
  488.     void MyEFXNode::SetEndNodeName(const AZStd::string& endNodeName)
  489.     {
  490.         m_endNodeName = endNodeName;
  491.     }
  492.  
  493.     void MyEFXNode::SetConstraintRotation(const AZ::Quaternion& constraintRotation)
  494.     {
  495.         m_constraintRotation = constraintRotation;
  496.     }
  497.  
  498.     void MyEFXNode::SetPostRotation(const AZ::Quaternion& postRotation)
  499.     {
  500.         m_postRotation = postRotation;
  501.     }
  502.  
  503.     void MyEFXNode::SetLimitMin(const AZ::Vector2& limitMin)
  504.     {
  505.         m_limitMin = limitMin;
  506.     }
  507.  
  508.     void MyEFXNode::SetLimitMax(const AZ::Vector2& limitMax)
  509.     {
  510.         m_limitMax = limitMax;
  511.     }
  512.  
  513.     void MyEFXNode::SetFollowSpeed(float followSpeed)
  514.     {
  515.         m_followSpeed = followSpeed;
  516.     }
  517.  
  518.     void MyEFXNode::SetTwistAxis(ConstraintTransformRotationAngles::EAxis twistAxis)
  519.     {
  520.         m_twistAxis = twistAxis;
  521.     }
  522.  
  523.     void MyEFXNode::SetLimitsEnabled(bool limitsEnabled)
  524.     {
  525.         m_limitsEnabled = limitsEnabled;
  526.     }
  527.  
  528.     void MyEFXNode::SetSmoothingEnabled(bool smoothingEnabled)
  529.     {
  530.         m_smoothing = smoothingEnabled;
  531.     }
  532.  
  533.     void MyEFXNode::Reflect(AZ::ReflectContext* context)
  534.     {
  535.         AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  536.         if (!serializeContext)
  537.         {
  538.             return;
  539.         }
  540.  
  541.         serializeContext->Class<MyEFXNode, AnimGraphNode>()
  542.             ->Version(2)
  543.             ->Field("targetNodeName", &MyEFXNode::m_targetNodeName)
  544.             ->Field("startNodeName", &MyEFXNode::m_startNodeName)
  545.             ->Field("endNodeName", &MyEFXNode::m_endNodeName)
  546.             ->Field("postRotation", &MyEFXNode::m_postRotation)
  547.             ->Field("limitsEnabled", &MyEFXNode::m_limitsEnabled)
  548.             ->Field("limitMin", &MyEFXNode::m_limitMin)
  549.             ->Field("limitMax", &MyEFXNode::m_limitMax)
  550.             ->Field("constraintRotation", &MyEFXNode::m_constraintRotation)
  551.             ->Field("twistAxis", &MyEFXNode::m_twistAxis)
  552.             ->Field("smoothing", &MyEFXNode::m_smoothing)
  553.             ->Field("followSpeed", &MyEFXNode::m_followSpeed);
  554.  
  555.         AZ::EditContext* editContext = serializeContext->GetEditContext();
  556.         if (!editContext)
  557.         {
  558.             return;
  559.         }
  560.  
  561.         auto root = editContext->Class<MyEFXNode>("MyEFXNode", "MyEFXNode At attributes");
  562.         root->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  563.             ->Attribute(AZ::Edit::Attributes::AutoExpand, "")
  564.             ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
  565.             ->DataElement(AZ_CRC("ActorNode", 0x35d9eb50), &MyEFXNode::m_targetNodeName, "Node", "The node to apply the lookat to. For example the head.")
  566.             ->Attribute(AZ::Edit::Attributes::ChangeNotify, &MyEFXNode::Reinit)
  567.             ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  568.             ->DataElement(AZ_CRC("ActorNode", 0x35d9eb50), &MyEFXNode::m_startNodeName, "StartNode", "The node to apply the lookat to. For example the head.")
  569.             ->Attribute(AZ::Edit::Attributes::ChangeNotify, &MyEFXNode::Reinit)
  570.             ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  571.             ->DataElement(AZ_CRC("ActorNode", 0x35d9eb50), &MyEFXNode::m_endNodeName, "EndNode", "The node to apply the lookat to. For example the head.")
  572.             ->Attribute(AZ::Edit::Attributes::ChangeNotify, &MyEFXNode::Reinit)
  573.             ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  574.             ->DataElement(AZ::Edit::UIHandlers::Default, &MyEFXNode::m_postRotation, "Post rotation", "The relative rotation applied after solving.");
  575.  
  576.         root->ClassElement(AZ::Edit::ClassElements::Group, "Rotation Limits")
  577.             ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  578.             ->DataElement(AZ::Edit::UIHandlers::Default, &MyEFXNode::m_limitsEnabled, "Enable limits", "Enable rotational limits?")
  579.             ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  580.             ->DataElement(AZ::Edit::UIHandlers::Default, &MyEFXNode::m_limitMin, "Yaw/pitch min", "The minimum rotational yaw and pitch angle limits, in degrees.")
  581.             ->Attribute(AZ::Edit::Attributes::Visibility, &MyEFXNode::GetLimitWidgetsVisibility)
  582.             ->Attribute(AZ::Edit::Attributes::Min, AZ::Vector2(-90.0f, -90.0f))
  583.             ->Attribute(AZ::Edit::Attributes::Max, AZ::Vector2(90.0f, 90.0f))
  584.             ->DataElement(AZ::Edit::UIHandlers::Default, &MyEFXNode::m_limitMax, "Yaw/pitch max", "The maximum rotational yaw and pitch angle limits, in degrees.")
  585.             ->Attribute(AZ::Edit::Attributes::Visibility, &MyEFXNode::GetLimitWidgetsVisibility)
  586.             ->Attribute(AZ::Edit::Attributes::Min, AZ::Vector2(-90.0f, -90.0f))
  587.             ->Attribute(AZ::Edit::Attributes::Max, AZ::Vector2(90.0f, 90.0f))
  588.             ->DataElement(AZ::Edit::UIHandlers::Default, &MyEFXNode::m_constraintRotation, "Constraint rotation", "A rotation that rotates the constraint space.")
  589.             ->Attribute(AZ::Edit::Attributes::Visibility, &MyEFXNode::GetLimitWidgetsVisibility)
  590.             ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MyEFXNode::m_twistAxis, "Roll axis", "The axis used for twist/roll.")
  591.             ->Attribute(AZ::Edit::Attributes::Visibility, &MyEFXNode::GetLimitWidgetsVisibility);
  592.  
  593.         root->ClassElement(AZ::Edit::ClassElements::Group, "Smoothing")
  594.             ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  595.             ->DataElement(AZ::Edit::UIHandlers::Default, &MyEFXNode::m_smoothing, "Enable smoothing", "Enable rotation smoothing, which is controlled by the follow speed setting.")
  596.             ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  597.             ->DataElement(AZ::Edit::UIHandlers::Default, &MyEFXNode::m_followSpeed, "Follow speed", "The speed factor at which to follow the goal. A value near zero meaning super slow and a value of 1 meaning instant following.")
  598.             ->Attribute(AZ::Edit::Attributes::Visibility, &MyEFXNode::GetFollowSpeedVisibility)
  599.             ->Attribute(AZ::Edit::Attributes::Min, 0.05f)
  600.             ->Attribute(AZ::Edit::Attributes::Max, 1.0);
  601.     }
  602. } // namespace EMotionFX
  603.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement