BsAnimationCurve.cpp 13 KB

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