Raycaster.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. import { Matrix4 } from '../math/Matrix4.js';
  2. import { Ray } from '../math/Ray.js';
  3. import { Layers } from './Layers.js';
  4. const _matrix = /*@__PURE__*/ new Matrix4();
  5. /**
  6. * This class is designed to assist with raycasting. Raycasting is used for
  7. * mouse picking (working out what objects in the 3d space the mouse is over)
  8. * amongst other things.
  9. */
  10. class Raycaster {
  11. /**
  12. * Constructs a new raycaster.
  13. *
  14. * @param {Vector3} origin - The origin vector where the ray casts from.
  15. * @param {Vector3} direction - The (normalized) direction vector that gives direction to the ray.
  16. * @param {number} [near=0] - All results returned are further away than near. Near can't be negative.
  17. * @param {number} [far=Infinity] - All results returned are closer than far. Far can't be lower than near.
  18. */
  19. constructor( origin, direction, near = 0, far = Infinity ) {
  20. /**
  21. * The ray used for raycasting.
  22. *
  23. * @type {Ray}
  24. */
  25. this.ray = new Ray( origin, direction );
  26. /**
  27. * All results returned are further away than near. Near can't be negative.
  28. *
  29. * @type {number}
  30. * @default 0
  31. */
  32. this.near = near;
  33. /**
  34. * All results returned are further away than near. Near can't be negative.
  35. *
  36. * @type {number}
  37. * @default Infinity
  38. */
  39. this.far = far;
  40. /**
  41. * The camera to use when raycasting against view-dependent objects such as
  42. * billboarded objects like sprites. This field can be set manually or
  43. * is set when calling `setFromCamera()`.
  44. *
  45. * @type {?Camera}
  46. * @default null
  47. */
  48. this.camera = null;
  49. /**
  50. * Allows to selectively ignore 3D objects when performing intersection tests.
  51. * The following code example ensures that only 3D objects on layer `1` will be
  52. * honored by raycaster.
  53. * ```js
  54. * raycaster.layers.set( 1 );
  55. * object.layers.enable( 1 );
  56. * ```
  57. *
  58. * @type {Layers}
  59. */
  60. this.layers = new Layers();
  61. /**
  62. * A parameter object that configures the raycasting. It has the structure:
  63. *
  64. * ```
  65. * {
  66. * Mesh: {},
  67. * Line: { threshold: 1 },
  68. * LOD: {},
  69. * Points: { threshold: 1 },
  70. * Sprite: {}
  71. * }
  72. * ```
  73. * Where `threshold` is the precision of the raycaster when intersecting objects, in world units.
  74. *
  75. * @type {Object}
  76. */
  77. this.params = {
  78. Mesh: {},
  79. Line: { threshold: 1 },
  80. LOD: {},
  81. Points: { threshold: 1 },
  82. Sprite: {}
  83. };
  84. }
  85. /**
  86. * Updates the ray with a new origin and direction by copying the values from the arguments.
  87. *
  88. * @param {Vector3} origin - The origin vector where the ray casts from.
  89. * @param {Vector3} direction - The (normalized) direction vector that gives direction to the ray.
  90. */
  91. set( origin, direction ) {
  92. // direction is assumed to be normalized (for accurate distance calculations)
  93. this.ray.set( origin, direction );
  94. }
  95. /**
  96. * Uses the given coordinates and camera to compute a new origin and direction for the internal ray.
  97. *
  98. * @param {Vector2} coords - 2D coordinates of the mouse, in normalized device coordinates (NDC).
  99. * X and Y components should be between `-1` and `1`.
  100. * @param {Camera} camera - The camera from which the ray should originate.
  101. */
  102. setFromCamera( coords, camera ) {
  103. if ( camera.isPerspectiveCamera ) {
  104. this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
  105. this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
  106. this.camera = camera;
  107. } else if ( camera.isOrthographicCamera ) {
  108. this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
  109. this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
  110. this.camera = camera;
  111. } else {
  112. console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type );
  113. }
  114. }
  115. /**
  116. * Uses the given WebXR controller to compute a new origin and direction for the internal ray.
  117. *
  118. * @param {WebXRController} controller - The controller to copy the position and direction from.
  119. * @return {Raycaster} A reference to this raycaster.
  120. */
  121. setFromXRController( controller ) {
  122. _matrix.identity().extractRotation( controller.matrixWorld );
  123. this.ray.origin.setFromMatrixPosition( controller.matrixWorld );
  124. this.ray.direction.set( 0, 0, - 1 ).applyMatrix4( _matrix );
  125. return this;
  126. }
  127. /**
  128. * The intersection point of a raycaster intersection test.
  129. * @typedef {Object} Raycaster~Intersection
  130. * @property {number} distance - The distance from the ray's origin to the intersection point.
  131. * @property {number} distanceToRay - Some 3D objects e.g. {@link Points} provide the distance of the
  132. * intersection to the nearest point on the ray. For other objects it will be `undefined`.
  133. * @property {Vector3} point - The intersection point, in world coordinates.
  134. * @property {Object} face - The face that has been intersected.
  135. * @property {number} faceIndex - The face index.
  136. * @property {Object3D} object - The 3D object that has been intersected.
  137. * @property {Vector2} uv - U,V coordinates at point of intersection.
  138. * @property {Vector2} uv1 - Second set of U,V coordinates at point of intersection.
  139. * @property {Vector3} uv1 - Interpolated normal vector at point of intersection.
  140. * @property {number} instanceId - The index number of the instance where the ray
  141. * intersects the {@link InstancedMesh}.
  142. */
  143. /**
  144. * Checks all intersection between the ray and the object with or without the
  145. * descendants. Intersections are returned sorted by distance, closest first.
  146. *
  147. * `Raycaster` delegates to the `raycast()` method of the passed 3D object, when
  148. * evaluating whether the ray intersects the object or not. This allows meshes to respond
  149. * differently to ray casting than lines or points.
  150. *
  151. * Note that for meshes, faces must be pointed towards the origin of the ray in order
  152. * to be detected; intersections of the ray passing through the back of a face will not
  153. * be detected. To raycast against both faces of an object, you'll want to set {@link Material#side}
  154. * to `THREE.DoubleSide`.
  155. *
  156. * @param {Object3D} object - The 3D object to check for intersection with the ray.
  157. * @param {boolean} [recursive=true] - If set to `true`, it also checks all descendants.
  158. * Otherwise it only checks intersection with the object.
  159. * @param {Array<Raycaster~Intersection>} [intersects=[]] The target array that holds the result of the method.
  160. * @return {Array<Raycaster~Intersection>} An array holding the intersection points.
  161. */
  162. intersectObject( object, recursive = true, intersects = [] ) {
  163. intersect( object, this, intersects, recursive );
  164. intersects.sort( ascSort );
  165. return intersects;
  166. }
  167. /**
  168. * Checks all intersection between the ray and the objects with or without
  169. * the descendants. Intersections are returned sorted by distance, closest first.
  170. *
  171. * @param {Array<Object3D>} objects - The 3D objects to check for intersection with the ray.
  172. * @param {boolean} [recursive=true] - If set to `true`, it also checks all descendants.
  173. * Otherwise it only checks intersection with the object.
  174. * @param {Array<Raycaster~Intersection>} [intersects=[]] The target array that holds the result of the method.
  175. * @return {Array<Raycaster~Intersection>} An array holding the intersection points.
  176. */
  177. intersectObjects( objects, recursive = true, intersects = [] ) {
  178. for ( let i = 0, l = objects.length; i < l; i ++ ) {
  179. intersect( objects[ i ], this, intersects, recursive );
  180. }
  181. intersects.sort( ascSort );
  182. return intersects;
  183. }
  184. }
  185. function ascSort( a, b ) {
  186. return a.distance - b.distance;
  187. }
  188. function intersect( object, raycaster, intersects, recursive ) {
  189. let propagate = true;
  190. if ( object.layers.test( raycaster.layers ) ) {
  191. const result = object.raycast( raycaster, intersects );
  192. if ( result === false ) propagate = false;
  193. }
  194. if ( propagate === true && recursive === true ) {
  195. const children = object.children;
  196. for ( let i = 0, l = children.length; i < l; i ++ ) {
  197. intersect( children[ i ], raycaster, intersects, true );
  198. }
  199. }
  200. }
  201. export { Raycaster };