SkeletalAnimation.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <Jolt/Jolt.h>
  5. #include <Jolt/Skeleton/SkeletalAnimation.h>
  6. #include <Jolt/Skeleton/SkeletonPose.h>
  7. #include <Jolt/ObjectStream/TypeDeclarations.h>
  8. #include <Jolt/Core/StreamIn.h>
  9. #include <Jolt/Core/StreamOut.h>
  10. JPH_NAMESPACE_BEGIN
  11. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SkeletalAnimation::JointState)
  12. {
  13. JPH_ADD_ATTRIBUTE(JointState, mRotation)
  14. JPH_ADD_ATTRIBUTE(JointState, mTranslation)
  15. }
  16. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SkeletalAnimation::Keyframe)
  17. {
  18. JPH_ADD_BASE_CLASS(Keyframe, JointState)
  19. JPH_ADD_ATTRIBUTE(Keyframe, mTime)
  20. }
  21. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SkeletalAnimation::AnimatedJoint)
  22. {
  23. JPH_ADD_ATTRIBUTE(AnimatedJoint, mJointName)
  24. JPH_ADD_ATTRIBUTE(AnimatedJoint, mKeyframes)
  25. }
  26. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SkeletalAnimation)
  27. {
  28. JPH_ADD_ATTRIBUTE(SkeletalAnimation, mAnimatedJoints)
  29. JPH_ADD_ATTRIBUTE(SkeletalAnimation, mIsLooping)
  30. }
  31. void SkeletalAnimation::JointState::FromMatrix(Mat44Arg inMatrix)
  32. {
  33. mRotation = inMatrix.GetQuaternion();
  34. mTranslation = inMatrix.GetTranslation();
  35. }
  36. float SkeletalAnimation::GetDuration() const
  37. {
  38. if (!mAnimatedJoints.empty() && !mAnimatedJoints[0].mKeyframes.empty())
  39. return mAnimatedJoints[0].mKeyframes.back().mTime;
  40. else
  41. return 0.0f;
  42. }
  43. void SkeletalAnimation::ScaleJoints(float inScale)
  44. {
  45. for (SkeletalAnimation::AnimatedJoint &j : mAnimatedJoints)
  46. for (SkeletalAnimation::Keyframe &k : j.mKeyframes)
  47. k.mTranslation *= inScale;
  48. }
  49. void SkeletalAnimation::Sample(float inTime, SkeletonPose &ioPose) const
  50. {
  51. // Correct time when animation is looping
  52. JPH_ASSERT(inTime >= 0.0f);
  53. float duration = GetDuration();
  54. float time = duration > 0.0f && mIsLooping? fmod(inTime, duration) : inTime;
  55. for (const AnimatedJoint &aj : mAnimatedJoints)
  56. {
  57. // Do binary search for keyframe
  58. int high = (int)aj.mKeyframes.size(), low = -1;
  59. while (high - low > 1)
  60. {
  61. int probe = (high + low) / 2;
  62. if (aj.mKeyframes[probe].mTime < time)
  63. low = probe;
  64. else
  65. high = probe;
  66. }
  67. JointState &state = ioPose.GetJoint(ioPose.GetSkeleton()->GetJointIndex(aj.mJointName));
  68. if (low == -1)
  69. {
  70. // Before first key, return first key
  71. state = static_cast<const JointState &>(aj.mKeyframes.front());
  72. }
  73. else if (high == (int)aj.mKeyframes.size())
  74. {
  75. // Beyond last key, return last key
  76. state = static_cast<const JointState &>(aj.mKeyframes.back());
  77. }
  78. else
  79. {
  80. // Interpolate
  81. const Keyframe &s1 = aj.mKeyframes[low];
  82. const Keyframe &s2 = aj.mKeyframes[low + 1];
  83. float fraction = (time - s1.mTime) / (s2.mTime - s1.mTime);
  84. JPH_ASSERT(fraction >= 0.0f && fraction <= 1.0f);
  85. state.mTranslation = (1.0f - fraction) * s1.mTranslation + fraction * s2.mTranslation;
  86. JPH_ASSERT(s1.mRotation.IsNormalized());
  87. JPH_ASSERT(s2.mRotation.IsNormalized());
  88. state.mRotation = s1.mRotation.SLERP(s2.mRotation, fraction);
  89. JPH_ASSERT(state.mRotation.IsNormalized());
  90. }
  91. }
  92. }
  93. void SkeletalAnimation::SaveBinaryState(StreamOut &inStream) const
  94. {
  95. inStream.Write((uint32)mAnimatedJoints.size());
  96. for (const AnimatedJoint &j : mAnimatedJoints)
  97. {
  98. // Write Joint name and number of keyframes
  99. inStream.Write(j.mJointName);
  100. inStream.Write((uint32)j.mKeyframes.size());
  101. for (const Keyframe &k : j.mKeyframes)
  102. {
  103. inStream.Write(k.mTime);
  104. inStream.Write(k.mRotation);
  105. inStream.Write(k.mTranslation);
  106. }
  107. }
  108. // Save additional parameters
  109. inStream.Write(mIsLooping);
  110. }
  111. SkeletalAnimation::AnimationResult SkeletalAnimation::sRestoreFromBinaryState(StreamIn &inStream)
  112. {
  113. AnimationResult result;
  114. Ref<SkeletalAnimation> animation = new SkeletalAnimation;
  115. // Restore animated joints
  116. uint32 len = 0;
  117. inStream.Read(len);
  118. animation->mAnimatedJoints.resize(len);
  119. for (AnimatedJoint &j : animation->mAnimatedJoints)
  120. {
  121. // Read joint name
  122. inStream.Read(j.mJointName);
  123. // Read keyframes
  124. len = 0;
  125. inStream.Read(len);
  126. j.mKeyframes.resize(len);
  127. for (Keyframe &k : j.mKeyframes)
  128. {
  129. inStream.Read(k.mTime);
  130. inStream.Read(k.mRotation);
  131. inStream.Read(k.mTranslation);
  132. }
  133. }
  134. // Read additional parameters
  135. inStream.Read(animation->mIsLooping);
  136. result.Set(animation);
  137. return result;
  138. }
  139. JPH_NAMESPACE_END