babylon.animation.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. "use strict";
  2. var BABYLON = BABYLON || {};
  3. (function () {
  4. BABYLON.Animation = function (name, targetProperty, framePerSecond, dataType, loopMode) {
  5. this.name = name;
  6. this.targetProperty = targetProperty;
  7. this.targetPropertyPath = targetProperty.split(".");
  8. this.framePerSecond = framePerSecond;
  9. this.dataType = dataType;
  10. this.loopMode = loopMode === undefined ? BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE : loopMode;
  11. this._keys = [];
  12. // Cache
  13. this._offsetsCache = {};
  14. this._highLimitsCache = {};
  15. };
  16. // Methods
  17. BABYLON.Animation.prototype.clone = function() {
  18. var clone = new BABYLON.Animation(this.name, this.targetPropertyPath.join("."), this.framePerSecond, this.dataType, this.loopMode);
  19. clone.setKeys(this._keys);
  20. return clone;
  21. };
  22. BABYLON.Animation.prototype.setKeys = function(values) {
  23. this._keys = values.slice(0);
  24. this._offsetsCache = {};
  25. this._highLimitsCache = {};
  26. };
  27. BABYLON.Animation.prototype._interpolate = function (currentFrame, repeatCount, loopMode, offsetValue, highLimitValue) {
  28. if (loopMode === BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT && repeatCount > 0) {
  29. return highLimitValue.clone ? highLimitValue.clone() : highLimitValue;
  30. }
  31. for (var key = 0; key < this._keys.length; key++) {
  32. if (this._keys[key + 1].frame >= currentFrame) {
  33. var startValue = this._keys[key].value;
  34. var endValue = this._keys[key + 1].value;
  35. var gradient = (currentFrame - this._keys[key].frame) / (this._keys[key + 1].frame - this._keys[key].frame);
  36. switch (this.dataType) {
  37. // Float
  38. case BABYLON.Animation.ANIMATIONTYPE_FLOAT:
  39. switch (loopMode) {
  40. case BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE:
  41. case BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT:
  42. return startValue + (endValue - startValue) * gradient;
  43. case BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE:
  44. return offsetValue * repeatCount + (startValue + (endValue - startValue) * gradient);
  45. }
  46. break;
  47. // Quaternion
  48. case BABYLON.Animation.ANIMATIONTYPE_QUATERNION:
  49. var quaternion = null;
  50. switch (loopMode) {
  51. case BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE:
  52. case BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT:
  53. quaternion = BABYLON.Quaternion.Slerp(startValue, endValue, gradient);
  54. break;
  55. case BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE:
  56. quaternion = BABYLON.Quaternion.Slerp(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
  57. break;
  58. }
  59. return quaternion;
  60. // Vector3
  61. case BABYLON.Animation.ANIMATIONTYPE_VECTOR3:
  62. switch (loopMode) {
  63. case BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE:
  64. case BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT:
  65. return BABYLON.Vector3.Lerp(startValue, endValue, gradient);
  66. case BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE:
  67. return BABYLON.Vector3.Lerp(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
  68. }
  69. // Matrix
  70. case BABYLON.Animation.ANIMATIONTYPE_MATRIX:
  71. switch (loopMode) {
  72. case BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE:
  73. case BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT:
  74. case BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE:
  75. return startValue;
  76. }
  77. default:
  78. break;
  79. }
  80. break;
  81. }
  82. }
  83. return this._keys[this._keys.length - 1].value;
  84. };
  85. BABYLON.Animation.prototype.animate = function (target, delay, from, to, loop, speedRatio) {
  86. if (!this.targetPropertyPath || this.targetPropertyPath.length < 1) {
  87. return false;
  88. }
  89. var returnValue = true;
  90. // Adding a start key at frame 0 if missing
  91. if (this._keys[0].frame != 0) {
  92. var newKey = {
  93. frame: 0,
  94. value: this._keys[0].value
  95. };
  96. this._keys.splice(0, 0, newKey);
  97. }
  98. // Check limits
  99. if (from < this._keys[0].frame || from > this._keys[this._keys.length - 1].frame) {
  100. from = this._keys[0].frame;
  101. }
  102. if (to < this._keys[0].frame || to > this._keys[this._keys.length - 1].frame) {
  103. to = this._keys[this._keys.length - 1].frame;
  104. }
  105. // Compute ratio
  106. var range = to - from;
  107. var ratio = delay * (this.framePerSecond * speedRatio) / 1000.0;
  108. if (ratio > range && !loop) { // If we are out of range and not looping get back to caller
  109. offsetValue = 0;
  110. returnValue = false;
  111. } else {
  112. // Get max value if required
  113. var offsetValue = 0;
  114. var highLimitValue = 0;
  115. if (this.loopMode != BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE) {
  116. var keyOffset = to.toString() + from.toString();
  117. if (!this._offsetsCache[keyOffset]) {
  118. var fromValue = this._interpolate(from, 0, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
  119. var toValue = this._interpolate(to, 0, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
  120. switch (this.dataType) {
  121. // Float
  122. case BABYLON.Animation.ANIMATIONTYPE_FLOAT:
  123. this._offsetsCache[keyOffset] = toValue - fromValue;
  124. break;
  125. // Quaternion
  126. case BABYLON.Animation.ANIMATIONTYPE_QUATERNION:
  127. this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
  128. break;
  129. // Vector3
  130. case BABYLON.Animation.ANIMATIONTYPE_VECTOR3:
  131. this._offsetsCache[keyOffset] = toValue.subtract(fromValue);
  132. default:
  133. break;
  134. }
  135. this._highLimitsCache[keyOffset] = toValue;
  136. }
  137. highLimitValue = this._highLimitsCache[keyOffset];
  138. offsetValue = this._offsetsCache[keyOffset];
  139. }
  140. }
  141. // Compute value
  142. var repeatCount = (ratio / range) >> 0;
  143. var currentFrame = returnValue ? from + ratio % range : to;
  144. var currentValue = this._interpolate(currentFrame, repeatCount, this.loopMode, offsetValue, highLimitValue);
  145. // Set value
  146. if (this.targetPropertyPath.length > 1) {
  147. var property = target[this.targetPropertyPath[0]];
  148. for (var index = 1; index < this.targetPropertyPath.length - 1; index++) {
  149. property = property[this.targetPropertyPath[index]];
  150. }
  151. property[this.targetPropertyPath[this.targetPropertyPath.length - 1]] = currentValue;
  152. } else {
  153. target[this.targetPropertyPath[0]] = currentValue;
  154. }
  155. if (target.markAsDirty) {
  156. target.markAsDirty(this.targetProperty);
  157. }
  158. return returnValue;
  159. };
  160. // Statics
  161. BABYLON.Animation.ANIMATIONTYPE_FLOAT = 0;
  162. BABYLON.Animation.ANIMATIONTYPE_VECTOR3 = 1;
  163. BABYLON.Animation.ANIMATIONTYPE_QUATERNION = 2;
  164. BABYLON.Animation.ANIMATIONTYPE_MATRIX = 3;
  165. BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE = 0;
  166. BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE = 1;
  167. BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT = 2;
  168. })();