babylon.skeletonViewer.ts 6.1 KB

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