Frustum.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import { WebGLCoordinateSystem, WebGPUCoordinateSystem } from '../constants.js';
  2. import { Vector3 } from './Vector3.js';
  3. import { Sphere } from './Sphere.js';
  4. import { Plane } from './Plane.js';
  5. const _sphere = /*@__PURE__*/ new Sphere();
  6. const _vector = /*@__PURE__*/ new Vector3();
  7. /**
  8. * Frustums are used to determine what is inside the camera's field of view.
  9. * They help speed up the rendering process - objects which lie outside a camera's
  10. * frustum can safely be excluded from rendering.
  11. *
  12. * This class is mainly intended for use internally by a renderer.
  13. */
  14. class Frustum {
  15. /**
  16. * Constructs a new frustum.
  17. *
  18. * @param {Plane} [p0] - The first plane that encloses the frustum.
  19. * @param {Plane} [p1] - The second plane that encloses the frustum.
  20. * @param {Plane} [p2] - The third plane that encloses the frustum.
  21. * @param {Plane} [p3] - The fourth plane that encloses the frustum.
  22. * @param {Plane} [p4] - The fifth plane that encloses the frustum.
  23. * @param {Plane} [p5] - The sixth plane that encloses the frustum.
  24. */
  25. constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) {
  26. /**
  27. * This array holds the planes that enclose the frustum.
  28. *
  29. * @type {Array<Plane>}
  30. */
  31. this.planes = [ p0, p1, p2, p3, p4, p5 ];
  32. }
  33. /**
  34. * Sets the frustum planes by copying the given planes.
  35. *
  36. * @param {Plane} [p0] - The first plane that encloses the frustum.
  37. * @param {Plane} [p1] - The second plane that encloses the frustum.
  38. * @param {Plane} [p2] - The third plane that encloses the frustum.
  39. * @param {Plane} [p3] - The fourth plane that encloses the frustum.
  40. * @param {Plane} [p4] - The fifth plane that encloses the frustum.
  41. * @param {Plane} [p5] - The sixth plane that encloses the frustum.
  42. * @return {Frustum} A reference to this frustum.
  43. */
  44. set( p0, p1, p2, p3, p4, p5 ) {
  45. const planes = this.planes;
  46. planes[ 0 ].copy( p0 );
  47. planes[ 1 ].copy( p1 );
  48. planes[ 2 ].copy( p2 );
  49. planes[ 3 ].copy( p3 );
  50. planes[ 4 ].copy( p4 );
  51. planes[ 5 ].copy( p5 );
  52. return this;
  53. }
  54. /**
  55. * Copies the values of the given frustum to this instance.
  56. *
  57. * @param {Frustum} frustum - The frustum to copy.
  58. * @return {Frustum} A reference to this frustum.
  59. */
  60. copy( frustum ) {
  61. const planes = this.planes;
  62. for ( let i = 0; i < 6; i ++ ) {
  63. planes[ i ].copy( frustum.planes[ i ] );
  64. }
  65. return this;
  66. }
  67. /**
  68. * Sets the frustum planes from the given projection matrix.
  69. *
  70. * @param {Matrix4} m - The projection matrix.
  71. * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} coordinateSystem - The coordinate system.
  72. * @return {Frustum} A reference to this frustum.
  73. */
  74. setFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) {
  75. const planes = this.planes;
  76. const me = m.elements;
  77. const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
  78. const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
  79. const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
  80. const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
  81. planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
  82. planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
  83. planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
  84. planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
  85. planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
  86. if ( coordinateSystem === WebGLCoordinateSystem ) {
  87. planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
  88. } else if ( coordinateSystem === WebGPUCoordinateSystem ) {
  89. planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize();
  90. } else {
  91. throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem );
  92. }
  93. return this;
  94. }
  95. /**
  96. * Returns `true` if the 3D object's bounding sphere is intersecting this frustum.
  97. *
  98. * Note that the 3D object must have a geometry so that the bounding sphere can be calculated.
  99. *
  100. * @param {Object3D} object - The 3D object to test.
  101. * @return {boolean} Whether the 3D object's bounding sphere is intersecting this frustum or not.
  102. */
  103. intersectsObject( object ) {
  104. if ( object.boundingSphere !== undefined ) {
  105. if ( object.boundingSphere === null ) object.computeBoundingSphere();
  106. _sphere.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld );
  107. } else {
  108. const geometry = object.geometry;
  109. if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
  110. _sphere.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );
  111. }
  112. return this.intersectsSphere( _sphere );
  113. }
  114. /**
  115. * Returns `true` if the given sprite is intersecting this frustum.
  116. *
  117. * @param {Sprite} sprite - The sprite to test.
  118. * @return {boolean} Whether the sprite is intersecting this frustum or not.
  119. */
  120. intersectsSprite( sprite ) {
  121. _sphere.center.set( 0, 0, 0 );
  122. _sphere.radius = 0.7071067811865476;
  123. _sphere.applyMatrix4( sprite.matrixWorld );
  124. return this.intersectsSphere( _sphere );
  125. }
  126. /**
  127. * Returns `true` if the given bounding sphere is intersecting this frustum.
  128. *
  129. * @param {Sphere} sphere - The bounding sphere to test.
  130. * @return {boolean} Whether the bounding sphere is intersecting this frustum or not.
  131. */
  132. intersectsSphere( sphere ) {
  133. const planes = this.planes;
  134. const center = sphere.center;
  135. const negRadius = - sphere.radius;
  136. for ( let i = 0; i < 6; i ++ ) {
  137. const distance = planes[ i ].distanceToPoint( center );
  138. if ( distance < negRadius ) {
  139. return false;
  140. }
  141. }
  142. return true;
  143. }
  144. /**
  145. * Returns `true` if the given bounding box is intersecting this frustum.
  146. *
  147. * @param {Box3} box - The bounding box to test.
  148. * @return {boolean} Whether the bounding box is intersecting this frustum or not.
  149. */
  150. intersectsBox( box ) {
  151. const planes = this.planes;
  152. for ( let i = 0; i < 6; i ++ ) {
  153. const plane = planes[ i ];
  154. // corner at max distance
  155. _vector.x = plane.normal.x > 0 ? box.max.x : box.min.x;
  156. _vector.y = plane.normal.y > 0 ? box.max.y : box.min.y;
  157. _vector.z = plane.normal.z > 0 ? box.max.z : box.min.z;
  158. if ( plane.distanceToPoint( _vector ) < 0 ) {
  159. return false;
  160. }
  161. }
  162. return true;
  163. }
  164. /**
  165. * Returns `true` if the given point lies within the frustum.
  166. *
  167. * @param {Vector3} point - The point to test.
  168. * @return {boolean} Whether the point lies within this frustum or not.
  169. */
  170. containsPoint( point ) {
  171. const planes = this.planes;
  172. for ( let i = 0; i < 6; i ++ ) {
  173. if ( planes[ i ].distanceToPoint( point ) < 0 ) {
  174. return false;
  175. }
  176. }
  177. return true;
  178. }
  179. /**
  180. * Returns a new frustum with copied values from this instance.
  181. *
  182. * @return {Frustum} A clone of this instance.
  183. */
  184. clone() {
  185. return new this.constructor().copy( this );
  186. }
  187. }
  188. export { Frustum };