morphTarget.ts 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. import { IAnimatable } from "../Misc/tools";
  2. import { Observable } from "../Misc/observable";
  3. import { Nullable, FloatArray } from "../types";
  4. import { Scene } from "../scene";
  5. import { EngineStore } from "../Engines/engineStore";
  6. import { AbstractMesh } from "../Meshes/abstractMesh";
  7. import { VertexBuffer } from "../Meshes/buffer";
  8. import { Animation } from "../Animations/animation";
  9. import { AnimationPropertiesOverride } from "../Animations/animationPropertiesOverride";
  10. import { serialize, SerializationHelper } from "../Misc/decorators";
  11. /**
  12. * Defines a target to use with MorphTargetManager
  13. * @see http://doc.babylonjs.com/how_to/how_to_use_morphtargets
  14. */
  15. export class MorphTarget implements IAnimatable {
  16. /**
  17. * Gets or sets the list of animations
  18. */
  19. public animations = new Array<Animation>();
  20. private _scene: Nullable<Scene>;
  21. private _positions: Nullable<FloatArray> = null;
  22. private _normals: Nullable<FloatArray> = null;
  23. private _tangents: Nullable<FloatArray> = null;
  24. private _influence: number;
  25. /**
  26. * Observable raised when the influence changes
  27. */
  28. public onInfluenceChanged = new Observable<boolean>();
  29. /** @hidden */
  30. public _onDataLayoutChanged = new Observable<void>();
  31. /**
  32. * Gets or sets the influence of this target (ie. its weight in the overall morphing)
  33. */
  34. public get influence(): number {
  35. return this._influence;
  36. }
  37. public set influence(influence: number) {
  38. if (this._influence === influence) {
  39. return;
  40. }
  41. var previous = this._influence;
  42. this._influence = influence;
  43. if (this.onInfluenceChanged.hasObservers) {
  44. this.onInfluenceChanged.notifyObservers(previous === 0 || influence === 0);
  45. }
  46. }
  47. /**
  48. * Gets or sets the id of the morph Target
  49. */
  50. @serialize()
  51. public id: string;
  52. private _animationPropertiesOverride: Nullable<AnimationPropertiesOverride> = null;
  53. /**
  54. * Gets or sets the animation properties override
  55. */
  56. public get animationPropertiesOverride(): Nullable<AnimationPropertiesOverride> {
  57. if (!this._animationPropertiesOverride && this._scene) {
  58. return this._scene.animationPropertiesOverride;
  59. }
  60. return this._animationPropertiesOverride;
  61. }
  62. public set animationPropertiesOverride(value: Nullable<AnimationPropertiesOverride>) {
  63. this._animationPropertiesOverride = value;
  64. }
  65. /**
  66. * Creates a new MorphTarget
  67. * @param name defines the name of the target
  68. * @param influence defines the influence to use
  69. * @param scene defines the scene the morphtarget belongs to
  70. */
  71. public constructor(
  72. /** defines the name of the target */
  73. public name: string, influence = 0, scene: Nullable<Scene> = null) {
  74. this._scene = scene || EngineStore.LastCreatedScene;
  75. this.influence = influence;
  76. }
  77. /**
  78. * Gets a boolean defining if the target contains position data
  79. */
  80. public get hasPositions(): boolean {
  81. return !!this._positions;
  82. }
  83. /**
  84. * Gets a boolean defining if the target contains normal data
  85. */
  86. public get hasNormals(): boolean {
  87. return !!this._normals;
  88. }
  89. /**
  90. * Gets a boolean defining if the target contains tangent data
  91. */
  92. public get hasTangents(): boolean {
  93. return !!this._tangents;
  94. }
  95. /**
  96. * Affects position data to this target
  97. * @param data defines the position data to use
  98. */
  99. public setPositions(data: Nullable<FloatArray>) {
  100. const hadPositions = this.hasPositions;
  101. this._positions = data;
  102. if (hadPositions !== this.hasPositions) {
  103. this._onDataLayoutChanged.notifyObservers(undefined);
  104. }
  105. }
  106. /**
  107. * Gets the position data stored in this target
  108. * @returns a FloatArray containing the position data (or null if not present)
  109. */
  110. public getPositions(): Nullable<FloatArray> {
  111. return this._positions;
  112. }
  113. /**
  114. * Affects normal data to this target
  115. * @param data defines the normal data to use
  116. */
  117. public setNormals(data: Nullable<FloatArray>) {
  118. const hadNormals = this.hasNormals;
  119. this._normals = data;
  120. if (hadNormals !== this.hasNormals) {
  121. this._onDataLayoutChanged.notifyObservers(undefined);
  122. }
  123. }
  124. /**
  125. * Gets the normal data stored in this target
  126. * @returns a FloatArray containing the normal data (or null if not present)
  127. */
  128. public getNormals(): Nullable<FloatArray> {
  129. return this._normals;
  130. }
  131. /**
  132. * Affects tangent data to this target
  133. * @param data defines the tangent data to use
  134. */
  135. public setTangents(data: Nullable<FloatArray>) {
  136. const hadTangents = this.hasTangents;
  137. this._tangents = data;
  138. if (hadTangents !== this.hasTangents) {
  139. this._onDataLayoutChanged.notifyObservers(undefined);
  140. }
  141. }
  142. /**
  143. * Gets the tangent data stored in this target
  144. * @returns a FloatArray containing the tangent data (or null if not present)
  145. */
  146. public getTangents(): Nullable<FloatArray> {
  147. return this._tangents;
  148. }
  149. /**
  150. * Serializes the current target into a Serialization object
  151. * @returns the serialized object
  152. */
  153. public serialize(): any {
  154. var serializationObject: any = {};
  155. serializationObject.name = this.name;
  156. serializationObject.influence = this.influence;
  157. serializationObject.positions = Array.prototype.slice.call(this.getPositions());
  158. if (this.id != null) {
  159. serializationObject.id = this.id;
  160. }
  161. if (this.hasNormals) {
  162. serializationObject.normals = Array.prototype.slice.call(this.getNormals());
  163. }
  164. if (this.hasTangents) {
  165. serializationObject.tangents = Array.prototype.slice.call(this.getTangents());
  166. }
  167. // Animations
  168. SerializationHelper.AppendSerializedAnimations(this, serializationObject);
  169. return serializationObject;
  170. }
  171. /**
  172. * Returns the string "MorphTarget"
  173. * @returns "MorphTarget"
  174. */
  175. public getClassName(): string {
  176. return "MorphTarget";
  177. }
  178. // Statics
  179. /**
  180. * Creates a new target from serialized data
  181. * @param serializationObject defines the serialized data to use
  182. * @returns a new MorphTarget
  183. */
  184. public static Parse(serializationObject: any): MorphTarget {
  185. var result = new MorphTarget(serializationObject.name, serializationObject.influence);
  186. result.setPositions(serializationObject.positions);
  187. if (serializationObject.id != null) {
  188. result.id = serializationObject.id;
  189. }
  190. if (serializationObject.normals) {
  191. result.setNormals(serializationObject.normals);
  192. }
  193. if (serializationObject.tangents) {
  194. result.setTangents(serializationObject.tangents);
  195. }
  196. // Animations
  197. if (serializationObject.animations) {
  198. for (var animationIndex = 0; animationIndex < serializationObject.animations.length; animationIndex++) {
  199. var parsedAnimation = serializationObject.animations[animationIndex];
  200. result.animations.push(Animation.Parse(parsedAnimation));
  201. }
  202. }
  203. return result;
  204. }
  205. /**
  206. * Creates a MorphTarget from mesh data
  207. * @param mesh defines the source mesh
  208. * @param name defines the name to use for the new target
  209. * @param influence defines the influence to attach to the target
  210. * @returns a new MorphTarget
  211. */
  212. public static FromMesh(mesh: AbstractMesh, name?: string, influence?: number): MorphTarget {
  213. if (!name) {
  214. name = mesh.name;
  215. }
  216. var result = new MorphTarget(name, influence, mesh.getScene());
  217. result.setPositions(<FloatArray>mesh.getVerticesData(VertexBuffer.PositionKind));
  218. if (mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
  219. result.setNormals(<FloatArray>mesh.getVerticesData(VertexBuffer.NormalKind));
  220. }
  221. if (mesh.isVerticesDataPresent(VertexBuffer.TangentKind)) {
  222. result.setTangents(<FloatArray>mesh.getVerticesData(VertexBuffer.TangentKind));
  223. }
  224. return result;
  225. }
  226. }