BsAnimationCurve.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Animation/BsAnimationCurve.h"
  4. #include "Private/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. // Handle the case where both keys are identical, or close enough to cause precision issues
  211. if(length < 0.000001f)
  212. {
  213. cache.cachedCubicCoefficients[0] = getZero<T>();
  214. cache.cachedCubicCoefficients[1] = getZero<T>();
  215. cache.cachedCubicCoefficients[2] = getZero<T>();
  216. cache.cachedCubicCoefficients[3] = leftKey.value;
  217. return leftKey.value;
  218. }
  219. Math::cubicHermiteCoefficients(leftKey.value, rightKey.value, leftKey.outTangent, rightKey.inTangent, length,
  220. cache.cachedCubicCoefficients);
  221. setStepCoefficients(leftKey, rightKey, cache.cachedCubicCoefficients);
  222. T output = evaluateCache(time, cache);
  223. return output;
  224. }
  225. template <class T>
  226. T TAnimationCurve<T>::evaluate(float time, bool loop) const
  227. {
  228. if (mKeyframes.size() == 0)
  229. return getZero<T>();
  230. AnimationUtility::wrapTime(time, mStart, mEnd, loop);
  231. UINT32 leftKeyIdx;
  232. UINT32 rightKeyIdx;
  233. findKeys(time, leftKeyIdx, rightKeyIdx);
  234. // Evaluate curve as hermite cubic spline
  235. const KeyFrame& leftKey = mKeyframes[leftKeyIdx];
  236. const KeyFrame& rightKey = mKeyframes[rightKeyIdx];
  237. if (leftKeyIdx == rightKeyIdx)
  238. return leftKey.value;
  239. float length = rightKey.time - leftKey.time;
  240. assert(length > 0.0f);
  241. float t;
  242. T leftTangent;
  243. T rightTangent;
  244. if (Math::approxEquals(length, 0.0f))
  245. {
  246. t = 0.0f;
  247. leftTangent = getZero<T>();
  248. rightTangent = getZero<T>();
  249. }
  250. else
  251. {
  252. // Scale from arbitrary range to [0, 1]
  253. t = (time - leftKey.time) / length;
  254. leftTangent = leftKey.outTangent * length;
  255. rightTangent = rightKey.inTangent * length;
  256. }
  257. T output = Math::cubicHermite(t, leftKey.value, rightKey.value, leftTangent, rightTangent);
  258. setStepValue(leftKey, rightKey, output);
  259. return output;
  260. }
  261. template <class T>
  262. TKeyframe<T> TAnimationCurve<T>::evaluateKey(float time, bool loop) const
  263. {
  264. if (mKeyframes.size() == 0)
  265. return TKeyframe<T>();
  266. AnimationUtility::wrapTime(time, mStart, mEnd, loop);
  267. UINT32 leftKeyIdx;
  268. UINT32 rightKeyIdx;
  269. findKeys(time, leftKeyIdx, rightKeyIdx);
  270. const KeyFrame& leftKey = mKeyframes[leftKeyIdx];
  271. const KeyFrame& rightKey = mKeyframes[rightKeyIdx];
  272. if (leftKeyIdx == rightKeyIdx)
  273. return leftKey;
  274. return evaluateKey(leftKey, rightKey, time);
  275. }
  276. template <class T>
  277. T TAnimationCurve<T>::evaluateCache(float time, const TCurveCache<T>& cache) const
  278. {
  279. float t = time - cache.cachedCurveStart;
  280. const T* coeffs = cache.cachedCubicCoefficients;
  281. return t * (t * (t * coeffs[0] + coeffs[1]) + coeffs[2]) + coeffs[3];
  282. }
  283. template <class T>
  284. void TAnimationCurve<T>::findKeys(float time, const TCurveCache<T>& animInstance, UINT32& leftKey, UINT32& rightKey) const
  285. {
  286. // Check nearby keys first if there is cached data
  287. if (animInstance.cachedKey != (UINT32)-1)
  288. {
  289. const KeyFrame& curKey = mKeyframes[animInstance.cachedKey];
  290. if (time >= curKey.time)
  291. {
  292. UINT32 end = std::min((UINT32)mKeyframes.size(), animInstance.cachedKey + CACHE_LOOKAHEAD + 1);
  293. for (UINT32 i = animInstance.cachedKey + 1; i < end; i++)
  294. {
  295. const KeyFrame& nextKey = mKeyframes[i];
  296. if (time < nextKey.time)
  297. {
  298. leftKey = i - 1;
  299. rightKey = i;
  300. animInstance.cachedKey = leftKey;
  301. return;
  302. }
  303. }
  304. }
  305. else
  306. {
  307. UINT32 start = (UINT32)std::max(0, (INT32)animInstance.cachedKey - (INT32)CACHE_LOOKAHEAD);
  308. for(UINT32 i = start; i < animInstance.cachedKey; i++)
  309. {
  310. const KeyFrame& prevKey = mKeyframes[i];
  311. if (time >= prevKey.time)
  312. {
  313. leftKey = i;
  314. rightKey = i + 1;
  315. animInstance.cachedKey = leftKey;
  316. return;
  317. }
  318. }
  319. }
  320. }
  321. // Cannot find nearby ones, search all keys
  322. findKeys(time, leftKey, rightKey);
  323. animInstance.cachedKey = leftKey;
  324. }
  325. template <class T>
  326. void TAnimationCurve<T>::findKeys(float time, UINT32& leftKey, UINT32& rightKey) const
  327. {
  328. INT32 start = 0;
  329. INT32 searchLength = (INT32)mKeyframes.size();
  330. while(searchLength > 0)
  331. {
  332. INT32 half = searchLength >> 1;
  333. INT32 mid = start + half;
  334. if(time < mKeyframes[mid].time)
  335. {
  336. searchLength = half;
  337. }
  338. else
  339. {
  340. start = mid + 1;
  341. searchLength -= (half + 1);
  342. }
  343. }
  344. leftKey = std::max(0, start - 1);
  345. rightKey = std::min(start, (INT32)mKeyframes.size() - 1);
  346. }
  347. template <class T>
  348. UINT32 TAnimationCurve<T>::findKey(float time)
  349. {
  350. UINT32 leftKeyIdx;
  351. UINT32 rightKeyIdx;
  352. findKeys(time, leftKeyIdx, rightKeyIdx);
  353. const KeyFrame& leftKey = mKeyframes[leftKeyIdx];
  354. const KeyFrame& rightKey = mKeyframes[rightKeyIdx];
  355. if (Math::abs(leftKey.time - time) <= Math::abs(rightKey.time - time))
  356. return leftKeyIdx;
  357. return rightKeyIdx;
  358. }
  359. template <class T>
  360. TKeyframe<T> TAnimationCurve<T>::evaluateKey(const KeyFrame& lhs, const KeyFrame& rhs, float time) const
  361. {
  362. float length = rhs.time - lhs.time;
  363. float t;
  364. T leftTangent;
  365. T rightTangent;
  366. if (Math::approxEquals(length, 0.0f))
  367. return lhs;
  368. // Resize tangents since we're not evaluating the curve over unit range
  369. float invLength = 1.0f / length;
  370. t = (time - lhs.time) * invLength;
  371. leftTangent = lhs.outTangent * length;
  372. rightTangent = rhs.inTangent * length;
  373. TKeyframe<T> output;
  374. output.time = time;
  375. output.value = Math::cubicHermite(t, lhs.value, rhs.value, leftTangent, rightTangent);
  376. output.inTangent = Math::cubicHermiteD1(t, lhs.value, rhs.value, leftTangent, rightTangent) * invLength;
  377. setStepValue(lhs, rhs, output.value);
  378. setStepTangent(lhs, rhs, output.inTangent);
  379. output.outTangent = output.inTangent;
  380. return output;
  381. }
  382. template <class T>
  383. TAnimationCurve<T> TAnimationCurve<T>::split(float start, float end)
  384. {
  385. Vector<TKeyframe<T>> keyFrames;
  386. start = Math::clamp(start, mStart, mEnd);
  387. end = Math::clamp(end, mStart, mEnd);
  388. if (Math::approxEquals(end - start, 0.0f))
  389. return TAnimationCurve<T>();
  390. UINT32 startKeyIdx = findKey(start);
  391. UINT32 endKeyIdx = findKey(end);
  392. keyFrames.reserve(endKeyIdx - startKeyIdx + 2);
  393. const KeyFrame& startKey = mKeyframes[startKeyIdx];
  394. const KeyFrame& endKey = mKeyframes[endKeyIdx];
  395. if (!Math::approxEquals(startKey.time, start))
  396. {
  397. if(start > startKey.time)
  398. {
  399. if (mKeyframes.size() > (startKeyIdx + 1))
  400. keyFrames.push_back(evaluateKey(startKey, mKeyframes[startKeyIdx + 1], start));
  401. else
  402. {
  403. TKeyframe<T> keyCopy = startKey;
  404. keyCopy.time = start;
  405. keyFrames.push_back(keyCopy);
  406. }
  407. startKeyIdx++;
  408. }
  409. else
  410. {
  411. if (startKeyIdx > 0)
  412. keyFrames.push_back(evaluateKey(mKeyframes[startKeyIdx - 1], startKey , start));
  413. else
  414. {
  415. TKeyframe<T> keyCopy = startKey;
  416. keyCopy.time = start;
  417. keyFrames.push_back(keyCopy);
  418. }
  419. }
  420. }
  421. else
  422. {
  423. keyFrames.push_back(startKey);
  424. startKeyIdx++;
  425. }
  426. if(!Math::approxEquals(endKey.time, end))
  427. {
  428. if(end > endKey.time)
  429. {
  430. if (mKeyframes.size() > (endKeyIdx + 1))
  431. keyFrames.push_back(evaluateKey(endKey, mKeyframes[endKeyIdx + 1], end));
  432. else
  433. {
  434. TKeyframe<T> keyCopy = endKey;
  435. keyCopy.time = end;
  436. keyFrames.push_back(keyCopy);
  437. }
  438. }
  439. else
  440. {
  441. if(endKeyIdx > 0)
  442. {
  443. keyFrames.push_back(evaluateKey(mKeyframes[endKeyIdx - 1], endKey, end));
  444. endKeyIdx--;
  445. }
  446. else
  447. {
  448. TKeyframe<T> keyCopy = endKey;
  449. keyCopy.time = end;
  450. keyFrames.push_back(keyCopy);
  451. }
  452. }
  453. }
  454. if(startKeyIdx < (UINT32)mKeyframes.size() && endKeyIdx > startKeyIdx)
  455. keyFrames.insert(keyFrames.begin() + 1, mKeyframes.begin() + startKeyIdx, mKeyframes.begin() + endKeyIdx + 1);
  456. for (auto& entry : keyFrames)
  457. entry.time -= start;
  458. return TAnimationCurve<T>(keyFrames);
  459. }
  460. template <class T>
  461. void TAnimationCurve<T>::makeAdditive()
  462. {
  463. if (mKeyframes.size() < 2)
  464. return;
  465. const KeyFrame& refKey = mKeyframes[0];
  466. UINT32 numKeys = (UINT32)mKeyframes.size();
  467. for(UINT32 i = 1; i < numKeys; i++)
  468. mKeyframes[i].value = getDiff(mKeyframes[i].value, refKey.value);
  469. }
  470. template class TAnimationCurve<Vector3>;
  471. template class TAnimationCurve<Quaternion>;
  472. template class TAnimationCurve<float>;
  473. }