rayHelper.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import { Vector3 } from "../Maths/math.vector.js";
  2. import { CreateLines } from "../Meshes/Builders/linesBuilder.js";
  3. /**
  4. * As raycast might be hard to debug, the RayHelper can help rendering the different rays
  5. * in order to better appreciate the issue one might have.
  6. * @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/interactions/picking_collisions#debugging
  7. */
  8. export class RayHelper {
  9. /**
  10. * Helper function to create a colored helper in a scene in one line.
  11. * @param ray Defines the ray we are currently trying to visualize
  12. * @param scene Defines the scene the ray is used in
  13. * @param color Defines the color we want to see the ray in
  14. * @returns The newly created ray helper.
  15. */
  16. static CreateAndShow(ray, scene, color) {
  17. const helper = new RayHelper(ray);
  18. helper.show(scene, color);
  19. return helper;
  20. }
  21. /**
  22. * Instantiate a new ray helper.
  23. * As raycast might be hard to debug, the RayHelper can help rendering the different rays
  24. * in order to better appreciate the issue one might have.
  25. * @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/interactions/picking_collisions#debugging
  26. * @param ray Defines the ray we are currently trying to visualize
  27. */
  28. constructor(ray) {
  29. this.ray = ray;
  30. }
  31. /**
  32. * Shows the ray we are willing to debug.
  33. * @param scene Defines the scene the ray needs to be rendered in
  34. * @param color Defines the color the ray needs to be rendered in
  35. */
  36. show(scene, color) {
  37. if (!this._renderFunction && this.ray) {
  38. const ray = this.ray;
  39. this._renderFunction = () => this._render();
  40. this._scene = scene;
  41. this._renderPoints = [ray.origin, ray.origin.add(ray.direction.scale(ray.length))];
  42. this._renderLine = CreateLines("ray", { points: this._renderPoints, updatable: true }, scene);
  43. this._renderLine.isPickable = false;
  44. if (this._renderFunction) {
  45. this._scene.registerBeforeRender(this._renderFunction);
  46. }
  47. }
  48. if (color && this._renderLine) {
  49. this._renderLine.color.copyFrom(color);
  50. }
  51. }
  52. /**
  53. * Hides the ray we are debugging.
  54. */
  55. hide() {
  56. if (this._renderFunction && this._scene) {
  57. this._scene.unregisterBeforeRender(this._renderFunction);
  58. this._scene = null;
  59. this._renderFunction = null;
  60. if (this._renderLine) {
  61. this._renderLine.dispose();
  62. this._renderLine = null;
  63. }
  64. this._renderPoints = [];
  65. }
  66. }
  67. _render() {
  68. const ray = this.ray;
  69. if (!ray) {
  70. return;
  71. }
  72. const point = this._renderPoints[1];
  73. const len = Math.min(ray.length, 1000000);
  74. point.copyFrom(ray.direction);
  75. point.scaleInPlace(len);
  76. point.addInPlace(ray.origin);
  77. this._renderPoints[0].copyFrom(ray.origin);
  78. CreateLines("ray", { points: this._renderPoints, updatable: true, instance: this._renderLine }, this._scene);
  79. this._renderLine?.refreshBoundingInfo();
  80. }
  81. /**
  82. * Attach a ray helper to a mesh so that we can easily see its orientation for instance or information like its normals.
  83. * @param mesh Defines the mesh we want the helper attached to
  84. * @param meshSpaceDirection Defines the direction of the Ray in mesh space (local space of the mesh node)
  85. * @param meshSpaceOrigin Defines the origin of the Ray in mesh space (local space of the mesh node)
  86. * @param length Defines the length of the ray
  87. */
  88. attachToMesh(mesh, meshSpaceDirection, meshSpaceOrigin, length) {
  89. this._attachedToMesh = mesh;
  90. const ray = this.ray;
  91. if (!ray) {
  92. return;
  93. }
  94. if (!ray.direction) {
  95. ray.direction = Vector3.Zero();
  96. }
  97. if (!ray.origin) {
  98. ray.origin = Vector3.Zero();
  99. }
  100. if (length) {
  101. ray.length = length;
  102. }
  103. if (!meshSpaceOrigin) {
  104. meshSpaceOrigin = Vector3.Zero();
  105. }
  106. if (!meshSpaceDirection) {
  107. // -1 so that this will work with Mesh.lookAt
  108. meshSpaceDirection = new Vector3(0, 0, -1);
  109. }
  110. if (!this._scene) {
  111. this._scene = mesh.getScene();
  112. }
  113. if (!this._meshSpaceDirection) {
  114. this._meshSpaceDirection = meshSpaceDirection.clone();
  115. this._meshSpaceOrigin = meshSpaceOrigin.clone();
  116. }
  117. else {
  118. this._meshSpaceDirection.copyFrom(meshSpaceDirection);
  119. this._meshSpaceOrigin.copyFrom(meshSpaceOrigin);
  120. }
  121. if (!this._onAfterRenderObserver) {
  122. this._onAfterRenderObserver = this._scene.onBeforeRenderObservable.add(() => this._updateToMesh());
  123. this._onAfterStepObserver = this._scene.onAfterStepObservable.add(() => this._updateToMesh());
  124. }
  125. // force world matrix computation before the first ray helper computation
  126. this._attachedToMesh.computeWorldMatrix(true);
  127. this._updateToMesh();
  128. }
  129. /**
  130. * Detach the ray helper from the mesh it has previously been attached to.
  131. */
  132. detachFromMesh() {
  133. if (this._attachedToMesh && this._scene) {
  134. if (this._onAfterRenderObserver) {
  135. this._scene.onBeforeRenderObservable.remove(this._onAfterRenderObserver);
  136. this._scene.onAfterStepObservable.remove(this._onAfterStepObserver);
  137. }
  138. this._attachedToMesh = null;
  139. this._onAfterRenderObserver = null;
  140. this._onAfterStepObserver = null;
  141. this._scene = null;
  142. }
  143. }
  144. _updateToMesh() {
  145. const ray = this.ray;
  146. if (!this._attachedToMesh || !ray) {
  147. return;
  148. }
  149. if (this._attachedToMesh.isDisposed()) {
  150. this.detachFromMesh();
  151. return;
  152. }
  153. this._attachedToMesh.getDirectionToRef(this._meshSpaceDirection, ray.direction);
  154. Vector3.TransformCoordinatesToRef(this._meshSpaceOrigin, this._attachedToMesh.getWorldMatrix(), ray.origin);
  155. }
  156. /**
  157. * Dispose the helper and release its associated resources.
  158. */
  159. dispose() {
  160. this.hide();
  161. this.detachFromMesh();
  162. this.ray = null;
  163. }
  164. }
  165. //# sourceMappingURL=rayHelper.js.map