Raycaster.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. */
  4. ( function ( THREE ) {
  5. THREE.Raycaster = function ( origin, direction, near, far ) {
  6. this.ray = new THREE.Ray( origin, direction );
  7. this.near = near || 0;
  8. this.far = far || Infinity;
  9. };
  10. var originCopy = new THREE.Vector3();
  11. var localOriginCopy = new THREE.Vector3();
  12. var localDirectionCopy = new THREE.Vector3();
  13. var vector = new THREE.Vector3();
  14. var normal = new THREE.Vector3();
  15. var intersectPoint = new THREE.Vector3();
  16. var inverseMatrix = new THREE.Matrix4();
  17. var descSort = function ( a, b ) {
  18. return a.distance - b.distance;
  19. };
  20. var v0 = new THREE.Vector3(), v1 = new THREE.Vector3(), v2 = new THREE.Vector3();
  21. // http://www.blackpawn.com/texts/pointinpoly/default.html
  22. var pointInFace3 = function ( p, a, b, c ) {
  23. v0.sub( c, a );
  24. v1.sub( b, a );
  25. v2.sub( p, a );
  26. var dot00 = v0.dot( v0 );
  27. var dot01 = v0.dot( v1 );
  28. var dot02 = v0.dot( v2 );
  29. var dot11 = v1.dot( v1 );
  30. var dot12 = v1.dot( v2 );
  31. var invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 );
  32. var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
  33. var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
  34. return ( u >= 0 ) && ( v >= 0 ) && ( u + v < 1 );
  35. };
  36. var intersectObject = function ( object, raycaster, intersects ) {
  37. if ( object instanceof THREE.Particle ) {
  38. var distance = raycaster.ray.distanceToPoint( object.matrixWorld.getPosition() );
  39. if ( distance > object.scale.x ) {
  40. return intersects;
  41. }
  42. intersects.push( {
  43. distance: distance,
  44. point: object.position,
  45. face: null,
  46. object: object
  47. } );
  48. } else if ( object instanceof THREE.Mesh ) {
  49. // Checking boundingSphere
  50. var scaledRadius = object.geometry.boundingSphere.radius * object.matrixWorld.getMaxScaleOnAxis();
  51. // Checking distance to raycaster
  52. var distance = raycaster.ray.distanceToPoint( object.matrixWorld.getPosition() );
  53. if ( distance > scaledRadius) {
  54. return intersects;
  55. }
  56. // Checking faces
  57. var geometry = object.geometry;
  58. var vertices = geometry.vertices;
  59. var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
  60. var objectMaterials = isFaceMaterial === true ? object.material.materials : null;
  61. var side = object.material.side;
  62. var a, b, c, d;
  63. var precision = raycaster.precision;
  64. object.matrixRotationWorld.extractRotation( object.matrixWorld );
  65. originCopy.copy( raycaster.ray.origin );
  66. inverseMatrix.getInverse( object.matrixWorld );
  67. localOriginCopy.copy( originCopy );
  68. inverseMatrix.multiplyVector3( localOriginCopy );
  69. localDirectionCopy.copy( raycaster.ray.direction );
  70. inverseMatrix.rotateAxis( localDirectionCopy ).normalize();
  71. for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
  72. var face = geometry.faces[ f ];
  73. var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material;
  74. if ( material === undefined ) continue;
  75. side = material.side;
  76. vector.sub( face.centroid, localOriginCopy );
  77. var normal = face.normal;
  78. var dot = localDirectionCopy.dot( normal );
  79. // bail if raycaster and plane are parallel
  80. if ( Math.abs( dot ) < precision ) continue;
  81. // calc distance to plane
  82. var scalar = normal.dot( vector ) / dot;
  83. // if negative distance, then plane is behind raycaster
  84. if ( scalar < 0 ) continue;
  85. if ( side === THREE.DoubleSide || ( side === THREE.FrontSide ? dot < 0 : dot > 0 ) ) {
  86. intersectPoint.add( localOriginCopy, localDirectionCopy.multiplyScalar( scalar ) );
  87. if ( face instanceof THREE.Face3 ) {
  88. a = vertices[ face.a ];
  89. b = vertices[ face.b ];
  90. c = vertices[ face.c ];
  91. if ( pointInFace3( intersectPoint, a, b, c ) ) {
  92. var point = object.matrixWorld.multiplyVector3( intersectPoint.clone() );
  93. distance = originCopy.distanceTo( point );
  94. if ( distance < raycaster.near || distance > raycaster.far ) continue;
  95. intersects.push( {
  96. distance: distance,
  97. point: point,
  98. face: face,
  99. faceIndex: f,
  100. object: object
  101. } );
  102. }
  103. } else if ( face instanceof THREE.Face4 ) {
  104. a = vertices[ face.a ];
  105. b = vertices[ face.b ];
  106. c = vertices[ face.c ];
  107. d = vertices[ face.d ];
  108. if ( pointInFace3( intersectPoint, a, b, d ) || pointInFace3( intersectPoint, b, c, d ) ) {
  109. var point = object.matrixWorld.multiplyVector3( intersectPoint.clone() );
  110. distance = originCopy.distanceTo( point );
  111. if ( distance < raycaster.near || distance > raycaster.far ) continue;
  112. intersects.push( {
  113. distance: distance,
  114. point: point,
  115. face: face,
  116. faceIndex: f,
  117. object: object
  118. } );
  119. }
  120. }
  121. }
  122. }
  123. }
  124. };
  125. var intersectDescendants = function ( object, raycaster, intersects ) {
  126. var descendants = object.getDescendants();
  127. for ( var i = 0, l = descendants.length; i < l; i ++ ) {
  128. intersectObject( descendants[ i ], raycaster, intersects );
  129. }
  130. };
  131. //
  132. THREE.Raycaster.prototype.precision = 0.0001;
  133. THREE.Raycaster.prototype.set = function ( origin, direction ) {
  134. this.ray.set( origin, direction );
  135. };
  136. THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) {
  137. var intersects = [];
  138. if ( recursive === true ) {
  139. intersectDescendants( object, this, intersects );
  140. }
  141. intersectObject( object, this, intersects );
  142. intersects.sort( descSort );
  143. return intersects;
  144. };
  145. THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) {
  146. var intersects = [];
  147. for ( var i = 0, l = objects.length; i < l; i ++ ) {
  148. intersectObject( objects[ i ], this, intersects );
  149. if ( recursive === true ) {
  150. intersectDescendants( objects[ i ], this, intersects );
  151. }
  152. }
  153. intersects.sort( descSort );
  154. return intersects;
  155. };
  156. }( THREE ) );