BsAnimationCurve.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsAnimationCurve.h"
  4. #include "BsAnimationCurveRTTI.h"
  5. #include "BsVector3.h"
  6. #include "BsQuaternion.h"
  7. #include "BsMath.h"
  8. #include "BsAnimationUtility.h"
  9. namespace BansheeEngine
  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. {
  153. mStart = keyframes[0].time;
  154. mEnd = keyframes.back().time;
  155. }
  156. else
  157. {
  158. mStart = 0.0f;
  159. mEnd = 0.0f;
  160. }
  161. mLength = mEnd - mStart;
  162. }
  163. template <class T>
  164. T TAnimationCurve<T>::evaluate(float time, const TCurveCache<T>& cache, bool loop) const
  165. {
  166. if (mKeyframes.size() == 0)
  167. return getZero<T>();
  168. // Wrap time if looping
  169. if(loop)
  170. {
  171. if (time < mStart)
  172. time = time + (std::floor(mEnd - time) / mLength) * mLength;
  173. else if (time > mEnd)
  174. time = time - std::floor((time - mStart) / mLength) * mLength;
  175. }
  176. // If time is within cache, evaluate it directly
  177. if (time >= cache.cachedCurveStart && time < cache.cachedCurveEnd)
  178. return evaluateCache(time, cache);
  179. // Clamp to start, cache constant of the first key and return
  180. if(time < mStart)
  181. {
  182. cache.cachedCurveStart = -std::numeric_limits<float>::infinity();
  183. cache.cachedCurveEnd = mStart;
  184. cache.cachedKey = 0;
  185. cache.cachedCubicCoefficients[0] = getZero<T>();
  186. cache.cachedCubicCoefficients[1] = getZero<T>();
  187. cache.cachedCubicCoefficients[2] = getZero<T>();
  188. cache.cachedCubicCoefficients[3] = mKeyframes[0].value;
  189. return mKeyframes[0].value;
  190. }
  191. if(time > mEnd) // Clamp to end, cache constant of the final key and return
  192. {
  193. UINT32 lastKey = (UINT32)mKeyframes.size() - 1;
  194. cache.cachedCurveStart = mEnd;
  195. cache.cachedCurveEnd = std::numeric_limits<float>::infinity();
  196. cache.cachedKey = lastKey;
  197. cache.cachedCubicCoefficients[0] = getZero<T>();
  198. cache.cachedCubicCoefficients[1] = getZero<T>();
  199. cache.cachedCubicCoefficients[2] = getZero<T>();
  200. cache.cachedCubicCoefficients[3] = mKeyframes[lastKey].value;
  201. return mKeyframes[lastKey].value;
  202. }
  203. // Since our value is not in cache, search for the valid pair of keys of interpolate
  204. UINT32 leftKeyIdx;
  205. UINT32 rightKeyIdx;
  206. findKeys(time, cache, leftKeyIdx, rightKeyIdx);
  207. // Calculate cubic hermite curve coefficients so we can store them in cache
  208. const KeyFrame& leftKey = mKeyframes[leftKeyIdx];
  209. const KeyFrame& rightKey = mKeyframes[rightKeyIdx];
  210. cache.cachedCurveStart = leftKey.time;
  211. cache.cachedCurveEnd = rightKey.time;
  212. float length = rightKey.time - leftKey.time;
  213. Math::cubicHermiteCoefficients(leftKey.value, rightKey.value, leftKey.outTangent, rightKey.inTangent, length,
  214. cache.cachedCubicCoefficients);
  215. setStepCoefficients(leftKey, rightKey, cache.cachedCubicCoefficients);
  216. T output = evaluateCache(time, cache);
  217. return output;
  218. }
  219. template <class T>
  220. T TAnimationCurve<T>::evaluate(float time, bool loop) const
  221. {
  222. if (mKeyframes.size() == 0)
  223. return getZero<T>();
  224. AnimationUtility::wrapTime(time, mStart, mEnd, loop);
  225. UINT32 leftKeyIdx;
  226. UINT32 rightKeyIdx;
  227. findKeys(time, leftKeyIdx, rightKeyIdx);
  228. // Evaluate curve as hermite cubic spline
  229. const KeyFrame& leftKey = mKeyframes[leftKeyIdx];
  230. const KeyFrame& rightKey = mKeyframes[rightKeyIdx];
  231. float length = rightKey.time - leftKey.time;
  232. float t;
  233. T leftTangent;
  234. T rightTangent;
  235. if (Math::approxEquals(length, 0.0f))
  236. {
  237. t = 0.0f;
  238. leftTangent = getZero<T>();
  239. rightTangent = getZero<T>();
  240. }
  241. else
  242. {
  243. // Scale from arbitrary range to [0, 1]
  244. t = (time - leftKey.time) / length;
  245. leftTangent = leftKey.outTangent * length;
  246. rightTangent = rightKey.inTangent * length;
  247. }
  248. T output = Math::cubicHermite(t, leftKey.value, rightKey.value, leftTangent, rightTangent);
  249. setStepValue(leftKey, rightKey, output);
  250. return output;
  251. }
  252. template <class T>
  253. TKeyframe<T> TAnimationCurve<T>::evaluateKey(float time, bool loop) const
  254. {
  255. if (mKeyframes.size() == 0)
  256. return TKeyframe<T>();
  257. AnimationUtility::wrapTime(time, mStart, mEnd, loop);
  258. UINT32 leftKeyIdx;
  259. UINT32 rightKeyIdx;
  260. findKeys(time, leftKeyIdx, rightKeyIdx);
  261. const KeyFrame& leftKey = mKeyframes[leftKeyIdx];
  262. const KeyFrame& rightKey = mKeyframes[rightKeyIdx];
  263. return evaluateKey(leftKey, rightKey, time);
  264. }
  265. template <class T>
  266. T TAnimationCurve<T>::evaluateCache(float time, const TCurveCache<T>& cache) const
  267. {
  268. float t = time - cache.cachedCurveStart;
  269. const T* coeffs = cache.cachedCubicCoefficients;
  270. return t * (t * (t * coeffs[0] + coeffs[1]) + coeffs[2]) + coeffs[3];
  271. }
  272. template <class T>
  273. void TAnimationCurve<T>::findKeys(float time, const TCurveCache<T>& animInstance, UINT32& leftKey, UINT32& rightKey) const
  274. {
  275. // Check nearby keys first if there is cached data
  276. if (animInstance.cachedKey != (UINT32)-1)
  277. {
  278. const KeyFrame& curKey = mKeyframes[animInstance.cachedKey];
  279. if (time >= curKey.time)
  280. {
  281. UINT32 end = std::min((UINT32)mKeyframes.size(), animInstance.cachedKey + CACHE_LOOKAHEAD + 1);
  282. for (UINT32 i = animInstance.cachedKey + 1; i < end; i++)
  283. {
  284. const KeyFrame& nextKey = mKeyframes[i];
  285. if (time < nextKey.time)
  286. {
  287. leftKey = i - 1;
  288. rightKey = i;
  289. animInstance.cachedKey = leftKey;
  290. return;
  291. }
  292. }
  293. }
  294. else
  295. {
  296. UINT32 start = (UINT32)std::max(0, (INT32)animInstance.cachedKey - (INT32)CACHE_LOOKAHEAD);
  297. for(UINT32 i = start; i < animInstance.cachedKey; i++)
  298. {
  299. const KeyFrame& prevKey = mKeyframes[i];
  300. if (time >= prevKey.time)
  301. {
  302. leftKey = i;
  303. rightKey = i + 1;
  304. animInstance.cachedKey = leftKey;
  305. return;
  306. }
  307. }
  308. }
  309. }
  310. // Cannot find nearby ones, search all keys
  311. findKeys(time, leftKey, rightKey);
  312. animInstance.cachedKey = leftKey;
  313. }
  314. template <class T>
  315. void TAnimationCurve<T>::findKeys(float time, UINT32& leftKey, UINT32& rightKey) const
  316. {
  317. INT32 start = 0;
  318. INT32 searchLength = (INT32)mKeyframes.size();
  319. while(searchLength > 0)
  320. {
  321. INT32 half = searchLength >> 1;
  322. INT32 mid = start + half;
  323. if(time < mKeyframes[mid].time)
  324. {
  325. searchLength = half;
  326. }
  327. else
  328. {
  329. start = mid + 1;
  330. searchLength -= (half + 1);
  331. }
  332. }
  333. leftKey = std::max(0, start - 1);
  334. rightKey = std::min(start, (INT32)mKeyframes.size() - 1);
  335. }
  336. template <class T>
  337. UINT32 TAnimationCurve<T>::findKey(float time)
  338. {
  339. UINT32 leftKeyIdx;
  340. UINT32 rightKeyIdx;
  341. findKeys(time, leftKeyIdx, rightKeyIdx);
  342. const KeyFrame& leftKey = mKeyframes[leftKeyIdx];
  343. const KeyFrame& rightKey = mKeyframes[rightKeyIdx];
  344. if (Math::abs(leftKey.time - time) <= Math::abs(rightKey.time - time))
  345. return leftKeyIdx;
  346. return rightKeyIdx;
  347. }
  348. template <class T>
  349. TKeyframe<T> TAnimationCurve<T>::evaluateKey(const KeyFrame& lhs, const KeyFrame& rhs, float time) const
  350. {
  351. float length = rhs.time - lhs.time;
  352. float t;
  353. T leftTangent;
  354. T rightTangent;
  355. if (Math::approxEquals(length, 0.0f))
  356. {
  357. t = 0.0f;
  358. leftTangent = getZero<T>();
  359. rightTangent = getZero<T>();
  360. }
  361. else
  362. {
  363. // Resize tangents since we're not evaluating the curve over unit range
  364. t = (time - lhs.time) / length;
  365. leftTangent = lhs.outTangent * length;
  366. rightTangent = rhs.inTangent * length;
  367. }
  368. TKeyframe<T> output;
  369. output.time = time;
  370. output.value = Math::cubicHermite(t, lhs.value, rhs.value, leftTangent, rightTangent);
  371. output.inTangent = Math::cubicHermiteD1(t, lhs.value, rhs.value, leftTangent, rightTangent);
  372. setStepValue(lhs, rhs, output.value);
  373. setStepTangent(lhs, rhs, output.inTangent);
  374. output.outTangent = output.inTangent;
  375. return output;
  376. }
  377. template <class T>
  378. TAnimationCurve<T> TAnimationCurve<T>::split(float start, float end)
  379. {
  380. Vector<TKeyframe<T>> keyFrames;
  381. start = Math::clamp(start, mStart, mEnd);
  382. end = Math::clamp(end, mStart, mEnd);
  383. if (Math::approxEquals(end - start, 0.0f))
  384. return TAnimationCurve<T>();
  385. UINT32 startKeyIdx = findKey(start);
  386. UINT32 endKeyIdx = findKey(end);
  387. keyFrames.reserve(endKeyIdx - startKeyIdx + 2);
  388. const KeyFrame& startKey = mKeyframes[startKeyIdx];
  389. const KeyFrame& endKey = mKeyframes[endKeyIdx];
  390. if (!Math::approxEquals(startKey.time, start))
  391. {
  392. keyFrames.push_back(evaluateKey(startKey, mKeyframes[startKeyIdx + 1], start));
  393. if (start > startKey.time)
  394. startKeyIdx++;
  395. }
  396. else
  397. {
  398. keyFrames.push_back(startKey);
  399. startKeyIdx++;
  400. }
  401. if(!Math::approxEquals(endKey.time, end))
  402. {
  403. keyFrames.push_back(evaluateKey(endKey, mKeyframes[endKeyIdx + 1], end));
  404. if (end < endKey.time)
  405. endKeyIdx--;
  406. }
  407. keyFrames.insert(keyFrames.begin() + 1, mKeyframes.begin() + startKeyIdx, mKeyframes.begin() + endKeyIdx + 1);
  408. for (auto& entry : keyFrames)
  409. entry.time -= start;
  410. return TAnimationCurve<T>(keyFrames);
  411. }
  412. template <class T>
  413. void TAnimationCurve<T>::makeAdditive()
  414. {
  415. if (mKeyframes.size() < 2)
  416. return;
  417. const KeyFrame& refKey = mKeyframes[0];
  418. UINT32 numKeys = (UINT32)mKeyframes.size();
  419. for(UINT32 i = 1; i < numKeys; i++)
  420. mKeyframes[i].value = getDiff(mKeyframes[i].value, refKey.value);
  421. }
  422. template class TAnimationCurve<Vector3>;
  423. template class TAnimationCurve<Quaternion>;
  424. template class TAnimationCurve<float>;
  425. }