123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <Tests/AnimGraphFixture.h>
- #include <EMotionFX/Source/AnimGraph.h>
- #include <EMotionFX/Source/AnimGraphBindPoseNode.h>
- #include <EMotionFX/Source/AnimGraphNode.h>
- #include <EMotionFX/Source/AnimGraphStateMachine.h>
- #include <EMotionFX/Source/BlendTree.h>
- #include <EMotionFX/Source/BlendTreeParameterNode.h>
- #include <EMotionFX/Source/BlendTreeTwoLinkIKNode.h>
- #include <EMotionFX/Source/EMotionFXManager.h>
- #include <EMotionFX/Source/Parameter/FloatSliderParameter.h>
- #include <EMotionFX/Source/Parameter/Vector3Parameter.h>
- #include <EMotionFX/Source/Parameter/RotationParameter.h>
- #include <EMotionFX/Source/Skeleton.h>
- #include <EMotionFX/Source/Motion.h>
- #include <EMotionFX/Source/TransformData.h>
- #include <EMotionFX/Source/BlendTreeVector3ComposeNode.h>
- #include <Tests/JackGraphFixture.h>
- namespace EMotionFX
- {
- struct BlendTreeTwoLinkIKNodeTestsData
- {
- AZStd::string m_testJointName;
- std::vector<AZStd::string> m_linkedJointNames;
- std::vector<std::vector<float>> m_reachablePositions;
- std::vector<std::vector<float>> m_unreachablePositions;
- std::vector<std::vector<float>> m_rotations;
- std::vector<float> m_bendDirPosition;
- std::vector<AZStd::string> m_alignToNodeNames;
- };
- class BlendTreeTwoLinkIKNodeFixture
- : public JackGraphFixture
- , public ::testing::WithParamInterface<testing::tuple<bool, BlendTreeTwoLinkIKNodeTestsData>>
- {
- public:
- using NodeAlignmentData = AZStd::pair<AZStd::string, int>;
- void ConstructGraph() override
- {
- JackGraphFixture::ConstructGraph();
- m_param = testing::get<1>(GetParam());
- m_jackSkeleton = m_actor->GetSkeleton();
- /*
- Blend tree in animgraph:
- +------------+
- |bindPoseNode|---+
- +------------+ | +-------------+
- +--->| | +---------+
- |twoLinkIKNode|--->|finalNode|
- +-----------+ +--->| | +---------+
- |m_paramNode|---+ +-------------+
- +-----------+
- */
- AddParameter<FloatSliderParameter>("WeightParam", 0.0f);
- AddParameter<Vector3Parameter>("GoalPosParam", AZ::Vector3(0.0f, 0.0f, 0.0f));
- AddParameter<RotationParameter>("RotationParam", AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f));
- AddParameter<Vector3Parameter>("BendDirParam", AZ::Vector3(0.0f, 0.0f, 0.0f));
- AnimGraphBindPoseNode* bindPoseNode = aznew AnimGraphBindPoseNode();
- BlendTreeFinalNode* finalNode = aznew BlendTreeFinalNode();
- m_paramNode = aznew BlendTreeParameterNode();
- m_twoLinkIKNode = aznew BlendTreeTwoLinkIKNode();
- m_twoLinkIKNode->SetEndNodeName(m_param.m_testJointName);
- m_blendTree = aznew BlendTree();
- m_blendTree->AddChildNode(bindPoseNode);
- m_blendTree->AddChildNode(m_paramNode);
- m_blendTree->AddChildNode(m_twoLinkIKNode);
- m_blendTree->AddChildNode(finalNode);
-
- m_animGraph->GetRootStateMachine()->AddChildNode(m_blendTree);
- m_animGraph->GetRootStateMachine()->SetEntryState(m_blendTree);
- m_twoLinkIKNode->AddConnection(bindPoseNode, AnimGraphBindPoseNode::OUTPUTPORT_RESULT, BlendTreeTwoLinkIKNode::INPUTPORT_POSE);
- finalNode->AddConnection(m_twoLinkIKNode, BlendTreeTwoLinkIKNode::OUTPUTPORT_POSE, BlendTreeFinalNode::INPUTPORT_POSE);
- };
- bool PosePositionCompareClose(const AZ::Vector3& posA, const AZ::Vector3& posB, float tolerance)
- {
- if (!posA.IsClose(posB, tolerance))
- {
- return false;
- }
- return true;
- };
- bool PositionVectorsPointInSameDirection(const AZ::Vector3& posA, const AZ::Vector3& posB, const AZ::Vector3& posC, const AZ::Vector3& targetPos)
- {
- const AZ::Vector3& vecCtoB = (posB - posC).GetNormalized();
- const AZ::Vector3& vecBtoA = (posA - posB).GetNormalized();
- const AZ::Vector3& vecCtoTarget = (targetPos - posC).GetNormalized();
- const float dot1 = vecCtoB.Dot(vecBtoA);
- const float dot2 = vecCtoB.Dot(vecCtoTarget);
- return AZ::IsClose(dot1, 1.0f, 0.001f) &&
- AZ::IsClose(dot2, 1.0f, 0.001f);
- };
- template <class paramType, class inputType>
- void ParamSetValue(const AZStd::string& paramName, const inputType& value)
- {
- const AZ::Outcome<size_t> parameterIndex = m_animGraphInstance->FindParameterIndex(paramName);
- MCore::Attribute* param = m_animGraphInstance->GetParameterValue(static_cast<AZ::u32>(parameterIndex.GetValue()));
- paramType* typeParam = static_cast<paramType*>(param);
- typeParam->SetValue(value);
- }
- protected:
- BlendTree* m_blendTree = nullptr;
- BlendTreeParameterNode* m_paramNode = nullptr;
- BlendTreeTwoLinkIKNode* m_twoLinkIKNode = nullptr;
- BlendTreeTwoLinkIKNodeTestsData m_param;
-
- Skeleton* m_jackSkeleton = nullptr;
- private:
- template<class ParameterType, class ValueType>
- void AddParameter(const AZStd::string& name, const ValueType& defaultValue)
- {
- ParameterType* parameter = aznew ParameterType();
- parameter->SetName(name);
- parameter->SetDefaultValue(defaultValue);
- m_animGraph->AddParameter(parameter);
- }
- };
- TEST_P(BlendTreeTwoLinkIKNodeFixture, ReachablePositionsOutputCorrectPose)
- {
- // Set values for vector3 and twoLinkIKNode weight parameter
- m_twoLinkIKNode->AddConnection(m_paramNode, static_cast<uint16>(m_paramNode->FindOutputPortByName("WeightParam")->m_portId), BlendTreeTwoLinkIKNode::INPUTPORT_WEIGHT);
- m_twoLinkIKNode->AddConnection(m_paramNode,
- static_cast<uint16>(m_paramNode->FindOutputPortByName("GoalPosParam")->m_portId), BlendTreeTwoLinkIKNode::INPUTPORT_GOALPOS);
- GetEMotionFX().Update(1.0f / 60.0f);
- const float weight = testing::get<0>(GetParam());
- ParamSetValue<MCore::AttributeFloat, float>("WeightParam", weight);
- // Remeber specific joint's original position to compare with its new position later
- const Pose* jackPose = m_actorInstance->GetTransformData()->GetCurrentPose();
- size_t testJointIndex;
- m_jackSkeleton->FindNodeAndIndexByName(m_param.m_testJointName, testJointIndex);
- const AZ::Vector3& testJointPos = jackPose->GetModelSpaceTransform(testJointIndex).m_position;
- for (std::vector<float> goalPosXYZ : m_param.m_reachablePositions)
- {
- const float goalX = goalPosXYZ[0];
- const float goalY = goalPosXYZ[1];
- const float goalZ = goalPosXYZ[2];
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("GoalPosParam", AZ::Vector3(goalX, goalY, goalZ));
- GetEMotionFX().Update(5.0f / 60.0f);
- const AZ::Vector3& testJointNewPos = jackPose->GetModelSpaceTransform(testJointIndex).m_position;
- // Based on weight, check if position of node changes to reachable goal position
- if (weight)
- {
- const AZ::Vector3 expectedPosition(goalX, goalY, goalZ);
- EXPECT_TRUE(PosePositionCompareClose(testJointNewPos, expectedPosition, 0.0001f))
- << "Joint position should be similar to expected position.";
- }
- else
- {
- EXPECT_TRUE(testJointNewPos == testJointPos) << "Joint position should not change when weight is 0.";
- }
- }
- };
- TEST_P(BlendTreeTwoLinkIKNodeFixture, ReachableAlignToNodeOutputCorrectPose)
- {
- m_twoLinkIKNode->AddConnection(m_paramNode, static_cast<uint16>(m_paramNode->FindOutputPortByName("WeightParam")->m_portId),
- BlendTreeTwoLinkIKNode::INPUTPORT_WEIGHT);
- GetEMotionFX().Update(1.0f / 60.0f);
- const float weight = testing::get<0>(GetParam());
- ParamSetValue<MCore::AttributeFloat, float>("WeightParam", weight);
-
- const Pose* jackPose = m_actorInstance->GetTransformData()->GetCurrentPose();
- size_t testJointIndex;
- m_jackSkeleton->FindNodeAndIndexByName(m_param.m_testJointName, testJointIndex);
- const AZ::Vector3& testJointPos = jackPose->GetModelSpaceTransform(testJointIndex).m_position;
- for (AZStd::string& nodeName : m_param.m_alignToNodeNames)
- {
- NodeAlignmentData alignToNode;
- alignToNode.first = nodeName;
- alignToNode.second = 0;
- m_twoLinkIKNode->SetAlignToNode(alignToNode);
-
- // Update will set uniqueData->m_mustUpdate to false for efficiency purposes
- // Unique data only updates once unless reset m_mustUpdate to true again
- BlendTreeTwoLinkIKNode::UniqueData* uniqueData = static_cast<BlendTreeTwoLinkIKNode::UniqueData*>(m_animGraphInstance->FindOrCreateUniqueNodeData(m_twoLinkIKNode));
- uniqueData->Invalidate();
- size_t alignToNodeIndex;
- m_jackSkeleton->FindNodeAndIndexByName(nodeName, alignToNodeIndex);
-
- GetEMotionFX().Update(1.0f / 60.0f);
- const AZ::Vector3& alignToNodePos = jackPose->GetModelSpaceTransform(alignToNodeIndex).m_position;
- const AZ::Vector3& testJointNewPos = jackPose->GetModelSpaceTransform(testJointIndex).m_position;
- // Based on weight, check if position of node changes to alignToNode position
- if (weight)
- {
- EXPECT_TRUE(PosePositionCompareClose(alignToNodePos, testJointNewPos, 0.0001f))
- << "Test joint position should be similar to align-to joint position.";
- }
- else
- {
- EXPECT_TRUE(testJointPos == testJointNewPos) << "Joint position should not change when weight is 0.";
- }
- }
- };
-
- TEST_P(BlendTreeTwoLinkIKNodeFixture, UnreachablePositionsOutputCorrectPose)
- {
- m_twoLinkIKNode->AddConnection(m_paramNode, static_cast<uint16>(m_paramNode->FindOutputPortByName("WeightParam")->m_portId),
- BlendTreeTwoLinkIKNode::INPUTPORT_WEIGHT);
- m_twoLinkIKNode->AddConnection(m_paramNode,
- static_cast<uint16>(m_paramNode->FindOutputPortByName("GoalPosParam")->m_portId), BlendTreeTwoLinkIKNode::INPUTPORT_GOALPOS);
- GetEMotionFX().Update(1.0f / 60.0f);
- const float weight = testing::get<0>(GetParam());
- ParamSetValue<MCore::AttributeFloat, float>("WeightParam", weight);
- const Pose* jackPose = m_actorInstance->GetTransformData()->GetCurrentPose();
- size_t testJointIndex;
- size_t linkedJoint0Index;
- size_t linkedJoint1Index;
- m_jackSkeleton->FindNodeAndIndexByName(m_param.m_testJointName, testJointIndex);
- m_jackSkeleton->FindNodeAndIndexByName(m_param.m_linkedJointNames[0], linkedJoint0Index);
- m_jackSkeleton->FindNodeAndIndexByName(m_param.m_linkedJointNames[1], linkedJoint1Index);
- const AZ::Vector3& testJointPos = jackPose->GetModelSpaceTransform(testJointIndex).m_position;
-
- for (std::vector<float> goalPosXYZ : m_param.m_unreachablePositions)
- {
- const float goalX = goalPosXYZ[0];
- const float goalY = goalPosXYZ[1];
- const float goalZ = goalPosXYZ[2];
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("GoalPosParam", AZ::Vector3(goalX, goalY, goalZ));
- GetEMotionFX().Update(1.0f / 60.0f);
- const AZ::Vector3& testJointNewPos = jackPose->GetModelSpaceTransform(testJointIndex).m_position;
- const AZ::Vector3& linkedJoint0Pos = jackPose->GetModelSpaceTransform(linkedJoint0Index).m_position;
- const AZ::Vector3& linkedJoint1Pos = jackPose->GetModelSpaceTransform(linkedJoint1Index).m_position;
- // Based on weight, check if position of the test node
- // And its linked nodes are pointing towards the unreachable position
- if (weight)
- {
- const AZ::Vector3 goalVec(goalX, goalY, goalZ);
- EXPECT_TRUE(PositionVectorsPointInSameDirection(testJointNewPos, linkedJoint0Pos, linkedJoint1Pos, goalVec))
- << "Test joint and its linked joints should point to the expected vector.";
- }
- else
- {
- EXPECT_TRUE(testJointNewPos == testJointPos) << "Joint position should not change when weight is 0.";
- }
- }
- };
- TEST_P(BlendTreeTwoLinkIKNodeFixture, RotatedPositionsOutputCorrectPose)
- {
- m_twoLinkIKNode->AddConnection(m_paramNode, static_cast<uint16>(m_paramNode->FindOutputPortByName("WeightParam")->m_portId),
- BlendTreeTwoLinkIKNode::INPUTPORT_WEIGHT);
- m_twoLinkIKNode->AddConnection(m_paramNode,
- static_cast<uint16>(m_paramNode->FindOutputPortByName("GoalPosParam")->m_portId), BlendTreeTwoLinkIKNode::INPUTPORT_GOALPOS);
- m_twoLinkIKNode->AddConnection(m_paramNode,
- static_cast<uint16>(m_paramNode->FindOutputPortByName("RotationParam")->m_portId), BlendTreeTwoLinkIKNode::INPUTPORT_GOALROT);
- m_twoLinkIKNode->SetRotationEnabled(true);
- GetEMotionFX().Update(1.0f / 60.0f);
- // Set up test joint position and weight
- const float weight = testing::get<0>(GetParam());
- ParamSetValue<MCore::AttributeFloat, float>("WeightParam", weight);
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("GoalPosParam", AZ::Vector3(0.0f, 1.0f, 1.0f));
- const Pose* jackPose = m_actorInstance->GetTransformData()->GetCurrentPose();
- size_t testJointIndex;
- m_jackSkeleton->FindNodeAndIndexByName(m_param.m_testJointName, testJointIndex);
- const AZ::Quaternion testJointRotation = jackPose->GetModelSpaceTransform(testJointIndex).m_rotation;
- for (std::vector<float> rotateXYZ : m_param.m_rotations)
- {
- const float rotateX = rotateXYZ[0];
- const float rotateY = rotateXYZ[1];
- const float rotateZ = rotateXYZ[2];
- ParamSetValue<MCore::AttributeQuaternion, AZ::Quaternion>("RotationParam", AZ::Quaternion(rotateX, rotateY, rotateZ, 1.0f));
-
- GetEMotionFX().Update(1.0f / 60.0f);
- const AZ::Quaternion testJointNewRotation = jackPose->GetModelSpaceTransform(testJointIndex).m_rotation;
- if (weight)
- {
- const AZ::Quaternion goalRotation(rotateX, rotateY, rotateZ, 1.0f);
- EXPECT_EQ(testJointNewRotation, goalRotation.GetNormalized()) << "Rotation of the test joint should be the same as the expected rotation.";
- }
- else
- {
- EXPECT_EQ(testJointNewRotation, testJointRotation) << "Rotation should not change when weight is 0.";
- }
- }
- };
- TEST_P(BlendTreeTwoLinkIKNodeFixture, BendDirectionOutputCorrectPose)
- {
- m_twoLinkIKNode->AddConnection(m_paramNode, static_cast<uint16>(m_paramNode->FindOutputPortByName("WeightParam")->m_portId),
- BlendTreeTwoLinkIKNode::INPUTPORT_WEIGHT);
- m_twoLinkIKNode->AddConnection(m_paramNode,
- static_cast<uint16>(m_paramNode->FindOutputPortByName("GoalPosParam")->m_portId), BlendTreeTwoLinkIKNode::INPUTPORT_GOALPOS);
- m_twoLinkIKNode->AddConnection(m_paramNode,
- static_cast<uint16>(m_paramNode->FindOutputPortByName("BendDirParam")->m_portId), BlendTreeTwoLinkIKNode::INPUTPORT_BENDDIR);
- m_twoLinkIKNode->SetRelativeBendDir(true);
- GetEMotionFX().Update(1.0f / 60.0f);
- // Set up Jack's arm to specific position for testing
- const float weight = testing::get<0>(GetParam());
- const float x = m_param.m_bendDirPosition[0];
- const float y = m_param.m_bendDirPosition[1];
- const float z = m_param.m_bendDirPosition[2];
- ParamSetValue<MCore::AttributeFloat, float>("WeightParam", weight);
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("GoalPosParam", AZ::Vector3(x, y, z));
- GetEMotionFX().Update(1.0f / 60.0f);
-
- Pose* jackPose = m_actorInstance->GetTransformData()->GetCurrentPose();
- size_t testBendJointIndex;
- size_t testJointIndex;
- AZStd::string& bendLoArm = m_param.m_linkedJointNames[0];
- m_jackSkeleton->FindNodeAndIndexByName(bendLoArm, testBendJointIndex);
- m_jackSkeleton->FindNodeAndIndexByName(m_param.m_testJointName, testJointIndex);
- const AZ::Vector3 testJointBendPos = jackPose->GetModelSpaceTransform(testBendJointIndex).m_position;
- // Bend the test joint to opposite positions and check positions are opposite
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("BendDirParam", AZ::Vector3(1.0f, 0.0f, 0.0f));
- GetEMotionFX().Update(1.0f / 60.0f);
- const AZ::Vector3 testJointBendRightPos = jackPose->GetModelSpaceTransform(testBendJointIndex).m_position;
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("BendDirParam", AZ::Vector3(-1.0f, 0.0f, 0.0f));
- GetEMotionFX().Update(1.0f / 60.0f);
- const AZ::Vector3 testJointBendLeftPos = jackPose->GetModelSpaceTransform(testBendJointIndex).m_position;
-
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("BendDirParam", AZ::Vector3(0.0f, 1.0f, 0.0f));
- GetEMotionFX().Update(1.0f / 60.0f);
- const AZ::Vector3 testJointBendDownPos = jackPose->GetModelSpaceTransform(testBendJointIndex).m_position;
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("BendDirParam", AZ::Vector3(0.0f, -1.0f, 0.0f));
- GetEMotionFX().Update(1.0f / 60.0f);
- const AZ::Vector3 testJointBendUpPos = jackPose->GetModelSpaceTransform(testBendJointIndex).m_position;
-
- if (weight)
- {
- // Z-axis(Height) of tested bend joint should behave correctly
- EXPECT_TRUE(testJointBendDownPos.GetZ() < testJointBendUpPos.GetZ()) << "Height of bent down joint should be lower than bent up joint.";
- EXPECT_TRUE(testJointBendPos.GetZ() < testJointBendUpPos.GetZ()) << "Height of original joint should be lower than bent up joint.";
- EXPECT_TRUE(testJointBendDownPos.GetZ() < testJointBendPos.GetZ()) << "Height of bent down joint should be lower than original joint.";
-
- // X-axis(Horizontal) of tested bend joint should behave correctly
- EXPECT_TRUE(testJointBendLeftPos.GetX() < testJointBendRightPos.GetX()) << "Bent left joint should be on the left of bent right joint.";
- EXPECT_TRUE(testJointBendPos.GetX() < testJointBendRightPos.GetX()) << "Original joint should be on the left of bent right joint.";
- EXPECT_TRUE(testJointBendLeftPos.GetX() < testJointBendPos.GetX()) << "Bent left joint should be on the left of original joint.";
- }
- else
- {
- // Position should not change if weight is 0
- EXPECT_EQ(testJointBendRightPos, testJointBendLeftPos) << "Joint position should not change.";
- EXPECT_EQ(testJointBendUpPos, testJointBendDownPos) << "Joint position should not change.";
- }
- };
- TEST_P(BlendTreeTwoLinkIKNodeFixture, CombinedFunctionsOutputCorrectPose)
- {
- // Two Link IK Node should not break when using all of its functions at the same time
- m_twoLinkIKNode->AddConnection(m_paramNode, static_cast<uint16>(m_paramNode->FindOutputPortByName("WeightParam")->m_portId),
- BlendTreeTwoLinkIKNode::INPUTPORT_WEIGHT);
- m_twoLinkIKNode->AddConnection(m_paramNode,
- static_cast<uint16>(m_paramNode->FindOutputPortByName("GoalPosParam")->m_portId), BlendTreeTwoLinkIKNode::INPUTPORT_GOALPOS);
- m_twoLinkIKNode->AddConnection(m_paramNode,
- static_cast<uint16>(m_paramNode->FindOutputPortByName("RotationParam")->m_portId), BlendTreeTwoLinkIKNode::INPUTPORT_GOALROT);
- m_twoLinkIKNode->AddConnection(m_paramNode,
- static_cast<uint16>(m_paramNode->FindOutputPortByName("BendDirParam")->m_portId), BlendTreeTwoLinkIKNode::INPUTPORT_BENDDIR);
- m_twoLinkIKNode->SetRotationEnabled(true);
- m_twoLinkIKNode->SetRelativeBendDir(true);
- GetEMotionFX().Update(1.0f / 60.0f);
- const Pose* jackPose = m_actorInstance->GetTransformData()->GetCurrentPose();
- size_t testJointIndex;
- size_t testBendJointIndex;
- AZStd::string& bendLoArm = m_param.m_linkedJointNames[0];
- m_jackSkeleton->FindNodeAndIndexByName(m_param.m_testJointName, testJointIndex);
- m_jackSkeleton->FindNodeAndIndexByName(bendLoArm, testBendJointIndex);
- // Adding weight and goal position
- const float weight = testing::get<0>(GetParam());
- const float posX = m_param.m_bendDirPosition[0];
- const float posY = m_param.m_bendDirPosition[1];
- const float posZ = m_param.m_bendDirPosition[2];
- ParamSetValue<MCore::AttributeFloat, float>("WeightParam", weight);
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("GoalPosParam", AZ::Vector3(posX, posY, posZ));
- GetEMotionFX().Update(1.0f / 60.0f);
- // Add bend direction
- const AZ::Vector3 testJointBendPos = jackPose->GetModelSpaceTransform(testBendJointIndex).m_position;
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("BendDirParam", AZ::Vector3(1.0f, 0.0f, 0.0f));
- GetEMotionFX().Update(1.0f / 60.0f);
- const AZ::Vector3 testJointBendRightPos = jackPose->GetModelSpaceTransform(testBendJointIndex).m_position;
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("BendDirParam", AZ::Vector3(-1.0f, 0.0f, 0.0f));
- GetEMotionFX().Update(1.0f / 60.0f);
- const AZ::Vector3 testJointBendLeftPos = jackPose->GetModelSpaceTransform(testBendJointIndex).m_position;
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("BendDirParam", AZ::Vector3(0.0f, 1.0f, 0.0f));
- GetEMotionFX().Update(1.0f / 60.0f);
- const AZ::Vector3 testJointBendDownPos = jackPose->GetModelSpaceTransform(testBendJointIndex).m_position;
- ParamSetValue<MCore::AttributeVector3, AZ::Vector3>("BendDirParam", AZ::Vector3(0.0f, -1.0f, 0.0f));
- GetEMotionFX().Update(1.0f / 60.0f);
- const AZ::Vector3 testJointBendUpPos = jackPose->GetModelSpaceTransform(testBendJointIndex).m_position;
- // Rotations with bent joint
- const AZ::Quaternion testJointOriginalRotation = jackPose->GetModelSpaceTransform(testJointIndex).m_rotation;
- for (std::vector<float> rotateXYZ : m_param.m_rotations)
- {
- const float rotateX = rotateXYZ[0];
- const float rotateY = rotateXYZ[1];
- const float rotateZ = rotateXYZ[2];
- ParamSetValue<MCore::AttributeQuaternion, AZ::Quaternion>("RotationParam", AZ::Quaternion(rotateX, rotateY, rotateZ, 1.0f));
- GetEMotionFX().Update(1.0f / 60.0f);
- const AZ::Quaternion testJointNewRotation = jackPose->GetModelSpaceTransform(testJointIndex).m_rotation;
- if (weight)
- {
- const AZ::Quaternion goalRotation(rotateX, rotateY, rotateZ, 1.0f);
- EXPECT_EQ(testJointNewRotation, goalRotation.GetNormalized()) << "Rotation of the test joint should be the same as the expected rotation.";
- }
- else
- {
- EXPECT_EQ(testJointNewRotation, testJointOriginalRotation) << "Rotation should not change when weight is 0.";
- }
- }
- if (weight)
- {
- // Z-axis(Height) of tested bend joint should behave correctly
- EXPECT_TRUE(testJointBendDownPos.GetZ() < testJointBendUpPos.GetZ()) << "Height of bent down joint should be lower than bent up joint.";
- EXPECT_TRUE(testJointBendPos.GetZ() < testJointBendUpPos.GetZ()) << "Height of original joint should be lower than bent up joint.";
- EXPECT_TRUE(testJointBendDownPos.GetZ() < testJointBendPos.GetZ()) << "Height of bent down joint should be lower than original joint.";
- // X-axis(Horizontal) of tested bend joint should behave correctly
- EXPECT_TRUE(testJointBendLeftPos.GetX() < testJointBendRightPos.GetX()) << "Bent left joint should be on the left of bent right joint.";
- EXPECT_TRUE(testJointBendPos.GetX() < testJointBendRightPos.GetX()) << "Original joint should be on the left of bent right joint.";
- EXPECT_TRUE(testJointBendLeftPos.GetX() < testJointBendPos.GetX()) << "Bent left joint should be on the left of original joint.";
- }
- else
- {
- // Position should not change if weight is 0
- EXPECT_EQ(testJointBendRightPos, testJointBendLeftPos) << "Joint position should not change.";
- EXPECT_EQ(testJointBendUpPos, testJointBendDownPos) << "Joint position should not change.";
- }
- };
- std::vector< BlendTreeTwoLinkIKNodeTestsData> testData
- {
- {
- "l_hand" /* Test joint */,
- {"l_loArm","l_upArm"} /* Linked joints */,
- {
- // Reachable positions for the joint
- {0.0f, -0.02f, 1.09f},
- {-0.08f, 0.03f, 1.50f},
- {0.08f, 0.03f, 1.50f},
- {0.0f, 0.02f, 1.67f}
- },
- {
- // Unreachable positions for the joint
- {0.0f, 0.0f, 0.0f},
- {0.0f, 10.0f, 0.0f},
- {0.0f, 0.0f, 10.0f},
- {0.0f, 10.0f, 10.0f},
- {10.0f, 0.0f, 0.0f},
- {10.0f, 10.0f, 0.0f},
- {10.0f, 10.0f, 10.0f}
- },
- {
- // Rotations of the joint
- {-90.0f, 180.0f, 0.0f},
- {-540.0f, 0.0f, 1020.0f},
- {0.0f, 0.0f, 0.0f},
- {0.0f, 480.0f, -60.8f},
- {0.0f, -500.0f, 1000.0f},
- {1000.0f, -500.0f, 360.0f},
- {10.0f, 0.0f, -5.0f}
- },
- {0.2f, 0.4f, 1.5f} /* Fixed position of the tested joint for bend direction test */,
- {"spine1", "r_shldr", "l_shldr", "head"} /* Names of align-to node */
- }
- ,
- {
- "r_hand",
- {"r_loArm","r_upArm"},
- {
- {0.0f, -0.02f, 1.09f},
- {-0.08f, 0.03f, 1.50f},
- {0.08f, 0.03f, 1.50f},
- {0.0f, 0.02f, 1.67f}
- },
- {
- {0.0f, 0.0f, 0.0f},
- {0.0f, 10.0f, 0.0f},
- {0.0f, 0.0f, 10.0f},
- {0.0f, 10.0f, 10.0f},
- {10.0f, 0.0f, 0.0f},
- {10.0f, 10.0f, 0.0f},
- {10.0f, 10.0f, 10.0f}
- },
- {
- {-0.05f, .10f, 0.0f},
- {-.05f, 0.0f, .10f},
- {0.0f, 0.0f, 0.0f},
- {0.0f, .10f, -.05f},
- {0.0f, -.05f, .10f},
- {0.10f, -.05f, 0.0f},
- {.10f, 0.0f, -.05f}
- },
- {-0.2f, 0.4f, 1.5f},
- {"spine1", "r_shldr", "l_shldr", "head"}
- }
- };
- INSTANTIATE_TEST_CASE_P(BlendTreeTwoLinkIKNode_OutputTests,
- BlendTreeTwoLinkIKNodeFixture,
- ::testing::Combine(
- ::testing::Bool(),
- ::testing::ValuesIn(testData)
- )
- );
- } // end namespace EMotionFX
|