BsAnimationCurve.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Animation/BsAnimationCurve.h"
  4. #include "RTTI/BsAnimationCurveRTTI.h"
  5. #include "Math/BsVector3.h"
  6. #include "Math/BsQuaternion.h"
  7. #include "Math/BsMath.h"
  8. #include "Animation/BsAnimationUtility.h"
  9. namespace bs
  10. {
  11. /**
  12. * Checks if any components of the keyframes are constant (step) functions and updates the hermite curve coefficients
  13. * accordingly.
  14. */
  15. void setStepCoefficients(const TKeyframe<float>& lhs, const TKeyframe<float>& rhs, float (&coefficients)[4])
  16. {
  17. if (lhs.outTangent != std::numeric_limits<float>::infinity() &&
  18. rhs.inTangent != std::numeric_limits<float>::infinity())
  19. return;
  20. coefficients[0] = 0.0f;
  21. coefficients[1] = 0.0f;
  22. coefficients[2] = 0.0f;
  23. coefficients[3] = lhs.value;
  24. }
  25. void setStepCoefficients(const TKeyframe<Vector3>& lhs, const TKeyframe<Vector3>& rhs, Vector3(&coefficients)[4])
  26. {
  27. for(UINT32 i = 0; i < 3; i++)
  28. {
  29. if (lhs.outTangent[i] != std::numeric_limits<float>::infinity() &&
  30. rhs.inTangent[i] != std::numeric_limits<float>::infinity())
  31. continue;
  32. coefficients[0][i] = 0.0f;
  33. coefficients[1][i] = 0.0f;
  34. coefficients[2][i] = 0.0f;
  35. coefficients[3][i] = lhs.value[i];
  36. }
  37. }
  38. void setStepCoefficients(const TKeyframe<Quaternion>& lhs, const TKeyframe<Quaternion>& rhs, Quaternion(&coefficients)[4])
  39. {
  40. for (UINT32 i = 0; i < 4; i++)
  41. {
  42. if (lhs.outTangent[i] != std::numeric_limits<float>::infinity() &&
  43. rhs.inTangent[i] != std::numeric_limits<float>::infinity())
  44. continue;
  45. coefficients[0][i] = 0.0f;
  46. coefficients[1][i] = 0.0f;
  47. coefficients[2][i] = 0.0f;
  48. coefficients[3][i] = lhs.value[i];
  49. }
  50. }
  51. /** Checks if any components of the keyframes are constant (step) functions and updates the key value. */
  52. void setStepValue(const TKeyframe<float>& lhs, const TKeyframe<float>& rhs, float& value)
  53. {
  54. if (lhs.outTangent != std::numeric_limits<float>::infinity() &&
  55. rhs.inTangent != std::numeric_limits<float>::infinity())
  56. return;
  57. value = lhs.value;
  58. }
  59. void setStepValue(const TKeyframe<Vector3>& lhs, const TKeyframe<Vector3>& rhs, Vector3& value)
  60. {
  61. for (UINT32 i = 0; i < 3; i++)
  62. {
  63. if (lhs.outTangent[i] != std::numeric_limits<float>::infinity() &&
  64. rhs.inTangent[i] != std::numeric_limits<float>::infinity())
  65. continue;
  66. value[i] = lhs.value[i];
  67. }
  68. }
  69. void setStepValue(const TKeyframe<Quaternion>& lhs, const TKeyframe<Quaternion>& rhs, Quaternion& value)
  70. {
  71. for (UINT32 i = 0; i < 4; i++)
  72. {
  73. if (lhs.outTangent[i] != std::numeric_limits<float>::infinity() &&
  74. rhs.inTangent[i] != std::numeric_limits<float>::infinity())
  75. continue;
  76. value[i] = lhs.value[i];
  77. }
  78. }
  79. /** Checks if any components of the keyframes are constant (step) functions and updates the key tangent. */
  80. void setStepTangent(const TKeyframe<float>& lhs, const TKeyframe<float>& rhs, float& tangent)
  81. {
  82. if (lhs.outTangent != std::numeric_limits<float>::infinity() &&
  83. rhs.inTangent != std::numeric_limits<float>::infinity())
  84. return;
  85. tangent = std::numeric_limits<float>::infinity();
  86. }
  87. void setStepTangent(const TKeyframe<Vector3>& lhs, const TKeyframe<Vector3>& rhs, Vector3& tangent)
  88. {
  89. for (UINT32 i = 0; i < 3; i++)
  90. {
  91. if (lhs.outTangent[i] != std::numeric_limits<float>::infinity() &&
  92. rhs.inTangent[i] != std::numeric_limits<float>::infinity())
  93. continue;
  94. tangent[i] = std::numeric_limits<float>::infinity();
  95. }
  96. }
  97. void setStepTangent(const TKeyframe<Quaternion>& lhs, const TKeyframe<Quaternion>& rhs, Quaternion& tangent)
  98. {
  99. for (UINT32 i = 0; i < 4; i++)
  100. {
  101. if (lhs.outTangent[i] != std::numeric_limits<float>::infinity() &&
  102. rhs.inTangent[i] != std::numeric_limits<float>::infinity())
  103. continue;
  104. tangent[i] = std::numeric_limits<float>::infinity();
  105. }
  106. }
  107. /** Calculates the difference between two values. */
  108. float getDiff(float lhs, float rhs)
  109. {
  110. return lhs - rhs;
  111. }
  112. Vector3 getDiff(const Vector3& lhs, const Vector3& rhs)
  113. {
  114. return lhs - rhs;
  115. }
  116. Quaternion getDiff(const Quaternion& lhs, const Quaternion& rhs)
  117. {
  118. return rhs.inverse() * lhs;
  119. }
  120. template <class T>
  121. T getZero() { return 0.0f; }
  122. template<>
  123. float getZero<float>() { return 0.0f; }
  124. template<>
  125. Vector3 getZero<Vector3>() { return Vector3(BsZero); }
  126. template<>
  127. Quaternion getZero<Quaternion>() { return Quaternion(BsZero); }
  128. template <class T>
  129. const UINT32 TAnimationCurve<T>::CACHE_LOOKAHEAD = 3;
  130. template <class T>
  131. TAnimationCurve<T>::TAnimationCurve()
  132. :mStart(0.0f), mEnd(0.0f), mLength(0.0f)
  133. {
  134. }
  135. template <class T>
  136. TAnimationCurve<T>::TAnimationCurve(const Vector<KeyFrame>& keyframes)
  137. :mKeyframes(keyframes)
  138. {
  139. #if BS_DEBUG_MODE
  140. // Ensure keyframes are sorted
  141. if(keyframes.size() > 0)
  142. {
  143. float time = keyframes[0].time;
  144. for (UINT32 i = 1; i < (UINT32)keyframes.size(); i++)
  145. {
  146. assert(keyframes[i].time >= time);
  147. time = keyframes[i].time;
  148. }
  149. }
  150. #endif
  151. if (keyframes.size() > 0)
  152. mEnd = keyframes.back().time;
  153. else
  154. mEnd = 0.0f;
  155. mStart = 0.0f;
  156. mLength = mEnd;
  157. }
  158. template <class T>
  159. T TAnimationCurve<T>::evaluate(float time, const TCurveCache<T>& cache, bool loop) const
  160. {
  161. if (mKeyframes.size() == 0)
  162. return getZero<T>();
  163. if (Math::approxEquals(mLength, 0.0f))
  164. time = 0.0f;
  165. // Wrap time if looping
  166. if(loop && mLength > 0.0f)
  167. {
  168. if (time < mStart)
  169. time = time + (std::floor(mEnd - time) / mLength) * mLength;
  170. else if (time > mEnd)
  171. time = time - std::floor((time - mStart) / mLength) * mLength;
  172. }
  173. // If time is within cache, evaluate it directly
  174. if (time >= cache.cachedCurveStart && time < cache.cachedCurveEnd)
  175. return evaluateCache(time, cache);
  176. // Clamp to start, cache constant of the first key and return
  177. if(time < mStart)
  178. {
  179. cache.cachedCurveStart = -std::numeric_limits<float>::infinity();
  180. cache.cachedCurveEnd = mStart;
  181. cache.cachedKey = 0;
  182. cache.cachedCubicCoefficients[0] = getZero<T>();
  183. cache.cachedCubicCoefficients[1] = getZero<T>();
  184. cache.cachedCubicCoefficients[2] = getZero<T>();
  185. cache.cachedCubicCoefficients[3] = mKeyframes[0].value;
  186. return mKeyframes[0].value;
  187. }
  188. if(time >= mEnd) // Clamp to end, cache constant of the final key and return
  189. {
  190. UINT32 lastKey = (UINT32)mKeyframes.size() - 1;
  191. cache.cachedCurveStart = mEnd;
  192. cache.cachedCurveEnd = std::numeric_limits<float>::infinity();
  193. cache.cachedKey = lastKey;
  194. cache.cachedCubicCoefficients[0] = getZero<T>();
  195. cache.cachedCubicCoefficients[1] = getZero<T>();
  196. cache.cachedCubicCoefficients[2] = getZero<T>();
  197. cache.cachedCubicCoefficients[3] = mKeyframes[lastKey].value;
  198. return mKeyframes[lastKey].value;
  199. }
  200. // Since our value is not in cache, search for the valid pair of keys of interpolate
  201. UINT32 leftKeyIdx;
  202. UINT32 rightKeyIdx;
  203. findKeys(time, cache, leftKeyIdx, rightKeyIdx);
  204. // Calculate cubic hermite curve coefficients so we can store them in cache
  205. const KeyFrame& leftKey = mKeyframes[leftKeyIdx];
  206. const KeyFrame& rightKey = mKeyframes[rightKeyIdx];
  207. cache.cachedCurveStart = leftKey.time;
  208. cache.cachedCurveEnd = rightKey.time;
  209. float length = rightKey.time - leftKey.time;
  210. assert(length > 0.0f);
  211. Math::cubicHermiteCoefficients(leftKey.value, rightKey.value, leftKey.outTangent, rightKey.inTangent, length,
  212. cache.cachedCubicCoefficients);
  213. setStepCoefficients(leftKey, rightKey, cache.cachedCubicCoefficients);
  214. T output = evaluateCache(time, cache);
  215. return output;
  216. }
  217. template <class T>
  218. T TAnimationCurve<T>::evaluate(float time, bool loop) const
  219. {
  220. if (mKeyframes.size() == 0)
  221. return getZero<T>();
  222. AnimationUtility::wrapTime(time, mStart, mEnd, loop);
  223. UINT32 leftKeyIdx;
  224. UINT32 rightKeyIdx;
  225. findKeys(time, leftKeyIdx, rightKeyIdx);
  226. // Evaluate curve as hermite cubic spline
  227. const KeyFrame& leftKey = mKeyframes[leftKeyIdx];
  228. const KeyFrame& rightKey = mKeyframes[rightKeyIdx];
  229. if (leftKeyIdx == rightKeyIdx)
  230. return leftKey.value;
  231. float length = rightKey.time - leftKey.time;
  232. assert(length > 0.0f);
  233. float t;
  234. T leftTangent;
  235. T rightTangent;
  236. if (Math::approxEquals(length, 0.0f))
  237. {
  238. t = 0.0f;
  239. leftTangent = getZero<T>();
  240. rightTangent = getZero<T>();
  241. }
  242. else
  243. {
  244. // Scale from arbitrary range to [0, 1]
  245. t = (time - leftKey.time) / length;
  246. leftTangent = leftKey.outTangent * length;
  247. rightTangent = rightKey.inTangent * length;
  248. }
  249. T output = Math::cubicHermite(t, leftKey.value, rightKey.value, leftTangent, rightTangent);
  250. setStepValue(leftKey, rightKey, output);
  251. return output;
  252. }
  253. template <class T>
  254. TKeyframe<T> TAnimationCurve<T>::evaluateKey(float time, bool loop) const
  255. {
  256. if (mKeyframes.size() == 0)
  257. return TKeyframe<T>();
  258. AnimationUtility::wrapTime(time, mStart, mEnd, loop);
  259. UINT32 leftKeyIdx;
  260. UINT32 rightKeyIdx;
  261. findKeys(time, leftKeyIdx, rightKeyIdx);
  262. const KeyFrame& leftKey = mKeyframes[leftKeyIdx];
  263. const KeyFrame& rightKey = mKeyframes[rightKeyIdx];
  264. if (leftKeyIdx == rightKeyIdx)
  265. return leftKey;
  266. return evaluateKey(leftKey, rightKey, time);
  267. }
  268. template <class T>
  269. T TAnimationCurve<T>::evaluateCache(float time, const TCurveCache<T>& cache) const
  270. {
  271. float t = time - cache.cachedCurveStart;
  272. const T* coeffs = cache.cachedCubicCoefficients;
  273. return t * (t * (t * coeffs[0] + coeffs[1]) + coeffs[2]) + coeffs[3];
  274. }
  275. template <class T>
  276. void TAnimationCurve<T>::findKeys(float time, const TCurveCache<T>& animInstance, UINT32& leftKey, UINT32& rightKey) const
  277. {
  278. // Check nearby keys first if there is cached data
  279. if (animInstance.cachedKey != (UINT32)-1)
  280. {
  281. const KeyFrame& curKey = mKeyframes[animInstance.cachedKey];
  282. if (time >= curKey.time)
  283. {
  284. UINT32 end = std::min((UINT32)mKeyframes.size(), animInstance.cachedKey + CACHE_LOOKAHEAD + 1);
  285. for (UINT32 i = animInstance.cachedKey + 1; i < end; i++)
  286. {
  287. const KeyFrame& nextKey = mKeyframes[i];
  288. if (time < nextKey.time)
  289. {
  290. leftKey = i - 1;
  291. rightKey = i;
  292. animInstance.cachedKey = leftKey;
  293. return;
  294. }
  295. }
  296. }
  297. else
  298. {
  299. UINT32 start = (UINT32)std::max(0, (INT32)animInstance.cachedKey - (INT32)CACHE_LOOKAHEAD);
  300. for(UINT32 i = start; i < animInstance.cachedKey; i++)
  301. {
  302. const KeyFrame& prevKey = mKeyframes[i];
  303. if (time >= prevKey.time)
  304. {
  305. leftKey = i;
  306. rightKey = i + 1;
  307. animInstance.cachedKey = leftKey;
  308. return;
  309. }
  310. }
  311. }
  312. }
  313. // Cannot find nearby ones, search all keys
  314. findKeys(time, leftKey, rightKey);
  315. animInstance.cachedKey = leftKey;
  316. }
  317. template <class T>
  318. void TAnimationCurve<T>::findKeys(float time, UINT32& leftKey, UINT32& rightKey) const
  319. {
  320. INT32 start = 0;
  321. INT32 searchLength = (INT32)mKeyframes.size();
  322. while(searchLength > 0)
  323. {
  324. INT32 half = searchLength >> 1;
  325. INT32 mid = start + half;
  326. if(time < mKeyframes[mid].time)
  327. {
  328. searchLength = half;
  329. }
  330. else
  331. {
  332. start = mid + 1;
  333. searchLength -= (half + 1);
  334. }
  335. }
  336. leftKey = std::max(0, start - 1);
  337. rightKey = std::min(start, (INT32)mKeyframes.size() - 1);
  338. }
  339. template <class T>
  340. UINT32 TAnimationCurve<T>::findKey(float time)
  341. {
  342. UINT32 leftKeyIdx;
  343. UINT32 rightKeyIdx;
  344. findKeys(time, leftKeyIdx, rightKeyIdx);
  345. const KeyFrame& leftKey = mKeyframes[leftKeyIdx];
  346. const KeyFrame& rightKey = mKeyframes[rightKeyIdx];
  347. if (Math::abs(leftKey.time - time) <= Math::abs(rightKey.time - time))
  348. return leftKeyIdx;
  349. return rightKeyIdx;
  350. }
  351. template <class T>
  352. TKeyframe<T> TAnimationCurve<T>::evaluateKey(const KeyFrame& lhs, const KeyFrame& rhs, float time) const
  353. {
  354. float length = rhs.time - lhs.time;
  355. float t;
  356. T leftTangent;
  357. T rightTangent;
  358. if (Math::approxEquals(length, 0.0f))
  359. return lhs;
  360. // Resize tangents since we're not evaluating the curve over unit range
  361. float invLength = 1.0f / length;
  362. t = (time - lhs.time) * invLength;
  363. leftTangent = lhs.outTangent * length;
  364. rightTangent = rhs.inTangent * length;
  365. TKeyframe<T> output;
  366. output.time = time;
  367. output.value = Math::cubicHermite(t, lhs.value, rhs.value, leftTangent, rightTangent);
  368. output.inTangent = Math::cubicHermiteD1(t, lhs.value, rhs.value, leftTangent, rightTangent) * invLength;
  369. setStepValue(lhs, rhs, output.value);
  370. setStepTangent(lhs, rhs, output.inTangent);
  371. output.outTangent = output.inTangent;
  372. return output;
  373. }
  374. template <class T>
  375. TAnimationCurve<T> TAnimationCurve<T>::split(float start, float end)
  376. {
  377. Vector<TKeyframe<T>> keyFrames;
  378. start = Math::clamp(start, mStart, mEnd);
  379. end = Math::clamp(end, mStart, mEnd);
  380. if (Math::approxEquals(end - start, 0.0f))
  381. return TAnimationCurve<T>();
  382. UINT32 startKeyIdx = findKey(start);
  383. UINT32 endKeyIdx = findKey(end);
  384. keyFrames.reserve(endKeyIdx - startKeyIdx + 2);
  385. const KeyFrame& startKey = mKeyframes[startKeyIdx];
  386. const KeyFrame& endKey = mKeyframes[endKeyIdx];
  387. if (!Math::approxEquals(startKey.time, start))
  388. {
  389. keyFrames.push_back(evaluateKey(startKey, mKeyframes[startKeyIdx + 1], start));
  390. if (start > startKey.time)
  391. startKeyIdx++;
  392. }
  393. else
  394. {
  395. keyFrames.push_back(startKey);
  396. startKeyIdx++;
  397. }
  398. if(!Math::approxEquals(endKey.time, end))
  399. {
  400. keyFrames.push_back(evaluateKey(endKey, mKeyframes[endKeyIdx + 1], end));
  401. if (end < endKey.time)
  402. endKeyIdx--;
  403. }
  404. keyFrames.insert(keyFrames.begin() + 1, mKeyframes.begin() + startKeyIdx, mKeyframes.begin() + endKeyIdx + 1);
  405. for (auto& entry : keyFrames)
  406. entry.time -= start;
  407. return TAnimationCurve<T>(keyFrames);
  408. }
  409. template <class T>
  410. void TAnimationCurve<T>::makeAdditive()
  411. {
  412. if (mKeyframes.size() < 2)
  413. return;
  414. const KeyFrame& refKey = mKeyframes[0];
  415. UINT32 numKeys = (UINT32)mKeyframes.size();
  416. for(UINT32 i = 1; i < numKeys; i++)
  417. mKeyframes[i].value = getDiff(mKeyframes[i].value, refKey.value);
  418. }
  419. template class TAnimationCurve<Vector3>;
  420. template class TAnimationCurve<Quaternion>;
  421. template class TAnimationCurve<float>;
  422. }