Feature.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <EMotionFX/Source/ActorInstance.h>
  9. #include <Allocators.h>
  10. #include <EMotionFX/Source/AnimGraphPose.h>
  11. #include <EMotionFX/Source/AnimGraphPosePool.h>
  12. #include <EMotionFX/Source/EMotionFXManager.h>
  13. #include <EMotionFX/Source/MotionInstance.h>
  14. #include <Feature.h>
  15. #include <Frame.h>
  16. #include <EMotionFX/Source/Pose.h>
  17. #include <EMotionFX/Source/TransformData.h>
  18. #include <EMotionFX/Source/Velocity.h>
  19. #include <MCore/Source/AzCoreConversions.h>
  20. #include <AzCore/Serialization/EditContext.h>
  21. #include <AzCore/Serialization/SerializeContext.h>
  22. namespace EMotionFX::MotionMatching
  23. {
  24. AZ_CLASS_ALLOCATOR_IMPL(Feature, MotionMatchAllocator)
  25. Feature::ExtractFeatureContext::ExtractFeatureContext(FeatureMatrix& featureMatrix, AnimGraphPosePool& posePool)
  26. : m_featureMatrix(featureMatrix)
  27. , m_posePool(posePool)
  28. {
  29. }
  30. Feature::QueryVectorContext::QueryVectorContext(const Pose& currentPose, const TrajectoryQuery& trajectoryQuery)
  31. : m_currentPose(currentPose)
  32. , m_trajectoryQuery(trajectoryQuery)
  33. {
  34. }
  35. Feature::FrameCostContext::FrameCostContext(const QueryVector& queryVector, const FeatureMatrix& featureMatrix)
  36. : m_queryVector(queryVector)
  37. , m_featureMatrix(featureMatrix)
  38. {
  39. }
  40. bool Feature::Init(const InitSettings& settings)
  41. {
  42. const Actor* actor = settings.m_actorInstance->GetActor();
  43. const Skeleton* skeleton = actor->GetSkeleton();
  44. const Node* joint = skeleton->FindNodeByNameNoCase(m_jointName.c_str());
  45. m_jointIndex = joint ? joint->GetNodeIndex() : InvalidIndex;
  46. if (m_jointIndex == InvalidIndex)
  47. {
  48. AZ_Error("Motion Matching", false, "Feature::Init(): Cannot find index for joint named '%s'.", m_jointName.c_str());
  49. return false;
  50. }
  51. const Node* relativeToJoint = skeleton->FindNodeByNameNoCase(m_relativeToJointName.c_str());
  52. m_relativeToNodeIndex = relativeToJoint ? relativeToJoint->GetNodeIndex() : InvalidIndex;
  53. if (m_relativeToNodeIndex == InvalidIndex)
  54. {
  55. AZ_Error("Motion Matching", false, "Feature::Init(): Cannot find index for joint named '%s'.", m_relativeToJointName.c_str());
  56. return false;
  57. }
  58. // Set a default feature name in case it did not get set manually.
  59. if (m_name.empty())
  60. {
  61. AZStd::string featureTypeName = this->RTTI_GetTypeName();
  62. AzFramework::StringFunc::Replace(featureTypeName, "Feature", "");
  63. m_name = AZStd::string::format("%s (%s)", featureTypeName.c_str(), m_jointName.c_str());
  64. }
  65. return true;
  66. }
  67. void Feature::SetDebugDrawColor(const AZ::Color& color)
  68. {
  69. m_debugColor = color;
  70. }
  71. const AZ::Color& Feature::GetDebugDrawColor() const
  72. {
  73. return m_debugColor;
  74. }
  75. void Feature::SetDebugDrawEnabled(bool enabled)
  76. {
  77. m_debugDrawEnabled = enabled;
  78. }
  79. bool Feature::GetDebugDrawEnabled() const
  80. {
  81. return m_debugDrawEnabled;
  82. }
  83. float Feature::CalculateFrameCost([[maybe_unused]] size_t frameIndex, [[maybe_unused]] const FrameCostContext& context) const
  84. {
  85. AZ_Assert(false, "Feature::CalculateFrameCost(): Not implemented for the given feature.");
  86. return 0.0f;
  87. }
  88. void Feature::SetRelativeToNodeIndex(size_t nodeIndex)
  89. {
  90. m_relativeToNodeIndex = nodeIndex;
  91. }
  92. float Feature::GetNormalizedDirectionDifference(const AZ::Vector2& directionA, const AZ::Vector2& directionB) const
  93. {
  94. const float dotProduct = directionA.GetNormalized().Dot(directionB.GetNormalized());
  95. const float normalizedDirectionDifference = (2.0f - (1.0f + dotProduct)) * 0.5f;
  96. return AZ::GetAbs(normalizedDirectionDifference);
  97. }
  98. float Feature::GetNormalizedDirectionDifference(const AZ::Vector3& directionA, const AZ::Vector3& directionB) const
  99. {
  100. const float dotProduct = directionA.GetNormalized().Dot(directionB.GetNormalized());
  101. const float normalizedDirectionDifference = (2.0f - (1.0f + dotProduct)) * 0.5f;
  102. return AZ::GetAbs(normalizedDirectionDifference);
  103. }
  104. float Feature::CalcResidual(float value) const
  105. {
  106. if (m_residualType == ResidualType::Squared)
  107. {
  108. return value * value;
  109. }
  110. return AZ::Abs(value);
  111. }
  112. float Feature::CalcResidual(const AZ::Vector3& a, const AZ::Vector3& b) const
  113. {
  114. const float euclideanDistance = (b - a).GetLength();
  115. return CalcResidual(euclideanDistance);
  116. }
  117. AZ::Crc32 Feature::GetCostFactorVisibility() const
  118. {
  119. return AZ::Edit::PropertyVisibility::Show;
  120. }
  121. void Feature::Reflect(AZ::ReflectContext* context)
  122. {
  123. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  124. if (!serializeContext)
  125. {
  126. return;
  127. }
  128. serializeContext->Class<Feature>()
  129. ->Version(2)
  130. ->Field("id", &Feature::m_id)
  131. ->Field("name", &Feature::m_name)
  132. ->Field("jointName", &Feature::m_jointName)
  133. ->Field("relativeToJointName", &Feature::m_relativeToJointName)
  134. ->Field("debugDraw", &Feature::m_debugDrawEnabled)
  135. ->Field("debugColor", &Feature::m_debugColor)
  136. ->Field("costFactor", &Feature::m_costFactor)
  137. ->Field("residualType", &Feature::m_residualType)
  138. ;
  139. AZ::EditContext* editContext = serializeContext->GetEditContext();
  140. if (!editContext)
  141. {
  142. return;
  143. }
  144. editContext->Class<Feature>("Feature", "Base class for a feature")
  145. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  146. ->Attribute(AZ::Edit::Attributes::AutoExpand, "")
  147. ->DataElement(AZ::Edit::UIHandlers::Default, &Feature::m_name, "Name", "Custom name of the feature used for identification and debug visualizations.")
  148. ->DataElement(AZ_CRC_CE("ActorNode"), &Feature::m_jointName, "Joint", "The joint to extract the data from.")
  149. ->DataElement(AZ_CRC_CE("ActorNode"), &Feature::m_relativeToJointName, "Relative To Joint", "When extracting feature data, convert it to relative-space to the given joint.")
  150. ->DataElement(AZ::Edit::UIHandlers::Default, &Feature::m_debugDrawEnabled, "Debug Draw", "Are debug visualizations enabled for this feature?")
  151. ->DataElement(AZ::Edit::UIHandlers::Default, &Feature::m_debugColor, "Debug Draw Color", "Color used for debug visualizations to identify the feature.")
  152. ->DataElement(AZ::Edit::UIHandlers::SpinBox, &Feature::m_costFactor, "Cost Factor", "The cost factor for the feature is multiplied with the actual and can be used to change a feature's influence in the motion matching search.")
  153. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  154. ->Attribute(AZ::Edit::Attributes::Max, 100.0f)
  155. ->Attribute(AZ::Edit::Attributes::Step, 0.1f)
  156. ->Attribute(AZ::Edit::Attributes::Visibility, &Feature::GetCostFactorVisibility)
  157. ->DataElement(AZ::Edit::UIHandlers::ComboBox, &Feature::m_residualType, "Residual", "Use 'Squared' in case minimal differences should be ignored and larger differences should overweight others. Use 'Absolute' for linear differences and don't want the mentioned effect.")
  158. ->EnumAttribute(ResidualType::Absolute, "Absolute")
  159. ->EnumAttribute(ResidualType::Squared, "Squared")
  160. ;
  161. }
  162. } // namespace EMotionFX::MotionMatching