Ray.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /**
  2. * @author bhouston / http://exocortex.com
  3. */
  4. THREE.Ray = function ( origin, direction ) {
  5. this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3();
  6. this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3();
  7. };
  8. THREE.Ray.prototype = {
  9. constructor: THREE.Ray,
  10. set: function ( origin, direction ) {
  11. this.origin.copy( origin );
  12. this.direction.copy( direction );
  13. return this;
  14. },
  15. copy: function ( ray ) {
  16. this.origin.copy( ray.origin );
  17. this.direction.copy( ray.direction );
  18. return this;
  19. },
  20. at: function ( t, optionalTarget ) {
  21. var result = optionalTarget || new THREE.Vector3();
  22. return result.copy( this.direction ).multiplyScalar( t ).add( this.origin );
  23. },
  24. recast: function () {
  25. var v1 = new THREE.Vector3();
  26. return function ( t ) {
  27. this.origin.copy( this.at( t, v1 ) );
  28. return this;
  29. };
  30. }(),
  31. closestPointToPoint: function ( point, optionalTarget ) {
  32. var result = optionalTarget || new THREE.Vector3();
  33. result.subVectors( point, this.origin );
  34. var directionDistance = result.dot( this.direction );
  35. if ( directionDistance < 0 ) {
  36. return this.origin.clone();
  37. }
  38. return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
  39. },
  40. distanceToPoint: function () {
  41. var v1 = new THREE.Vector3();
  42. return function ( point ) {
  43. var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
  44. // point behind the ray
  45. if ( directionDistance < 0 ) {
  46. return this.origin.distanceTo( point );
  47. }
  48. v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
  49. return v1.distanceTo( point );
  50. };
  51. }(),
  52. distanceToSegment: function( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
  53. // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp
  54. // It returns the min distance between the ray and the segment
  55. // defined by v0 and v1
  56. // It can also set two optional targets :
  57. // - The closest point on the ray
  58. // - The closest point on the segment
  59. var segCenter = v0.clone().add( v1 ).multiplyScalar( 0.5 );
  60. var segDir = v1.clone().sub( v0 ).normalize();
  61. var segExtent = v0.distanceTo( v1 ) * 0.5;
  62. var diff = this.origin.clone().sub( segCenter );
  63. var a01 = - this.direction.dot( segDir );
  64. var b0 = diff.dot( this.direction );
  65. var b1 = - diff.dot( segDir );
  66. var c = diff.lengthSq();
  67. var det = Math.abs( 1 - a01 * a01 );
  68. var s0, s1, sqrDist, extDet;
  69. if (det >= 0) {
  70. // The ray and segment are not parallel.
  71. s0 = a01 * b1 - b0;
  72. s1 = a01 * b0 - b1;
  73. extDet = segExtent * det;
  74. if (s0 >= 0) {
  75. if (s1 >= -extDet) {
  76. if (s1 <= extDet) {
  77. // region 0
  78. // Minimum at interior points of ray and segment.
  79. var invDet = 1 / det;
  80. s0 *= invDet;
  81. s1 *= invDet;
  82. sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
  83. } else {
  84. // region 1
  85. s1 = segExtent;
  86. s0 = Math.max( 0, - ( a01 * s1 + b0) );
  87. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  88. }
  89. }
  90. else {
  91. // region 5
  92. s1 = - segExtent;
  93. s0 = Math.max( 0, - ( a01 * s1 + b0) );
  94. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  95. }
  96. } else {
  97. if ( s1 <= - extDet) {
  98. // region 4
  99. s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
  100. s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
  101. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  102. } else if (s1 <= extDet) {
  103. // region 3
  104. s0 = 0;
  105. s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
  106. sqrDist = s1 * ( s1 + 2 * b1 ) + c;
  107. } else {
  108. // region 2
  109. s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
  110. s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
  111. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  112. }
  113. }
  114. } else {
  115. // Ray and segment are parallel.
  116. s1 = ( a01 > 0 ) ? - segExtent : segExtent;
  117. s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
  118. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  119. }
  120. if ( optionalPointOnRay ) {
  121. optionalPointOnRay.copy( this.direction.clone().multiplyScalar( s0 ).add( this.origin ) );
  122. }
  123. if ( optionalPointOnSegment ) {
  124. optionalPointOnSegment.copy( segDir.clone().multiplyScalar( s1 ).add( segCenter ) );
  125. }
  126. return sqrDist;
  127. },
  128. isIntersectionSphere: function ( sphere ) {
  129. return this.distanceToPoint( sphere.center ) <= sphere.radius;
  130. },
  131. isIntersectionPlane: function ( plane ) {
  132. // check if the ray lies on the plane first
  133. var distToPoint = plane.distanceToPoint( this.origin );
  134. if ( distToPoint === 0 ) {
  135. return true;
  136. }
  137. var denominator = plane.normal.dot( this.direction );
  138. if ( denominator * distToPoint < 0 ) {
  139. return true
  140. }
  141. // ray origin is behind the plane (and is pointing behind it)
  142. return false;
  143. },
  144. distanceToPlane: function ( plane ) {
  145. var denominator = plane.normal.dot( this.direction );
  146. if ( denominator == 0 ) {
  147. // line is coplanar, return origin
  148. if( plane.distanceToPoint( this.origin ) == 0 ) {
  149. return 0;
  150. }
  151. // Null is preferable to undefined since undefined means.... it is undefined
  152. return null;
  153. }
  154. var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
  155. // Return if the ray never intersects the plane
  156. return t >= 0 ? t : null;
  157. },
  158. intersectPlane: function ( plane, optionalTarget ) {
  159. var t = this.distanceToPlane( plane );
  160. if ( t === null ) {
  161. return null;
  162. }
  163. return this.at( t, optionalTarget );
  164. },
  165. applyMatrix4: function ( matrix4 ) {
  166. this.direction.add( this.origin ).applyMatrix4( matrix4 );
  167. this.origin.applyMatrix4( matrix4 );
  168. this.direction.sub( this.origin );
  169. return this;
  170. },
  171. equals: function ( ray ) {
  172. return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
  173. },
  174. clone: function () {
  175. return new THREE.Ray().copy( this );
  176. }
  177. };
粤ICP备19079148号