3
0

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