PoseDataJointVelocities.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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 <EMotionFX/Source/AnimGraphPose.h>
  10. #include <EMotionFX/Source/MotionInstance.h>
  11. #include <EMotionFX/Source/TransformData.h>
  12. #include <EMotionFX/Source/Velocity.h>
  13. #include <Allocators.h>
  14. #include <Feature.h>
  15. #include <PoseDataJointVelocities.h>
  16. namespace EMotionFX::MotionMatching
  17. {
  18. AZ_CLASS_ALLOCATOR_IMPL(PoseDataJointVelocities, MotionMatchAllocator)
  19. PoseDataJointVelocities::PoseDataJointVelocities()
  20. : PoseData()
  21. {
  22. }
  23. PoseDataJointVelocities::~PoseDataJointVelocities()
  24. {
  25. Clear();
  26. }
  27. void PoseDataJointVelocities::Clear()
  28. {
  29. m_velocities.clear();
  30. m_angularVelocities.clear();
  31. }
  32. void PoseDataJointVelocities::LinkToActorInstance(const ActorInstance* actorInstance)
  33. {
  34. m_velocities.resize(actorInstance->GetNumNodes());
  35. m_angularVelocities.resize(actorInstance->GetNumNodes());
  36. SetRelativeToJointIndex(actorInstance->GetActor()->GetMotionExtractionNodeIndex());
  37. }
  38. void PoseDataJointVelocities::SetRelativeToJointIndex(size_t relativeToJointIndex)
  39. {
  40. if (relativeToJointIndex == InvalidIndex)
  41. {
  42. m_relativeToJointIndex = 0;
  43. }
  44. else
  45. {
  46. m_relativeToJointIndex = relativeToJointIndex;
  47. }
  48. }
  49. void PoseDataJointVelocities::LinkToActor(const Actor* actor)
  50. {
  51. AZ_UNUSED(actor);
  52. Clear();
  53. }
  54. void PoseDataJointVelocities::Reset()
  55. {
  56. const size_t numJoints = m_velocities.size();
  57. for (size_t i = 0; i < numJoints; ++i)
  58. {
  59. m_velocities[i] = AZ::Vector3::CreateZero();
  60. m_angularVelocities[i] = AZ::Vector3::CreateZero();
  61. }
  62. }
  63. void PoseDataJointVelocities::CopyFrom(const PoseData* from)
  64. {
  65. AZ_Assert(from->RTTI_GetType() == azrtti_typeid<PoseDataJointVelocities>(), "Cannot copy from pose data other than joint velocity pose data.");
  66. const PoseDataJointVelocities* fromVelocityPoseData = static_cast<const PoseDataJointVelocities*>(from);
  67. m_isUsed = fromVelocityPoseData->m_isUsed;
  68. m_velocities = fromVelocityPoseData->m_velocities;
  69. m_angularVelocities = fromVelocityPoseData->m_angularVelocities;
  70. m_relativeToJointIndex = fromVelocityPoseData->m_relativeToJointIndex;
  71. }
  72. void PoseDataJointVelocities::Blend(const Pose* destPose, float weight)
  73. {
  74. PoseDataJointVelocities* destPoseData = destPose->GetPoseData<PoseDataJointVelocities>();
  75. if (destPoseData && destPoseData->IsUsed())
  76. {
  77. AZ_Assert(m_velocities.size() == destPoseData->m_velocities.size(), "Expected the same number of joints and velocities in the destination pose data.");
  78. if (m_isUsed)
  79. {
  80. // Blend while both, the destination pose as well as the current pose hold joint velocities.
  81. for (size_t i = 0; i < m_velocities.size(); ++i)
  82. {
  83. m_velocities[i] = m_velocities[i].Lerp(destPoseData->m_velocities[i], weight);
  84. m_angularVelocities[i] = m_angularVelocities[i].Lerp(destPoseData->m_angularVelocities[i], weight);
  85. }
  86. }
  87. else
  88. {
  89. // The destination pose data is used while the current one is not. Just copy over the velocities from the destination.
  90. m_velocities = destPoseData->m_velocities;
  91. m_angularVelocities = destPoseData->m_angularVelocities;
  92. }
  93. }
  94. else
  95. {
  96. // Destination pose either doesn't contain velocity pose data or it is unused.
  97. // Don't do anything and keep the current velocities.
  98. }
  99. }
  100. void PoseDataJointVelocities::DebugDraw(AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Color& color) const
  101. {
  102. AZ_Assert(m_pose->GetNumTransforms() == m_velocities.size(), "Expected a joint velocity for each joint in the pose.");
  103. const Pose* pose = m_pose;
  104. for (size_t i = 0; i < m_velocities.size(); ++i)
  105. {
  106. const size_t jointIndex = i;
  107. // draw linear velocity
  108. {
  109. const Transform jointModelTM = pose->GetModelSpaceTransform(jointIndex);
  110. const Transform relativeToWorldTM = pose->GetWorldSpaceTransform(m_relativeToJointIndex);
  111. const AZ::Vector3 jointPosition = relativeToWorldTM.TransformPoint(jointModelTM.m_position);
  112. const AZ::Vector3& velocity = m_velocities[i];
  113. const AZ::Vector3 velocityWorldSpace = relativeToWorldTM.TransformVector(velocity);
  114. const float scale = 0.1f;
  115. DebugDrawVelocity(debugDisplay, jointPosition, velocityWorldSpace * scale, color);
  116. }
  117. }
  118. }
  119. void PoseDataJointVelocities::CalculateVelocity(const ActorInstance* actorInstance, AnimGraphPosePool& posePool, Motion* motion, float requestedSampleTime, size_t relativeToJointIndex)
  120. {
  121. MotionDataSampleSettings sampleSettings;
  122. sampleSettings.m_actorInstance = actorInstance;
  123. sampleSettings.m_inPlace = false;
  124. sampleSettings.m_mirror = false;
  125. sampleSettings.m_retarget = false;
  126. sampleSettings.m_inputPose = sampleSettings.m_actorInstance->GetTransformData()->GetBindPose();
  127. const size_t numJoints = m_velocities.size();
  128. SetRelativeToJointIndex(relativeToJointIndex);
  129. m_velocities.resize(numJoints);
  130. m_angularVelocities.resize(numJoints);
  131. // Prepare for sampling.
  132. AnimGraphPose* prevPose = posePool.RequestPose(actorInstance);
  133. AnimGraphPose* currentPose = posePool.RequestPose(actorInstance);
  134. const size_t numSamples = 3;
  135. const float timeRange = 0.05f; // secs
  136. const float halfTimeRange = timeRange * 0.5f;
  137. const float startTime = requestedSampleTime - halfTimeRange;
  138. const float numInbetweens = aznumeric_cast<float>(numSamples - 1); // Number of elements or windows between two keyframes.
  139. const float frameDelta = timeRange / numInbetweens;
  140. const float motionDuration = motion->GetDuration();
  141. // Zero all linear and angular velocities.
  142. Reset();
  143. for (size_t sampleIndex = 0; sampleIndex < numSamples; ++sampleIndex)
  144. {
  145. float sampleTime = startTime + sampleIndex * frameDelta;
  146. sampleTime = AZ::GetClamp(sampleTime, 0.0f, motionDuration);
  147. if (sampleIndex == 0)
  148. {
  149. sampleSettings.m_sampleTime = sampleTime;
  150. motion->SamplePose(&prevPose->GetPose(), sampleSettings);
  151. continue;
  152. }
  153. sampleSettings.m_sampleTime = sampleTime;
  154. motion->SamplePose(&currentPose->GetPose(), sampleSettings);
  155. const Transform inverseJointWorldTransform = currentPose->GetPose().GetWorldSpaceTransform(relativeToJointIndex).Inversed();
  156. for (size_t jointIndex = 0; jointIndex < numJoints; ++jointIndex)
  157. {
  158. const Transform prevWorldTransform = prevPose->GetPose().GetWorldSpaceTransform(jointIndex);
  159. const Transform currentWorldTransform = currentPose->GetPose().GetWorldSpaceTransform(jointIndex);
  160. // Calculate the linear velocity.
  161. const AZ::Vector3 prevPosition = inverseJointWorldTransform.TransformPoint(prevWorldTransform.m_position);
  162. const AZ::Vector3 currentPosition = inverseJointWorldTransform.TransformPoint(currentWorldTransform.m_position);
  163. const AZ::Vector3 linearVelocity = CalculateLinearVelocity(prevPosition, currentPosition, frameDelta);
  164. m_velocities[jointIndex] += linearVelocity;
  165. // Calculate the angular velocity.
  166. const AZ::Quaternion prevRotation = inverseJointWorldTransform.m_rotation * prevWorldTransform.m_rotation;
  167. const AZ::Quaternion currentRotation = inverseJointWorldTransform.m_rotation * currentWorldTransform.m_rotation;
  168. const AZ::Vector3 angularVelocity = CalculateAngularVelocity(prevRotation, currentRotation, frameDelta);
  169. m_angularVelocities[jointIndex] += angularVelocity;
  170. }
  171. *prevPose = *currentPose;
  172. }
  173. for (size_t i = 0; i < numJoints; ++i)
  174. {
  175. m_velocities[i] /= numInbetweens;
  176. m_angularVelocities[i] /= numInbetweens;
  177. }
  178. posePool.FreePose(prevPose);
  179. posePool.FreePose(currentPose);
  180. }
  181. void PoseDataJointVelocities::Reflect(AZ::ReflectContext* context)
  182. {
  183. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  184. if (serializeContext)
  185. {
  186. serializeContext->Class<PoseDataJointVelocities, PoseData>()->Version(1);
  187. }
  188. }
  189. } // namespace EMotionFX::MotionMatching