physicsViewer.ts 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. import { Nullable } from "../types";
  2. import { Scene } from "../scene";
  3. import { AbstractMesh } from "../Meshes/abstractMesh";
  4. import { Mesh } from "../Meshes/mesh";
  5. import { BoxBuilder } from "../Meshes/Builders/boxBuilder";
  6. import { SphereBuilder } from "../Meshes/Builders/sphereBuilder";
  7. import { Quaternion, Color3, Vector3 } from "../Maths/math";
  8. import { Material } from "../Materials/material";
  9. import { EngineStore } from "../Engines/engineStore";
  10. import { StandardMaterial } from "../Materials/standardMaterial";
  11. import { IPhysicsEnginePlugin } from "../Physics/IPhysicsEngine";
  12. import { PhysicsImpostor } from "../Physics/physicsImpostor";
  13. import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
  14. /**
  15. * Used to show the physics impostor around the specific mesh
  16. */
  17. export class PhysicsViewer {
  18. /** @hidden */
  19. protected _impostors: Array<Nullable<PhysicsImpostor>> = [];
  20. /** @hidden */
  21. protected _meshes: Array<Nullable<AbstractMesh>> = [];
  22. /** @hidden */
  23. protected _scene: Nullable<Scene>;
  24. /** @hidden */
  25. protected _numMeshes = 0;
  26. /** @hidden */
  27. protected _physicsEnginePlugin: Nullable<IPhysicsEnginePlugin>;
  28. private _renderFunction: () => void;
  29. private _utilityLayer: Nullable<UtilityLayerRenderer>;
  30. private _debugBoxMesh: Mesh;
  31. private _debugSphereMesh: Mesh;
  32. private _debugMaterial: StandardMaterial;
  33. private _debugMeshMeshes = new Array<Mesh>();
  34. /**
  35. * Creates a new PhysicsViewer
  36. * @param scene defines the hosting scene
  37. */
  38. constructor(scene: Scene) {
  39. this._scene = scene || EngineStore.LastCreatedScene;
  40. let physicEngine = this._scene.getPhysicsEngine();
  41. if (physicEngine) {
  42. this._physicsEnginePlugin = physicEngine.getPhysicsPlugin();
  43. }
  44. this._utilityLayer = new UtilityLayerRenderer(this._scene, false);
  45. this._utilityLayer.pickUtilitySceneFirst = false;
  46. this._utilityLayer.utilityLayerScene.autoClearDepthAndStencil = true;
  47. }
  48. /** @hidden */
  49. protected _updateDebugMeshes(): void {
  50. var plugin = this._physicsEnginePlugin;
  51. for (var i = 0; i < this._numMeshes; i++) {
  52. let impostor = this._impostors[i];
  53. if (!impostor) {
  54. continue;
  55. }
  56. if (impostor.isDisposed) {
  57. this.hideImpostor(this._impostors[i--]);
  58. } else {
  59. if (impostor.type === PhysicsImpostor.MeshImpostor) {
  60. continue;
  61. }
  62. let mesh = this._meshes[i];
  63. if (mesh && plugin) {
  64. plugin.syncMeshWithImpostor(mesh, impostor);
  65. }
  66. }
  67. }
  68. }
  69. /**
  70. * Renders a specified physic impostor
  71. * @param impostor defines the impostor to render
  72. * @param targetMesh defines the mesh represented by the impostor
  73. * @returns the new debug mesh used to render the impostor
  74. */
  75. public showImpostor(impostor: PhysicsImpostor, targetMesh?: Mesh): Nullable<AbstractMesh> {
  76. if (!this._scene) {
  77. return null;
  78. }
  79. for (var i = 0; i < this._numMeshes; i++) {
  80. if (this._impostors[i] == impostor) {
  81. return null;
  82. }
  83. }
  84. var debugMesh = this._getDebugMesh(impostor, targetMesh);
  85. if (debugMesh) {
  86. this._impostors[this._numMeshes] = impostor;
  87. this._meshes[this._numMeshes] = debugMesh;
  88. if (this._numMeshes === 0) {
  89. this._renderFunction = this._updateDebugMeshes.bind(this);
  90. this._scene.registerBeforeRender(this._renderFunction);
  91. }
  92. this._numMeshes++;
  93. }
  94. return debugMesh;
  95. }
  96. /**
  97. * Hides a specified physic impostor
  98. * @param impostor defines the impostor to hide
  99. */
  100. public hideImpostor(impostor: Nullable<PhysicsImpostor>) {
  101. if (!impostor || !this._scene || !this._utilityLayer) {
  102. return;
  103. }
  104. var removed = false;
  105. const utilityLayerScene = this._utilityLayer.utilityLayerScene;
  106. for (var i = 0; i < this._numMeshes; i++) {
  107. if (this._impostors[i] == impostor) {
  108. let mesh = this._meshes[i];
  109. if (!mesh) {
  110. continue;
  111. }
  112. utilityLayerScene.removeMesh(mesh);
  113. mesh.dispose();
  114. let index = this._debugMeshMeshes.indexOf(mesh as Mesh);
  115. if (index > -1) {
  116. this._debugMeshMeshes.splice(index, 1);
  117. }
  118. this._numMeshes--;
  119. if (this._numMeshes > 0) {
  120. this._meshes[i] = this._meshes[this._numMeshes];
  121. this._impostors[i] = this._impostors[this._numMeshes];
  122. this._meshes[this._numMeshes] = null;
  123. this._impostors[this._numMeshes] = null;
  124. } else {
  125. this._meshes[0] = null;
  126. this._impostors[0] = null;
  127. }
  128. removed = true;
  129. break;
  130. }
  131. }
  132. if (removed && this._numMeshes === 0) {
  133. this._scene.unregisterBeforeRender(this._renderFunction);
  134. }
  135. }
  136. private _getDebugMaterial(scene: Scene): Material {
  137. if (!this._debugMaterial) {
  138. this._debugMaterial = new StandardMaterial('', scene);
  139. this._debugMaterial.wireframe = true;
  140. this._debugMaterial.emissiveColor = Color3.White();
  141. this._debugMaterial.disableLighting = true;
  142. }
  143. return this._debugMaterial;
  144. }
  145. private _getDebugBoxMesh(scene: Scene): AbstractMesh {
  146. if (!this._debugBoxMesh) {
  147. this._debugBoxMesh = BoxBuilder.CreateBox('physicsBodyBoxViewMesh', { size: 1 }, scene);
  148. this._debugBoxMesh.rotationQuaternion = Quaternion.Identity();
  149. this._debugBoxMesh.material = this._getDebugMaterial(scene);
  150. this._debugBoxMesh.setEnabled(false);
  151. }
  152. return this._debugBoxMesh.createInstance('physicsBodyBoxViewInstance');
  153. }
  154. private _getDebugSphereMesh(scene: Scene): AbstractMesh {
  155. if (!this._debugSphereMesh) {
  156. this._debugSphereMesh = SphereBuilder.CreateSphere('physicsBodySphereViewMesh', { diameter: 1 }, scene);
  157. this._debugSphereMesh.rotationQuaternion = Quaternion.Identity();
  158. this._debugSphereMesh.material = this._getDebugMaterial(scene);
  159. this._debugSphereMesh.setEnabled(false);
  160. }
  161. return this._debugSphereMesh.createInstance('physicsBodyBoxViewInstance');
  162. }
  163. private _getDebugMeshMesh(mesh: Mesh, scene: Scene): AbstractMesh {
  164. var wireframeOver = new Mesh(mesh.name, scene, null, mesh);
  165. wireframeOver.position = Vector3.Zero();
  166. wireframeOver.setParent(mesh);
  167. wireframeOver.material = this._getDebugMaterial(scene);
  168. this._debugMeshMeshes.push(wireframeOver);
  169. return wireframeOver;
  170. }
  171. private _getDebugMesh(impostor: PhysicsImpostor, targetMesh?: Mesh): Nullable<AbstractMesh> {
  172. if (!this._utilityLayer) {
  173. return null;
  174. }
  175. var mesh: Nullable<AbstractMesh> = null;
  176. const utilityLayerScene = this._utilityLayer.utilityLayerScene;
  177. switch (impostor.type) {
  178. case PhysicsImpostor.BoxImpostor:
  179. mesh = this._getDebugBoxMesh(utilityLayerScene);
  180. impostor.getBoxSizeToRef(mesh.scaling);
  181. break;
  182. case PhysicsImpostor.SphereImpostor:
  183. mesh = this._getDebugSphereMesh(utilityLayerScene);
  184. var radius = impostor.getRadius();
  185. mesh.scaling.x = radius * 2;
  186. mesh.scaling.y = radius * 2;
  187. mesh.scaling.z = radius * 2;
  188. break;
  189. case PhysicsImpostor.MeshImpostor:
  190. if (targetMesh) {
  191. mesh = this._getDebugMeshMesh(targetMesh, utilityLayerScene);
  192. }
  193. break;
  194. }
  195. return mesh;
  196. }
  197. /** Releases all resources */
  198. public dispose() {
  199. let count = this._numMeshes;
  200. for (var index = 0; index < count; index++) {
  201. this.hideImpostor(this._impostors[0]);
  202. }
  203. if (this._debugBoxMesh) {
  204. this._debugBoxMesh.dispose();
  205. }
  206. if (this._debugSphereMesh) {
  207. this._debugSphereMesh.dispose();
  208. }
  209. if (this._debugMaterial) {
  210. this._debugMaterial.dispose();
  211. }
  212. this._impostors.length = 0;
  213. this._scene = null;
  214. this._physicsEnginePlugin = null;
  215. if (this._utilityLayer) {
  216. this._utilityLayer.dispose();
  217. this._utilityLayer = null;
  218. }
  219. }
  220. }