SkeletalAnimation.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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. JPH_NAMESPACE_BEGIN
  9. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SkeletalAnimation::JointState)
  10. {
  11. JPH_ADD_ATTRIBUTE(JointState, mRotation)
  12. JPH_ADD_ATTRIBUTE(JointState, mTranslation)
  13. }
  14. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SkeletalAnimation::Keyframe)
  15. {
  16. JPH_ADD_BASE_CLASS(Keyframe, JointState)
  17. JPH_ADD_ATTRIBUTE(Keyframe, mTime)
  18. }
  19. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SkeletalAnimation::AnimatedJoint)
  20. {
  21. JPH_ADD_ATTRIBUTE(AnimatedJoint, mJointName)
  22. JPH_ADD_ATTRIBUTE(AnimatedJoint, mKeyframes)
  23. }
  24. JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SkeletalAnimation)
  25. {
  26. JPH_ADD_ATTRIBUTE(SkeletalAnimation, mAnimatedJoints)
  27. JPH_ADD_ATTRIBUTE(SkeletalAnimation, mIsLooping)
  28. }
  29. void SkeletalAnimation::JointState::FromMatrix(Mat44Arg inMatrix)
  30. {
  31. mRotation = inMatrix.GetQuaternion();
  32. mTranslation = inMatrix.GetTranslation();
  33. }
  34. float SkeletalAnimation::GetDuration() const
  35. {
  36. if (!mAnimatedJoints.empty() && !mAnimatedJoints[0].mKeyframes.empty())
  37. return mAnimatedJoints[0].mKeyframes.back().mTime;
  38. else
  39. return 0.0f;
  40. }
  41. void SkeletalAnimation::ScaleJoints(float inScale)
  42. {
  43. for (SkeletalAnimation::AnimatedJoint &j : mAnimatedJoints)
  44. for (SkeletalAnimation::Keyframe &k : j.mKeyframes)
  45. k.mTranslation *= inScale;
  46. }
  47. void SkeletalAnimation::Sample(float inTime, SkeletonPose &ioPose) const
  48. {
  49. // Correct time when animation is looping
  50. JPH_ASSERT(inTime >= 0.0f);
  51. float duration = GetDuration();
  52. float time = duration > 0.0f && mIsLooping? fmod(inTime, duration) : inTime;
  53. for (const AnimatedJoint &aj : mAnimatedJoints)
  54. {
  55. // Do binary search for keyframe
  56. int high = (int)aj.mKeyframes.size(), low = -1;
  57. while (high - low > 1)
  58. {
  59. int probe = (high + low) / 2;
  60. if (aj.mKeyframes[probe].mTime < time)
  61. low = probe;
  62. else
  63. high = probe;
  64. }
  65. JointState &state = ioPose.GetJoint(ioPose.GetSkeleton()->GetJointIndex(aj.mJointName));
  66. if (low == -1)
  67. {
  68. // Before first key, return first key
  69. state = static_cast<const JointState &>(aj.mKeyframes.front());
  70. }
  71. else if (high == (int)aj.mKeyframes.size())
  72. {
  73. // Beyond last key, return last key
  74. state = static_cast<const JointState &>(aj.mKeyframes.back());
  75. }
  76. else
  77. {
  78. // Interpolate
  79. const Keyframe &s1 = aj.mKeyframes[low];
  80. const Keyframe &s2 = aj.mKeyframes[low + 1];
  81. float fraction = (time - s1.mTime) / (s2.mTime - s1.mTime);
  82. JPH_ASSERT(fraction >= 0.0f && fraction <= 1.0f);
  83. state.mTranslation = (1.0f - fraction) * s1.mTranslation + fraction * s2.mTranslation;
  84. JPH_ASSERT(s1.mRotation.IsNormalized());
  85. JPH_ASSERT(s2.mRotation.IsNormalized());
  86. state.mRotation = s1.mRotation.SLERP(s2.mRotation, fraction);
  87. JPH_ASSERT(state.mRotation.IsNormalized());
  88. }
  89. }
  90. }
  91. JPH_NAMESPACE_END