Raycaster.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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. // normalized ray.direction required for accurate distance calculations
  8. if( this.ray.direction.length() > 0 ) {
  9. this.ray.direction.normalize();
  10. }
  11. this.near = near || 0;
  12. this.far = far || Infinity;
  13. };
  14. var sphere = new THREE.Sphere();
  15. var localRay = new THREE.Ray();
  16. var facePlane = new THREE.Plane();
  17. var intersectPoint = new THREE.Vector3();
  18. var inverseMatrix = new THREE.Matrix4();
  19. var descSort = function ( a, b ) {
  20. return a.distance - b.distance;
  21. };
  22. var v0 = new THREE.Vector3(), v1 = new THREE.Vector3(), v2 = new THREE.Vector3();
  23. // http://www.blackpawn.com/texts/pointinpoly/default.html
  24. var pointInFace3 = function ( p, a, b, c ) {
  25. v0.sub( c, a );
  26. v1.sub( b, a );
  27. v2.sub( p, a );
  28. var dot00 = v0.dot( v0 );
  29. var dot01 = v0.dot( v1 );
  30. var dot02 = v0.dot( v2 );
  31. var dot11 = v1.dot( v1 );
  32. var dot12 = v1.dot( v2 );
  33. var invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 );
  34. var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
  35. var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
  36. return ( u >= 0 ) && ( v >= 0 ) && ( u + v < 1 );
  37. };
  38. var intersectObject = function ( object, raycaster, intersects ) {
  39. if ( object instanceof THREE.Particle ) {
  40. var distance = raycaster.ray.distanceToPoint( object.matrixWorld.getPosition() );
  41. if ( distance > object.scale.x ) {
  42. return intersects;
  43. }
  44. intersects.push( {
  45. distance: distance,
  46. point: object.position,
  47. face: null,
  48. object: object
  49. } );
  50. } else if ( object instanceof THREE.Mesh ) {
  51. // Checking boundingSphere distance to ray
  52. sphere.set(
  53. object.matrixWorld.getPosition(),
  54. object.geometry.boundingSphere.radius* object.matrixWorld.getMaxScaleOnAxis() );
  55. if ( ! raycaster.ray.isIntersectionSphere( sphere ) ) {
  56. return intersects;
  57. }
  58. // Checking faces
  59. var geometry = object.geometry;
  60. var vertices = geometry.vertices;
  61. var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
  62. var objectMaterials = isFaceMaterial === true ? object.material.materials : null;
  63. var side = object.material.side;
  64. var a, b, c, d;
  65. var precision = raycaster.precision;
  66. object.matrixRotationWorld.extractRotation( object.matrixWorld );
  67. inverseMatrix.getInverse( object.matrixWorld );
  68. localRay.copy( raycaster.ray ).transformSelf( inverseMatrix );
  69. for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
  70. var face = geometry.faces[ f ];
  71. var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material;
  72. if ( material === undefined ) continue;
  73. facePlane.setFromNormalAndCoplanarPoint( face.normal, face.centroid );
  74. var planeDistance = localRay.distanceToPlane( facePlane );
  75. // bail if raycaster and plane are parallel
  76. if ( Math.abs( planeDistance ) < precision ) continue;
  77. // if negative distance, then plane is behind raycaster
  78. if ( planeDistance < 0 ) continue;
  79. // check if we hit the wrong side of a single sided face
  80. side = material.side;
  81. if( side !== THREE.DoubleSide ) {
  82. var planeSign = localRay.direction.dot( facePlane.normal );
  83. if( ! ( side === THREE.FrontSide ? planeSign < 0 : planeSign > 0 ) ) continue;
  84. }
  85. // this can be done using the planeDistance from localRay because localRay wasn't normalized, but ray was
  86. if ( planeDistance < raycaster.near || planeDistance > raycaster.far ) continue;
  87. intersectPoint = localRay.at( planeDistance, intersectPoint ); // passing in intersectPoint avoids a copy
  88. if ( face instanceof THREE.Face3 ) {
  89. a = vertices[ face.a ];
  90. b = vertices[ face.b ];
  91. c = vertices[ face.c ];
  92. if ( ! pointInFace3( intersectPoint, a, b, c ) ) continue;
  93. } else if ( face instanceof THREE.Face4 ) {
  94. a = vertices[ face.a ];
  95. b = vertices[ face.b ];
  96. c = vertices[ face.c ];
  97. d = vertices[ face.d ];
  98. if ( ( ! pointInFace3( intersectPoint, a, b, d ) ) &&
  99. ( ! pointInFace3( intersectPoint, b, c, d ) ) ) continue;
  100. } else {
  101. // This is added because if we call out of this if/else group when none of the cases
  102. // match it will add a point to the intersection list erroneously.
  103. throw Error( "face type not supported" );
  104. }
  105. intersects.push( {
  106. distance: planeDistance, // this works because the original ray was normalized, and the transformed localRay wasn't
  107. point: raycaster.ray.at( planeDistance ),
  108. face: face,
  109. faceIndex: f,
  110. object: object
  111. } );
  112. }
  113. }
  114. };
  115. var intersectDescendants = function ( object, raycaster, intersects ) {
  116. var descendants = object.getDescendants();
  117. for ( var i = 0, l = descendants.length; i < l; i ++ ) {
  118. intersectObject( descendants[ i ], raycaster, intersects );
  119. }
  120. };
  121. //
  122. THREE.Raycaster.prototype.precision = 0.0001;
  123. THREE.Raycaster.prototype.set = function ( origin, direction ) {
  124. this.ray.set( origin, direction );
  125. // normalized ray.direction required for accurate distance calculations
  126. if( this.ray.direction.length() > 0 ) {
  127. this.ray.direction.normalize();
  128. }
  129. };
  130. THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) {
  131. var intersects = [];
  132. if ( recursive === true ) {
  133. intersectDescendants( object, this, intersects );
  134. }
  135. intersectObject( object, this, intersects );
  136. intersects.sort( descSort );
  137. return intersects;
  138. };
  139. THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) {
  140. var intersects = [];
  141. for ( var i = 0, l = objects.length; i < l; i ++ ) {
  142. intersectObject( objects[ i ], this, intersects );
  143. if ( recursive === true ) {
  144. intersectDescendants( objects[ i ], this, intersects );
  145. }
  146. }
  147. intersects.sort( descSort );
  148. return intersects;
  149. };
  150. }( THREE ) );
粤ICP备19079148号