animation.ts 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  1. import { IEasingFunction, EasingFunction } from "./easing";
  2. import { Vector3, Quaternion, Vector2, Matrix } from "../Maths/math.vector";
  3. import { Color3 } from '../Maths/math.color';
  4. import { Scalar } from "../Maths/math.scalar";
  5. import { Nullable } from "../types";
  6. import { Scene } from "../scene";
  7. import { SerializationHelper } from "../Misc/decorators";
  8. import { _TypeStore } from '../Misc/typeStore';
  9. import { IAnimationKey, AnimationKeyInterpolation } from './animationKey';
  10. import { AnimationRange } from './animationRange';
  11. import { AnimationEvent } from './animationEvent';
  12. import { Node } from "../node";
  13. import { IAnimatable } from './animatable.interface';
  14. import { Size } from '../Maths/math.size';
  15. declare type Animatable = import("./animatable").Animatable;
  16. declare type RuntimeAnimation = import("./runtimeAnimation").RuntimeAnimation;
  17. /**
  18. * @hidden
  19. */
  20. export class _IAnimationState {
  21. key: number;
  22. repeatCount: number;
  23. workValue?: any;
  24. loopMode?: number;
  25. offsetValue?: any;
  26. highLimitValue?: any;
  27. }
  28. /**
  29. * Class used to store any kind of animation
  30. */
  31. export class Animation {
  32. /**
  33. * Use matrix interpolation instead of using direct key value when animating matrices
  34. */
  35. public static AllowMatricesInterpolation = false;
  36. /**
  37. * When matrix interpolation is enabled, this boolean forces the system to use Matrix.DecomposeLerp instead of Matrix.Lerp. Interpolation is more precise but slower
  38. */
  39. public static AllowMatrixDecomposeForInterpolation = true;
  40. /**
  41. * Stores the key frames of the animation
  42. */
  43. private _keys: Array<IAnimationKey>;
  44. /**
  45. * Stores the easing function of the animation
  46. */
  47. private _easingFunction: IEasingFunction;
  48. /**
  49. * @hidden Internal use only
  50. */
  51. public _runtimeAnimations = new Array<RuntimeAnimation>();
  52. /**
  53. * The set of event that will be linked to this animation
  54. */
  55. private _events = new Array<AnimationEvent>();
  56. /**
  57. * Stores an array of target property paths
  58. */
  59. public targetPropertyPath: string[];
  60. /**
  61. * Stores the blending speed of the animation
  62. */
  63. public blendingSpeed = 0.01;
  64. /**
  65. * Stores the animation ranges for the animation
  66. */
  67. private _ranges: { [name: string]: Nullable<AnimationRange> } = {};
  68. /**
  69. * @hidden Internal use
  70. */
  71. public static _PrepareAnimation(name: string, targetProperty: string, framePerSecond: number, totalFrame: number,
  72. from: any, to: any, loopMode?: number, easingFunction?: EasingFunction): Nullable<Animation> {
  73. var dataType = undefined;
  74. if (!isNaN(parseFloat(from)) && isFinite(from)) {
  75. dataType = Animation.ANIMATIONTYPE_FLOAT;
  76. } else if (from instanceof Quaternion) {
  77. dataType = Animation.ANIMATIONTYPE_QUATERNION;
  78. } else if (from instanceof Vector3) {
  79. dataType = Animation.ANIMATIONTYPE_VECTOR3;
  80. } else if (from instanceof Vector2) {
  81. dataType = Animation.ANIMATIONTYPE_VECTOR2;
  82. } else if (from instanceof Color3) {
  83. dataType = Animation.ANIMATIONTYPE_COLOR3;
  84. } else if (from instanceof Size) {
  85. dataType = Animation.ANIMATIONTYPE_SIZE;
  86. }
  87. if (dataType == undefined) {
  88. return null;
  89. }
  90. var animation = new Animation(name, targetProperty, framePerSecond, dataType, loopMode);
  91. var keys: Array<IAnimationKey> = [{ frame: 0, value: from }, { frame: totalFrame, value: to }];
  92. animation.setKeys(keys);
  93. if (easingFunction !== undefined) {
  94. animation.setEasingFunction(easingFunction);
  95. }
  96. return animation;
  97. }
  98. /**
  99. * Sets up an animation
  100. * @param property The property to animate
  101. * @param animationType The animation type to apply
  102. * @param framePerSecond The frames per second of the animation
  103. * @param easingFunction The easing function used in the animation
  104. * @returns The created animation
  105. */
  106. public static CreateAnimation(property: string, animationType: number, framePerSecond: number, easingFunction: EasingFunction): Animation {
  107. var animation: Animation = new Animation(property + "Animation",
  108. property,
  109. framePerSecond,
  110. animationType,
  111. Animation.ANIMATIONLOOPMODE_CONSTANT);
  112. animation.setEasingFunction(easingFunction);
  113. return animation;
  114. }
  115. /**
  116. * Create and start an animation on a node
  117. * @param name defines the name of the global animation that will be run on all nodes
  118. * @param node defines the root node where the animation will take place
  119. * @param targetProperty defines property to animate
  120. * @param framePerSecond defines the number of frame per second yo use
  121. * @param totalFrame defines the number of frames in total
  122. * @param from defines the initial value
  123. * @param to defines the final value
  124. * @param loopMode defines which loop mode you want to use (off by default)
  125. * @param easingFunction defines the easing function to use (linear by default)
  126. * @param onAnimationEnd defines the callback to call when animation end
  127. * @returns the animatable created for this animation
  128. */
  129. public static CreateAndStartAnimation(name: string, node: Node, targetProperty: string,
  130. framePerSecond: number, totalFrame: number,
  131. from: any, to: any, loopMode?: number, easingFunction?: EasingFunction, onAnimationEnd?: () => void): Nullable<Animatable> {
  132. var animation = Animation._PrepareAnimation(name, targetProperty, framePerSecond, totalFrame, from, to, loopMode, easingFunction);
  133. if (!animation) {
  134. return null;
  135. }
  136. return node.getScene().beginDirectAnimation(node, [animation], 0, totalFrame, (animation.loopMode === 1), 1.0, onAnimationEnd);
  137. }
  138. /**
  139. * Create and start an animation on a node and its descendants
  140. * @param name defines the name of the global animation that will be run on all nodes
  141. * @param node defines the root node where the animation will take place
  142. * @param directDescendantsOnly if true only direct descendants will be used, if false direct and also indirect (children of children, an so on in a recursive manner) descendants will be used
  143. * @param targetProperty defines property to animate
  144. * @param framePerSecond defines the number of frame per second to use
  145. * @param totalFrame defines the number of frames in total
  146. * @param from defines the initial value
  147. * @param to defines the final value
  148. * @param loopMode defines which loop mode you want to use (off by default)
  149. * @param easingFunction defines the easing function to use (linear by default)
  150. * @param onAnimationEnd defines the callback to call when an animation ends (will be called once per node)
  151. * @returns the list of animatables created for all nodes
  152. * @example https://www.babylonjs-playground.com/#MH0VLI
  153. */
  154. public static CreateAndStartHierarchyAnimation(name: string, node: Node, directDescendantsOnly: boolean, targetProperty: string,
  155. framePerSecond: number, totalFrame: number,
  156. from: any, to: any, loopMode?: number, easingFunction?: EasingFunction, onAnimationEnd?: () => void): Nullable<Animatable[]> {
  157. var animation = Animation._PrepareAnimation(name, targetProperty, framePerSecond, totalFrame, from, to, loopMode, easingFunction);
  158. if (!animation) {
  159. return null;
  160. }
  161. let scene = node.getScene();
  162. return scene.beginDirectHierarchyAnimation(node, directDescendantsOnly, [animation], 0, totalFrame, (animation.loopMode === 1), 1.0, onAnimationEnd);
  163. }
  164. /**
  165. * Creates a new animation, merges it with the existing animations and starts it
  166. * @param name Name of the animation
  167. * @param node Node which contains the scene that begins the animations
  168. * @param targetProperty Specifies which property to animate
  169. * @param framePerSecond The frames per second of the animation
  170. * @param totalFrame The total number of frames
  171. * @param from The frame at the beginning of the animation
  172. * @param to The frame at the end of the animation
  173. * @param loopMode Specifies the loop mode of the animation
  174. * @param easingFunction (Optional) The easing function of the animation, which allow custom mathematical formulas for animations
  175. * @param onAnimationEnd Callback to run once the animation is complete
  176. * @returns Nullable animation
  177. */
  178. public static CreateMergeAndStartAnimation(name: string, node: Node, targetProperty: string,
  179. framePerSecond: number, totalFrame: number,
  180. from: any, to: any, loopMode?: number, easingFunction?: EasingFunction, onAnimationEnd?: () => void): Nullable<Animatable> {
  181. var animation = Animation._PrepareAnimation(name, targetProperty, framePerSecond, totalFrame, from, to, loopMode, easingFunction);
  182. if (!animation) {
  183. return null;
  184. }
  185. node.animations.push(animation);
  186. return node.getScene().beginAnimation(node, 0, totalFrame, (animation.loopMode === 1), 1.0, onAnimationEnd);
  187. }
  188. /**
  189. * Transition property of an host to the target Value
  190. * @param property The property to transition
  191. * @param targetValue The target Value of the property
  192. * @param host The object where the property to animate belongs
  193. * @param scene Scene used to run the animation
  194. * @param frameRate Framerate (in frame/s) to use
  195. * @param transition The transition type we want to use
  196. * @param duration The duration of the animation, in milliseconds
  197. * @param onAnimationEnd Callback trigger at the end of the animation
  198. * @returns Nullable animation
  199. */
  200. public static TransitionTo(property: string, targetValue: any, host: any, scene: Scene, frameRate: number, transition: Animation, duration: number, onAnimationEnd: Nullable<() => void> = null): Nullable<Animatable> {
  201. if (duration <= 0) {
  202. host[property] = targetValue;
  203. if (onAnimationEnd) {
  204. onAnimationEnd();
  205. }
  206. return null;
  207. }
  208. var endFrame: number = frameRate * (duration / 1000);
  209. transition.setKeys([{
  210. frame: 0,
  211. value: host[property].clone ? host[property].clone() : host[property]
  212. },
  213. {
  214. frame: endFrame,
  215. value: targetValue
  216. }]);
  217. if (!host.animations) {
  218. host.animations = [];
  219. }
  220. host.animations.push(transition);
  221. var animation: Animatable = scene.beginAnimation(host, 0, endFrame, false);
  222. animation.onAnimationEnd = onAnimationEnd;
  223. return animation;
  224. }
  225. /**
  226. * Return the array of runtime animations currently using this animation
  227. */
  228. public get runtimeAnimations(): RuntimeAnimation[] {
  229. return this._runtimeAnimations;
  230. }
  231. /**
  232. * Specifies if any of the runtime animations are currently running
  233. */
  234. public get hasRunningRuntimeAnimations(): boolean {
  235. for (var runtimeAnimation of this._runtimeAnimations) {
  236. if (!runtimeAnimation.isStopped) {
  237. return true;
  238. }
  239. }
  240. return false;
  241. }
  242. /**
  243. * Initializes the animation
  244. * @param name Name of the animation
  245. * @param targetProperty Property to animate
  246. * @param framePerSecond The frames per second of the animation
  247. * @param dataType The data type of the animation
  248. * @param loopMode The loop mode of the animation
  249. * @param enableBlending Specifies if blending should be enabled
  250. */
  251. constructor(
  252. /**Name of the animation */
  253. public name: string,
  254. /**Property to animate */
  255. public targetProperty: string,
  256. /**The frames per second of the animation */
  257. public framePerSecond: number,
  258. /**The data type of the animation */
  259. public dataType: number,
  260. /**The loop mode of the animation */
  261. public loopMode?: number,
  262. /**Specifies if blending should be enabled */
  263. public enableBlending?: boolean) {
  264. this.targetPropertyPath = targetProperty.split(".");
  265. this.dataType = dataType;
  266. this.loopMode = loopMode === undefined ? Animation.ANIMATIONLOOPMODE_CYCLE : loopMode;
  267. }
  268. // Methods
  269. /**
  270. * Converts the animation to a string
  271. * @param fullDetails support for multiple levels of logging within scene loading
  272. * @returns String form of the animation
  273. */
  274. public toString(fullDetails?: boolean): string {
  275. var ret = "Name: " + this.name + ", property: " + this.targetProperty;
  276. ret += ", datatype: " + (["Float", "Vector3", "Quaternion", "Matrix", "Color3", "Vector2"])[this.dataType];
  277. ret += ", nKeys: " + (this._keys ? this._keys.length : "none");
  278. ret += ", nRanges: " + (this._ranges ? Object.keys(this._ranges).length : "none");
  279. if (fullDetails) {
  280. ret += ", Ranges: {";
  281. var first = true;
  282. for (var name in this._ranges) {
  283. if (first) {
  284. ret += ", ";
  285. first = false;
  286. }
  287. ret += name;
  288. }
  289. ret += "}";
  290. }
  291. return ret;
  292. }
  293. /**
  294. * Add an event to this animation
  295. * @param event Event to add
  296. */
  297. public addEvent(event: AnimationEvent): void {
  298. this._events.push(event);
  299. }
  300. /**
  301. * Remove all events found at the given frame
  302. * @param frame The frame to remove events from
  303. */
  304. public removeEvents(frame: number): void {
  305. for (var index = 0; index < this._events.length; index++) {
  306. if (this._events[index].frame === frame) {
  307. this._events.splice(index, 1);
  308. index--;
  309. }
  310. }
  311. }
  312. /**
  313. * Retrieves all the events from the animation
  314. * @returns Events from the animation
  315. */
  316. public getEvents(): AnimationEvent[] {
  317. return this._events;
  318. }
  319. /**
  320. * Creates an animation range
  321. * @param name Name of the animation range
  322. * @param from Starting frame of the animation range
  323. * @param to Ending frame of the animation
  324. */
  325. public createRange(name: string, from: number, to: number): void {
  326. // check name not already in use; could happen for bones after serialized
  327. if (!this._ranges[name]) {
  328. this._ranges[name] = new AnimationRange(name, from, to);
  329. }
  330. }
  331. /**
  332. * Deletes an animation range by name
  333. * @param name Name of the animation range to delete
  334. * @param deleteFrames Specifies if the key frames for the range should also be deleted (true) or not (false)
  335. */
  336. public deleteRange(name: string, deleteFrames = true): void {
  337. let range = this._ranges[name];
  338. if (!range) {
  339. return;
  340. }
  341. if (deleteFrames) {
  342. var from = range.from;
  343. var to = range.to;
  344. // this loop MUST go high to low for multiple splices to work
  345. for (var key = this._keys.length - 1; key >= 0; key--) {
  346. if (this._keys[key].frame >= from && this._keys[key].frame <= to) {
  347. this._keys.splice(key, 1);
  348. }
  349. }
  350. }
  351. this._ranges[name] = null; // said much faster than 'delete this._range[name]'
  352. }
  353. /**
  354. * Gets the animation range by name, or null if not defined
  355. * @param name Name of the animation range
  356. * @returns Nullable animation range
  357. */
  358. public getRange(name: string): Nullable<AnimationRange> {
  359. return this._ranges[name];
  360. }
  361. /**
  362. * Gets the key frames from the animation
  363. * @returns The key frames of the animation
  364. */
  365. public getKeys(): Array<IAnimationKey> {
  366. return this._keys;
  367. }
  368. /**
  369. * Gets the highest frame rate of the animation
  370. * @returns Highest frame rate of the animation
  371. */
  372. public getHighestFrame(): number {
  373. var ret = 0;
  374. for (var key = 0, nKeys = this._keys.length; key < nKeys; key++) {
  375. if (ret < this._keys[key].frame) {
  376. ret = this._keys[key].frame;
  377. }
  378. }
  379. return ret;
  380. }
  381. /**
  382. * Gets the easing function of the animation
  383. * @returns Easing function of the animation
  384. */
  385. public getEasingFunction(): IEasingFunction {
  386. return this._easingFunction;
  387. }
  388. /**
  389. * Sets the easing function of the animation
  390. * @param easingFunction A custom mathematical formula for animation
  391. */
  392. public setEasingFunction(easingFunction: EasingFunction): void {
  393. this._easingFunction = easingFunction;
  394. }
  395. /**
  396. * Interpolates a scalar linearly
  397. * @param startValue Start value of the animation curve
  398. * @param endValue End value of the animation curve
  399. * @param gradient Scalar amount to interpolate
  400. * @returns Interpolated scalar value
  401. */
  402. public floatInterpolateFunction(startValue: number, endValue: number, gradient: number): number {
  403. return Scalar.Lerp(startValue, endValue, gradient);
  404. }
  405. /**
  406. * Interpolates a scalar cubically
  407. * @param startValue Start value of the animation curve
  408. * @param outTangent End tangent of the animation
  409. * @param endValue End value of the animation curve
  410. * @param inTangent Start tangent of the animation curve
  411. * @param gradient Scalar amount to interpolate
  412. * @returns Interpolated scalar value
  413. */
  414. public floatInterpolateFunctionWithTangents(startValue: number, outTangent: number, endValue: number, inTangent: number, gradient: number): number {
  415. return Scalar.Hermite(startValue, outTangent, endValue, inTangent, gradient);
  416. }
  417. /**
  418. * Interpolates a quaternion using a spherical linear interpolation
  419. * @param startValue Start value of the animation curve
  420. * @param endValue End value of the animation curve
  421. * @param gradient Scalar amount to interpolate
  422. * @returns Interpolated quaternion value
  423. */
  424. public quaternionInterpolateFunction(startValue: Quaternion, endValue: Quaternion, gradient: number): Quaternion {
  425. return Quaternion.Slerp(startValue, endValue, gradient);
  426. }
  427. /**
  428. * Interpolates a quaternion cubically
  429. * @param startValue Start value of the animation curve
  430. * @param outTangent End tangent of the animation curve
  431. * @param endValue End value of the animation curve
  432. * @param inTangent Start tangent of the animation curve
  433. * @param gradient Scalar amount to interpolate
  434. * @returns Interpolated quaternion value
  435. */
  436. public quaternionInterpolateFunctionWithTangents(startValue: Quaternion, outTangent: Quaternion, endValue: Quaternion, inTangent: Quaternion, gradient: number): Quaternion {
  437. return Quaternion.Hermite(startValue, outTangent, endValue, inTangent, gradient).normalize();
  438. }
  439. /**
  440. * Interpolates a Vector3 linearl
  441. * @param startValue Start value of the animation curve
  442. * @param endValue End value of the animation curve
  443. * @param gradient Scalar amount to interpolate
  444. * @returns Interpolated scalar value
  445. */
  446. public vector3InterpolateFunction(startValue: Vector3, endValue: Vector3, gradient: number): Vector3 {
  447. return Vector3.Lerp(startValue, endValue, gradient);
  448. }
  449. /**
  450. * Interpolates a Vector3 cubically
  451. * @param startValue Start value of the animation curve
  452. * @param outTangent End tangent of the animation
  453. * @param endValue End value of the animation curve
  454. * @param inTangent Start tangent of the animation curve
  455. * @param gradient Scalar amount to interpolate
  456. * @returns InterpolatedVector3 value
  457. */
  458. public vector3InterpolateFunctionWithTangents(startValue: Vector3, outTangent: Vector3, endValue: Vector3, inTangent: Vector3, gradient: number): Vector3 {
  459. return Vector3.Hermite(startValue, outTangent, endValue, inTangent, gradient);
  460. }
  461. /**
  462. * Interpolates a Vector2 linearly
  463. * @param startValue Start value of the animation curve
  464. * @param endValue End value of the animation curve
  465. * @param gradient Scalar amount to interpolate
  466. * @returns Interpolated Vector2 value
  467. */
  468. public vector2InterpolateFunction(startValue: Vector2, endValue: Vector2, gradient: number): Vector2 {
  469. return Vector2.Lerp(startValue, endValue, gradient);
  470. }
  471. /**
  472. * Interpolates a Vector2 cubically
  473. * @param startValue Start value of the animation curve
  474. * @param outTangent End tangent of the animation
  475. * @param endValue End value of the animation curve
  476. * @param inTangent Start tangent of the animation curve
  477. * @param gradient Scalar amount to interpolate
  478. * @returns Interpolated Vector2 value
  479. */
  480. public vector2InterpolateFunctionWithTangents(startValue: Vector2, outTangent: Vector2, endValue: Vector2, inTangent: Vector2, gradient: number): Vector2 {
  481. return Vector2.Hermite(startValue, outTangent, endValue, inTangent, gradient);
  482. }
  483. /**
  484. * Interpolates a size linearly
  485. * @param startValue Start value of the animation curve
  486. * @param endValue End value of the animation curve
  487. * @param gradient Scalar amount to interpolate
  488. * @returns Interpolated Size value
  489. */
  490. public sizeInterpolateFunction(startValue: Size, endValue: Size, gradient: number): Size {
  491. return Size.Lerp(startValue, endValue, gradient);
  492. }
  493. /**
  494. * Interpolates a Color3 linearly
  495. * @param startValue Start value of the animation curve
  496. * @param endValue End value of the animation curve
  497. * @param gradient Scalar amount to interpolate
  498. * @returns Interpolated Color3 value
  499. */
  500. public color3InterpolateFunction(startValue: Color3, endValue: Color3, gradient: number): Color3 {
  501. return Color3.Lerp(startValue, endValue, gradient);
  502. }
  503. /**
  504. * @hidden Internal use only
  505. */
  506. public _getKeyValue(value: any): any {
  507. if (typeof value === "function") {
  508. return value();
  509. }
  510. return value;
  511. }
  512. /**
  513. * @hidden Internal use only
  514. */
  515. public _interpolate(currentFrame: number, state: _IAnimationState): any {
  516. if (state.loopMode === Animation.ANIMATIONLOOPMODE_CONSTANT && state.repeatCount > 0) {
  517. return state.highLimitValue.clone ? state.highLimitValue.clone() : state.highLimitValue;
  518. }
  519. const keys = this._keys;
  520. if (keys.length === 1) {
  521. return this._getKeyValue(keys[0].value);
  522. }
  523. var startKeyIndex = state.key;
  524. if (keys[startKeyIndex].frame >= currentFrame) {
  525. while (startKeyIndex - 1 >= 0 && keys[startKeyIndex].frame >= currentFrame) {
  526. startKeyIndex--;
  527. }
  528. }
  529. for (var key = startKeyIndex; key < keys.length; key++) {
  530. var endKey = keys[key + 1];
  531. if (endKey.frame >= currentFrame) {
  532. state.key = key;
  533. var startKey = keys[key];
  534. var startValue = this._getKeyValue(startKey.value);
  535. if (startKey.interpolation === AnimationKeyInterpolation.STEP) {
  536. return startValue;
  537. }
  538. var endValue = this._getKeyValue(endKey.value);
  539. var useTangent = startKey.outTangent !== undefined && endKey.inTangent !== undefined;
  540. var frameDelta = endKey.frame - startKey.frame;
  541. // gradient : percent of currentFrame between the frame inf and the frame sup
  542. var gradient = (currentFrame - startKey.frame) / frameDelta;
  543. // check for easingFunction and correction of gradient
  544. let easingFunction = this.getEasingFunction();
  545. if (easingFunction != null) {
  546. gradient = easingFunction.ease(gradient);
  547. }
  548. switch (this.dataType) {
  549. // Float
  550. case Animation.ANIMATIONTYPE_FLOAT:
  551. var floatValue = useTangent ? this.floatInterpolateFunctionWithTangents(startValue, startKey.outTangent * frameDelta, endValue, endKey.inTangent * frameDelta, gradient) : this.floatInterpolateFunction(startValue, endValue, gradient);
  552. switch (state.loopMode) {
  553. case Animation.ANIMATIONLOOPMODE_CYCLE:
  554. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  555. return floatValue;
  556. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  557. return state.offsetValue * state.repeatCount + floatValue;
  558. }
  559. break;
  560. // Quaternion
  561. case Animation.ANIMATIONTYPE_QUATERNION:
  562. var quatValue = useTangent ? this.quaternionInterpolateFunctionWithTangents(startValue, startKey.outTangent.scale(frameDelta), endValue, endKey.inTangent.scale(frameDelta), gradient) : this.quaternionInterpolateFunction(startValue, endValue, gradient);
  563. switch (state.loopMode) {
  564. case Animation.ANIMATIONLOOPMODE_CYCLE:
  565. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  566. return quatValue;
  567. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  568. return quatValue.addInPlace(state.offsetValue.scale(state.repeatCount));
  569. }
  570. return quatValue;
  571. // Vector3
  572. case Animation.ANIMATIONTYPE_VECTOR3:
  573. var vec3Value = useTangent ? this.vector3InterpolateFunctionWithTangents(startValue, startKey.outTangent.scale(frameDelta), endValue, endKey.inTangent.scale(frameDelta), gradient) : this.vector3InterpolateFunction(startValue, endValue, gradient);
  574. switch (state.loopMode) {
  575. case Animation.ANIMATIONLOOPMODE_CYCLE:
  576. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  577. return vec3Value;
  578. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  579. return vec3Value.add(state.offsetValue.scale(state.repeatCount));
  580. }
  581. // Vector2
  582. case Animation.ANIMATIONTYPE_VECTOR2:
  583. var vec2Value = useTangent ? this.vector2InterpolateFunctionWithTangents(startValue, startKey.outTangent.scale(frameDelta), endValue, endKey.inTangent.scale(frameDelta), gradient) : this.vector2InterpolateFunction(startValue, endValue, gradient);
  584. switch (state.loopMode) {
  585. case Animation.ANIMATIONLOOPMODE_CYCLE:
  586. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  587. return vec2Value;
  588. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  589. return vec2Value.add(state.offsetValue.scale(state.repeatCount));
  590. }
  591. // Size
  592. case Animation.ANIMATIONTYPE_SIZE:
  593. switch (state.loopMode) {
  594. case Animation.ANIMATIONLOOPMODE_CYCLE:
  595. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  596. return this.sizeInterpolateFunction(startValue, endValue, gradient);
  597. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  598. return this.sizeInterpolateFunction(startValue, endValue, gradient).add(state.offsetValue.scale(state.repeatCount));
  599. }
  600. // Color3
  601. case Animation.ANIMATIONTYPE_COLOR3:
  602. switch (state.loopMode) {
  603. case Animation.ANIMATIONLOOPMODE_CYCLE:
  604. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  605. return this.color3InterpolateFunction(startValue, endValue, gradient);
  606. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  607. return this.color3InterpolateFunction(startValue, endValue, gradient).add(state.offsetValue.scale(state.repeatCount));
  608. }
  609. // Matrix
  610. case Animation.ANIMATIONTYPE_MATRIX:
  611. switch (state.loopMode) {
  612. case Animation.ANIMATIONLOOPMODE_CYCLE:
  613. case Animation.ANIMATIONLOOPMODE_CONSTANT:
  614. if (Animation.AllowMatricesInterpolation) {
  615. return this.matrixInterpolateFunction(startValue, endValue, gradient, state.workValue);
  616. }
  617. case Animation.ANIMATIONLOOPMODE_RELATIVE:
  618. return startValue;
  619. }
  620. default:
  621. break;
  622. }
  623. break;
  624. }
  625. }
  626. return this._getKeyValue(keys[keys.length - 1].value);
  627. }
  628. /**
  629. * Defines the function to use to interpolate matrices
  630. * @param startValue defines the start matrix
  631. * @param endValue defines the end matrix
  632. * @param gradient defines the gradient between both matrices
  633. * @param result defines an optional target matrix where to store the interpolation
  634. * @returns the interpolated matrix
  635. */
  636. public matrixInterpolateFunction(startValue: Matrix, endValue: Matrix, gradient: number, result?: Matrix): Matrix {
  637. if (Animation.AllowMatrixDecomposeForInterpolation) {
  638. if (result) {
  639. Matrix.DecomposeLerpToRef(startValue, endValue, gradient, result);
  640. return result;
  641. }
  642. return Matrix.DecomposeLerp(startValue, endValue, gradient);
  643. }
  644. if (result) {
  645. Matrix.LerpToRef(startValue, endValue, gradient, result);
  646. return result;
  647. }
  648. return Matrix.Lerp(startValue, endValue, gradient);
  649. }
  650. /**
  651. * Makes a copy of the animation
  652. * @returns Cloned animation
  653. */
  654. public clone(): Animation {
  655. var clone = new Animation(this.name, this.targetPropertyPath.join("."), this.framePerSecond, this.dataType, this.loopMode);
  656. clone.enableBlending = this.enableBlending;
  657. clone.blendingSpeed = this.blendingSpeed;
  658. if (this._keys) {
  659. clone.setKeys(this._keys);
  660. }
  661. if (this._ranges) {
  662. clone._ranges = {};
  663. for (var name in this._ranges) {
  664. let range = this._ranges[name];
  665. if (!range) {
  666. continue;
  667. }
  668. clone._ranges[name] = range.clone();
  669. }
  670. }
  671. return clone;
  672. }
  673. /**
  674. * Sets the key frames of the animation
  675. * @param values The animation key frames to set
  676. */
  677. public setKeys(values: Array<IAnimationKey>): void {
  678. this._keys = values.slice(0);
  679. }
  680. /**
  681. * Serializes the animation to an object
  682. * @returns Serialized object
  683. */
  684. public serialize(): any {
  685. var serializationObject: any = {};
  686. serializationObject.name = this.name;
  687. serializationObject.property = this.targetProperty;
  688. serializationObject.framePerSecond = this.framePerSecond;
  689. serializationObject.dataType = this.dataType;
  690. serializationObject.loopBehavior = this.loopMode;
  691. serializationObject.enableBlending = this.enableBlending;
  692. serializationObject.blendingSpeed = this.blendingSpeed;
  693. var dataType = this.dataType;
  694. serializationObject.keys = [];
  695. var keys = this.getKeys();
  696. for (var index = 0; index < keys.length; index++) {
  697. var animationKey = keys[index];
  698. var key: any = {};
  699. key.frame = animationKey.frame;
  700. switch (dataType) {
  701. case Animation.ANIMATIONTYPE_FLOAT:
  702. key.values = [animationKey.value];
  703. break;
  704. case Animation.ANIMATIONTYPE_QUATERNION:
  705. case Animation.ANIMATIONTYPE_MATRIX:
  706. case Animation.ANIMATIONTYPE_VECTOR3:
  707. case Animation.ANIMATIONTYPE_COLOR3:
  708. key.values = animationKey.value.asArray();
  709. break;
  710. }
  711. serializationObject.keys.push(key);
  712. }
  713. serializationObject.ranges = [];
  714. for (var name in this._ranges) {
  715. let source = this._ranges[name];
  716. if (!source) {
  717. continue;
  718. }
  719. var range: any = {};
  720. range.name = name;
  721. range.from = source.from;
  722. range.to = source.to;
  723. serializationObject.ranges.push(range);
  724. }
  725. return serializationObject;
  726. }
  727. // Statics
  728. /**
  729. * Float animation type
  730. */
  731. private static _ANIMATIONTYPE_FLOAT = 0;
  732. /**
  733. * Vector3 animation type
  734. */
  735. private static _ANIMATIONTYPE_VECTOR3 = 1;
  736. /**
  737. * Quaternion animation type
  738. */
  739. private static _ANIMATIONTYPE_QUATERNION = 2;
  740. /**
  741. * Matrix animation type
  742. */
  743. private static _ANIMATIONTYPE_MATRIX = 3;
  744. /**
  745. * Color3 animation type
  746. */
  747. private static _ANIMATIONTYPE_COLOR3 = 4;
  748. /**
  749. * Vector2 animation type
  750. */
  751. private static _ANIMATIONTYPE_VECTOR2 = 5;
  752. /**
  753. * Size animation type
  754. */
  755. private static _ANIMATIONTYPE_SIZE = 6;
  756. /**
  757. * Relative Loop Mode
  758. */
  759. private static _ANIMATIONLOOPMODE_RELATIVE = 0;
  760. /**
  761. * Cycle Loop Mode
  762. */
  763. private static _ANIMATIONLOOPMODE_CYCLE = 1;
  764. /**
  765. * Constant Loop Mode
  766. */
  767. private static _ANIMATIONLOOPMODE_CONSTANT = 2;
  768. /**
  769. * Get the float animation type
  770. */
  771. public static get ANIMATIONTYPE_FLOAT(): number {
  772. return Animation._ANIMATIONTYPE_FLOAT;
  773. }
  774. /**
  775. * Get the Vector3 animation type
  776. */
  777. public static get ANIMATIONTYPE_VECTOR3(): number {
  778. return Animation._ANIMATIONTYPE_VECTOR3;
  779. }
  780. /**
  781. * Get the Vector2 animation type
  782. */
  783. public static get ANIMATIONTYPE_VECTOR2(): number {
  784. return Animation._ANIMATIONTYPE_VECTOR2;
  785. }
  786. /**
  787. * Get the Size animation type
  788. */
  789. public static get ANIMATIONTYPE_SIZE(): number {
  790. return Animation._ANIMATIONTYPE_SIZE;
  791. }
  792. /**
  793. * Get the Quaternion animation type
  794. */
  795. public static get ANIMATIONTYPE_QUATERNION(): number {
  796. return Animation._ANIMATIONTYPE_QUATERNION;
  797. }
  798. /**
  799. * Get the Matrix animation type
  800. */
  801. public static get ANIMATIONTYPE_MATRIX(): number {
  802. return Animation._ANIMATIONTYPE_MATRIX;
  803. }
  804. /**
  805. * Get the Color3 animation type
  806. */
  807. public static get ANIMATIONTYPE_COLOR3(): number {
  808. return Animation._ANIMATIONTYPE_COLOR3;
  809. }
  810. /**
  811. * Get the Relative Loop Mode
  812. */
  813. public static get ANIMATIONLOOPMODE_RELATIVE(): number {
  814. return Animation._ANIMATIONLOOPMODE_RELATIVE;
  815. }
  816. /**
  817. * Get the Cycle Loop Mode
  818. */
  819. public static get ANIMATIONLOOPMODE_CYCLE(): number {
  820. return Animation._ANIMATIONLOOPMODE_CYCLE;
  821. }
  822. /**
  823. * Get the Constant Loop Mode
  824. */
  825. public static get ANIMATIONLOOPMODE_CONSTANT(): number {
  826. return Animation._ANIMATIONLOOPMODE_CONSTANT;
  827. }
  828. /** @hidden */
  829. public static _UniversalLerp(left: any, right: any, amount: number): any {
  830. let constructor = left.constructor;
  831. if (constructor.Lerp) { // Lerp supported
  832. return constructor.Lerp(left, right, amount);
  833. } else if (constructor.Slerp) { // Slerp supported
  834. return constructor.Slerp(left, right, amount);
  835. } else if (left.toFixed) { // Number
  836. return left * (1.0 - amount) + amount * right;
  837. } else { // Blending not supported
  838. return right;
  839. }
  840. }
  841. /**
  842. * Parses an animation object and creates an animation
  843. * @param parsedAnimation Parsed animation object
  844. * @returns Animation object
  845. */
  846. public static Parse(parsedAnimation: any): Animation {
  847. var animation = new Animation(parsedAnimation.name, parsedAnimation.property, parsedAnimation.framePerSecond, parsedAnimation.dataType, parsedAnimation.loopBehavior);
  848. var dataType = parsedAnimation.dataType;
  849. var keys: Array<IAnimationKey> = [];
  850. var data;
  851. var index: number;
  852. if (parsedAnimation.enableBlending) {
  853. animation.enableBlending = parsedAnimation.enableBlending;
  854. }
  855. if (parsedAnimation.blendingSpeed) {
  856. animation.blendingSpeed = parsedAnimation.blendingSpeed;
  857. }
  858. for (index = 0; index < parsedAnimation.keys.length; index++) {
  859. var key = parsedAnimation.keys[index];
  860. var inTangent: any;
  861. var outTangent: any;
  862. switch (dataType) {
  863. case Animation.ANIMATIONTYPE_FLOAT:
  864. data = key.values[0];
  865. if (key.values.length >= 1) {
  866. inTangent = key.values[1];
  867. }
  868. if (key.values.length >= 2) {
  869. outTangent = key.values[2];
  870. }
  871. break;
  872. case Animation.ANIMATIONTYPE_QUATERNION:
  873. data = Quaternion.FromArray(key.values);
  874. if (key.values.length >= 8) {
  875. var _inTangent = Quaternion.FromArray(key.values.slice(4, 8));
  876. if (!_inTangent.equals(Quaternion.Zero())) {
  877. inTangent = _inTangent;
  878. }
  879. }
  880. if (key.values.length >= 12) {
  881. var _outTangent = Quaternion.FromArray(key.values.slice(8, 12));
  882. if (!_outTangent.equals(Quaternion.Zero())) {
  883. outTangent = _outTangent;
  884. }
  885. }
  886. break;
  887. case Animation.ANIMATIONTYPE_MATRIX:
  888. data = Matrix.FromArray(key.values);
  889. break;
  890. case Animation.ANIMATIONTYPE_COLOR3:
  891. data = Color3.FromArray(key.values);
  892. break;
  893. case Animation.ANIMATIONTYPE_VECTOR3:
  894. default:
  895. data = Vector3.FromArray(key.values);
  896. break;
  897. }
  898. var keyData: any = {};
  899. keyData.frame = key.frame;
  900. keyData.value = data;
  901. if (inTangent != undefined) {
  902. keyData.inTangent = inTangent;
  903. }
  904. if (outTangent != undefined) {
  905. keyData.outTangent = outTangent;
  906. }
  907. keys.push(keyData);
  908. }
  909. animation.setKeys(keys);
  910. if (parsedAnimation.ranges) {
  911. for (index = 0; index < parsedAnimation.ranges.length; index++) {
  912. data = parsedAnimation.ranges[index];
  913. animation.createRange(data.name, data.from, data.to);
  914. }
  915. }
  916. return animation;
  917. }
  918. /**
  919. * Appends the serialized animations from the source animations
  920. * @param source Source containing the animations
  921. * @param destination Target to store the animations
  922. */
  923. public static AppendSerializedAnimations(source: IAnimatable, destination: any): void {
  924. SerializationHelper.AppendSerializedAnimations(source, destination);
  925. }
  926. }
  927. _TypeStore.RegisteredTypes["BABYLON.Animation"] = Animation;
  928. Node._AnimationRangeFactory = (name: string, from: number, to: number) => new AnimationRange(name, from, to);