skeletonViewer.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. module BABYLON.Debug {
  2. /**
  3. * Class used to render a debug view of a given skeleton
  4. * @see http://www.babylonjs-playground.com/#1BZJVJ#8
  5. */
  6. export class SkeletonViewer {
  7. /** Gets or sets the color used to render the skeleton */
  8. public color: Color3 = Color3.White();
  9. private _scene: Scene;
  10. private _debugLines = new Array<Array<Vector3>>();
  11. private _debugMesh: Nullable<LinesMesh>;
  12. private _isEnabled = false;
  13. private _renderFunction: () => void;
  14. public get debugMesh(): Nullable<LinesMesh> {
  15. return this._debugMesh;
  16. }
  17. /**
  18. * Creates a new SkeletonViewer
  19. * @param skeleton defines the skeleton to render
  20. * @param mesh defines the mesh attached to the skeleton
  21. * @param scene defines the hosting scene
  22. * @param autoUpdateBonesMatrices defines a boolean indicating if bones matrices must be forced to update before rendering (true by default)
  23. * @param renderingGroupId defines the rendering group id to use with the viewer
  24. * @param utilityLayerRenderer defines an optional utility layer to render the helper on
  25. */
  26. constructor(
  27. /** defines the skeleton to render */
  28. public skeleton: Skeleton,
  29. /** defines the mesh attached to the skeleton */
  30. public mesh: AbstractMesh,
  31. scene: Scene,
  32. /** defines a boolean indicating if bones matrices must be forced to update before rendering (true by default) */
  33. public autoUpdateBonesMatrices = true,
  34. /** defines the rendering group id to use with the viewer */
  35. public renderingGroupId = 1,
  36. /** defines an optional utility layer to render the helper on */
  37. public utilityLayerRenderer?: UtilityLayerRenderer
  38. ) {
  39. this._scene = scene;
  40. this.update();
  41. this._renderFunction = this.update.bind(this);
  42. }
  43. /** Gets or sets a boolean indicating if the viewer is enabled */
  44. public set isEnabled(value: boolean) {
  45. if (this._isEnabled === value) {
  46. return;
  47. }
  48. this._isEnabled = value;
  49. if (value) {
  50. this._scene.registerBeforeRender(this._renderFunction);
  51. } else {
  52. this._scene.unregisterBeforeRender(this._renderFunction);
  53. }
  54. }
  55. public get isEnabled(): boolean {
  56. return this._isEnabled;
  57. }
  58. private _getBonePosition(position: Vector3, bone: Bone, meshMat: Matrix, x = 0, y = 0, z = 0): void {
  59. var tmat = Tmp.Matrix[0];
  60. var parentBone = bone.getParent();
  61. tmat.copyFrom(bone.getLocalMatrix());
  62. if (x !== 0 || y !== 0 || z !== 0) {
  63. var tmat2 = Tmp.Matrix[1];
  64. BABYLON.Matrix.IdentityToRef(tmat2);
  65. tmat2.setTranslationFromFloats(x, y, z);
  66. tmat2.multiplyToRef(tmat, tmat);
  67. }
  68. if (parentBone) {
  69. tmat.multiplyToRef(parentBone.getAbsoluteTransform(), tmat);
  70. }
  71. tmat.multiplyToRef(meshMat, tmat);
  72. position.x = tmat.m[12];
  73. position.y = tmat.m[13];
  74. position.z = tmat.m[14];
  75. }
  76. private _getLinesForBonesWithLength(bones: Bone[], meshMat: Matrix): void {
  77. var len = bones.length;
  78. var meshPos = this.mesh.position;
  79. for (var i = 0; i < len; i++) {
  80. var bone = bones[i];
  81. var points = this._debugLines[i];
  82. if (!points) {
  83. points = [Vector3.Zero(), Vector3.Zero()];
  84. this._debugLines[i] = points;
  85. }
  86. this._getBonePosition(points[0], bone, meshMat);
  87. this._getBonePosition(points[1], bone, meshMat, 0, bone.length, 0);
  88. points[0].subtractInPlace(meshPos);
  89. points[1].subtractInPlace(meshPos);
  90. }
  91. }
  92. private _getLinesForBonesNoLength(bones: Bone[], meshMat: Matrix): void {
  93. var len = bones.length;
  94. var boneNum = 0;
  95. var meshPos = this.mesh.position;
  96. for (var i = len - 1; i >= 0; i--) {
  97. var childBone = bones[i];
  98. var parentBone = childBone.getParent();
  99. if (!parentBone) {
  100. continue;
  101. }
  102. var points = this._debugLines[boneNum];
  103. if (!points) {
  104. points = [Vector3.Zero(), Vector3.Zero()];
  105. this._debugLines[boneNum] = points;
  106. }
  107. childBone.getAbsolutePositionToRef(this.mesh, points[0]);
  108. parentBone.getAbsolutePositionToRef(this.mesh, points[1]);
  109. points[0].subtractInPlace(meshPos);
  110. points[1].subtractInPlace(meshPos);
  111. boneNum++;
  112. }
  113. }
  114. /** Update the viewer to sync with current skeleton state */
  115. public update() {
  116. if (this.autoUpdateBonesMatrices) {
  117. this.skeleton.computeAbsoluteTransforms();
  118. }
  119. if (this.skeleton.bones[0].length === undefined) {
  120. this._getLinesForBonesNoLength(this.skeleton.bones, this.mesh.getWorldMatrix());
  121. } else {
  122. this._getLinesForBonesWithLength(this.skeleton.bones, this.mesh.getWorldMatrix());
  123. }
  124. const targetScene = this.utilityLayerRenderer ? this.utilityLayerRenderer.utilityLayerScene : this._scene;
  125. if (!this._debugMesh) {
  126. this._debugMesh = BABYLON.MeshBuilder.CreateLineSystem("", { lines: this._debugLines, updatable: true, instance: null }, targetScene);
  127. this._debugMesh.renderingGroupId = this.renderingGroupId;
  128. } else {
  129. BABYLON.MeshBuilder.CreateLineSystem("", { lines: this._debugLines, updatable: true, instance: this._debugMesh }, targetScene);
  130. }
  131. this._debugMesh.position.copyFrom(this.mesh.position);
  132. this._debugMesh.color = this.color;
  133. }
  134. /** Release associated resources */
  135. public dispose() {
  136. if (this._debugMesh) {
  137. this.isEnabled = false;
  138. this._debugMesh.dispose();
  139. this._debugMesh = null;
  140. }
  141. }
  142. }
  143. }