商域无疆 (http://blog.csdn.net/omni360/)

本文遵循“署名-非商业用途-保持一致”创作公用协议

转载请保留此句:商域无疆 -  本博客专注于 敏捷开发及移动和物联设备研究:数据可视化、GOLANG、Html5、WEBGL、THREE.JS,否则,出自本博客的文章拒绝转载或再转载,谢谢合作。

俺也是刚開始学,好多地儿肯定不正确还请见谅.

下面代码是THREE.JS 源代码文件里Math/Ray.js文件的凝视.

很多其它更新在 : https://github.com/omni360/three.js.sourcecode/blob/master/Three.js

今天把Three.js的Ray类凝视完了,很重要的一个类.在场景中拾取对象,常常会用到这个类.

  1. // File:src/math/Ray.js
  2.  
  3. /**
  4. * @author bhouston / http://exocortex.com
  5. */
  6. /*
  7. ///Ray对象的构造函数.用来创建一个三维空间里的射线对象.Ray对象的功能函数採用
  8. ///定义构造的函数原型对象来实现,ray主要是用来进行碰撞检測,在选择场景中的对象时常常会用到,推断当前鼠标是否与对象重合用来选择对象.
  9. ///
  10. /// 使用方法: var origin = new Vector3(1,1,1),direction = new Vector3(9,9,9); var ray = new Ray(origin,direction);
  11. /// 创建一个原点为origin,方向为direction的射线.
  12. */
  13. ///<summary>Ray</summary>
  14. ///<param name ="origin" type="Vector3">射线的端点,Vector3对象</param>
  15. ///<param name ="direction" type="Vector3">射线的方向,Vector3对象</param>
  16. THREE.Ray = function ( origin, direction ) {
  17.  
  18. this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3();
  19. this.direction = ( direction !== undefined ) ?
  20.  
  21. direction : new THREE.Vector3();
  22.  
  23. };
  24.  
  25. /****************************************
  26. ****以下是Vector3对象提供的功能函数.
  27. ****************************************/
  28. THREE.Ray.prototype = {
  29.  
  30. constructor: THREE.Ray, //构造器,返回对创建此对象的Ray函数的引用
  31.  
  32. /*
  33. ///set方法用来从新设置射线的端点和方向(origin,direction).并返回新的射线.
  34. */
  35. ///<summary>set</summary>
  36. ///<param name ="origin" type="Vector3">x坐标</param>
  37. ///<param name ="direction" type="Vector3">y坐标</param>
  38. ///<returns type="Ray">返回新的射线</returns>
  39. set: function ( origin, direction ) {
  40.  
  41. this.origin.copy( origin );
  42. this.direction.copy( direction );
  43.  
  44. return this; //返回新的射线
  45.  
  46. },
  47.  
  48. /*
  49. ///copy方法用来复制射线的端点,方向,origin,direction坐标值.并返回新的坐标值的射线.
  50. */
  51. ///<summary>copy</summary>
  52. ///<param name ="ray" type="Ray">射线</param>
  53. ///<returns type="Ray">返回新坐标值的射线</returns>
  54. copy: function ( ray ) {
  55.  
  56. this.origin.copy( ray.origin );
  57. this.direction.copy( ray.direction );
  58.  
  59. return this; //返回新坐标值的射线
  60.  
  61. },
  62.  
  63. /*
  64. ///at方法将返回沿当前射线方向的从端点起长度为t的点.假设传入了optionalTarget參数,将结果保存到optionalTarget中.
  65. /// NOTE:optionalTarget是可选參数,假设没有设置,系统自己主动创建一个暂时Vector3对象
  66. */
  67. ///<summary>at</summary>
  68. ///<param name ="t" type="Number">数值,到端点的长度</param>
  69. ///<param name ="optionalTarget" type="Vector3">optionalTarget是可选參数,假设没有设置,系统自己主动创建一个暂时Vector3对象</param>
  70. ///<returns type="Ray">返回沿当前射线方向的从端点起长度为t的点/returns>
  71. at: function ( t, optionalTarget ) {
  72.  
  73. var result = optionalTarget || new THREE.Vector3();
  74.  
  75. return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); //将返回沿当前射线方向的从端点起长度为t的点
  76.  
  77. },
  78.  
  79. /*
  80. ///recast方法将调用at(t)方法返回沿当前射线方向的从端点起长度为t的点,并将范围的点设为端点.
  81. */
  82. ///<summary>recast</summary>
  83. ///<param name ="t" type="Number">数值,到端点的长度</param>
  84. ///<returns type="Ray">返回新端点的射线/returns>
  85. recast: function () {
  86.  
  87. var v1 = new THREE.Vector3();
  88.  
  89. return function ( t ) {
  90.  
  91. this.origin.copy( this.at( t, v1 ) ); //调用at(t)方法返回沿当前射线方向的从端点起长度为t的点,并将范围的点设为端点.
  92.  
  93. return this; //返回新端点的射线
  94.  
  95. };
  96.  
  97. }(),
  98.  
  99. /*
  100. ///closestPointToPoint方法将返回随意点point到射线上的垂足.假设传入了optionalTarget參数,将结果保存到optionalTarget中.
  101. /// NOTE:optionalTarget是可选參数,假设没有设置,系统自己主动创建一个暂时Vector3对象
  102. /// NOTE:注意closestPointToPoint()方法定义假设垂足不在射线上,返回原点.
  103. */
  104. ///<summary>closestPointToPoint</summary>
  105. ///<param name ="point" type="Vector3">随意点Vector3对象</param>
  106. ///<param name ="optionalTarget" type="Vector3">optionalTarget是可选參数,假设没有设置,系统自己主动创建一个暂时Vector3对象</param>
  107. ///<returns type="Ray">返回随意点point到射线上的垂足/returns>
  108. closestPointToPoint: function ( point, optionalTarget ) {
  109.  
  110. var result = optionalTarget || new THREE.Vector3();
  111. result.subVectors( point, this.origin );
  112. var directionDistance = result.dot( this.direction ); //调用dot方法返回两个向量的点积,并赋值给directionDistance.
  113.  
  114. if ( directionDistance < 0 ) { //假设directionDistance小于0,表示垂足不在射线上,
  115.  
  116. return result.copy( this.origin ); //返回原点
  117.  
  118. }
  119.  
  120. return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); //返回随意点point到射线上的垂足
  121.  
  122. },
  123.  
  124. /*
  125. ///distanceToPoint方法将返回随意点到该射线的距离.
  126. /// NOTE:注意distanceToPoint()方法定义假设传入的參数point在端点后面,返回端点到该点的距离.
  127. */
  128. ///<summary>distanceToPoint</summary>
  129. ///<param name ="point" type="Vector3">随意点Vector3对象</param>
  130. ///<returns type="Number">返回随意点point到射线的距离或到射线端点的距离./returns>
  131. distanceToPoint: function () {
  132.  
  133. var v1 = new THREE.Vector3();
  134.  
  135. return function ( point ) {
  136.  
  137. var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); //调用dot方法返回两个向量的点积,并赋值给directionDistance.
  138.  
  139. // point behind the ray
  140. // 推断端点是否在端点后面
  141.  
  142. if ( directionDistance < 0 ) { //假设directionDistance小于0,表示參数point在射线端点后面
  143.  
  144. return this.origin.distanceTo( point ); //返回端点到该点的距离
  145.  
  146. }
  147.  
  148. v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); //假设參数point在射线端点前面,
  149.  
  150. return v1.distanceTo( point ); //返回该点到射线的距离,即到垂足的距离.
  151.  
  152. };
  153.  
  154. }(),
  155.  
  156. /*
  157. ///distanceSqToSegment方法将返回有參数v0,v1组成的线段到当前射线的最小距离.可选參数optionalPointOnRay, optionalPointOnSegment,分别用来存储在射线上和在线段上的垂足.
  158. */
  159. ///<summary>distanceToPoint</summary>
  160. ///<param name ="v0" type="Vector3">随意点Vector3对象</param>
  161. ///<param name ="v1" type="Vector3">随意点Vector3对象</param>
  162. ///<param name ="optionalPointOnRay" type="Vector3">optionalPointOnRay是可选參数,假设没有设置,系统自己主动创建一个暂时Vector3对象,用来存储在射线上的垂足</param>
  163. ///<param name ="optionalPointOnSegment" type="Vector3">optionalPointOnSegment是可选參数,假设没有设置,系统自己主动创建一个暂时Vector3对象,用来存储在线段上的垂足</param>
  164. ///<returns type="Number">返回随意点point到射线的距离或到射线端点的距离./returns>
  165. distanceSqToSegment: function ( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
  166.  
  167. // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp
  168. // It returns the min distance between the ray and the segment
  169. // distanceSqToSegment()方法返回线段到当前射线的最小距离
  170. // defined by v0 and v1
  171. // 线段由v0,v1构成
  172. // It can also set two optional targets :
  173. // 可一传递两个可选參数optionalPointOnRay, optionalPointOnSegment
  174. // - The closest point on the ray
  175. // 參数optionalPointOnRay用来存储在射线上的垂足
  176. // - The closest point on the segment
  177. // 參数optionalPointOnSegment用来存储在线段上的垂足
  178.  
  179. var segCenter = v0.clone().add( v1 ).multiplyScalar( 0.5 ); //获得线段的中点
  180. var segDir = v1.clone().sub( v0 ).normalize(); //获得线段的单位向量,
  181. var segExtent = v0.distanceTo( v1 ) * 0.5; //线段的长度的一半?
  182. var diff = this.origin.clone().sub( segCenter ); //
  183. var a01 = - this.direction.dot( segDir );
  184. var b0 = diff.dot( this.direction );
  185. var b1 = - diff.dot( segDir );
  186. var c = diff.lengthSq();
  187. var det = Math.abs( 1 - a01 * a01 );
  188. var s0, s1, sqrDist, extDet;
  189.  
  190. if ( det >= 0 ) {
  191.  
  192. // The ray and segment are not parallel.
  193. // 线段和射线不平行
  194.  
  195. s0 = a01 * b1 - b0;
  196. s1 = a01 * b0 - b1;
  197. extDet = segExtent * det;
  198.  
  199. if ( s0 >= 0 ) {
  200.  
  201. if ( s1 >= - extDet ) {
  202.  
  203. if ( s1 <= extDet ) {
  204.  
  205. // region 0
  206. // Minimum at interior points of ray and segment.
  207.  
  208. var invDet = 1 / det;
  209. s0 *= invDet;
  210. s1 *= invDet;
  211. sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
  212.  
  213. } else {
  214.  
  215. // region 1
  216.  
  217. s1 = segExtent;
  218. s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
  219. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  220.  
  221. }
  222.  
  223. } else {
  224.  
  225. // region 5
  226.  
  227. s1 = - segExtent;
  228. s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
  229. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  230.  
  231. }
  232.  
  233. } else {
  234.  
  235. if ( s1 <= - extDet ) {
  236.  
  237. // region 4
  238.  
  239. s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
  240. s1 = ( s0 > 0 ) ?
  241.  
  242. - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
  243. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  244.  
  245. } else if ( s1 <= extDet ) {
  246.  
  247. // region 3
  248.  
  249. s0 = 0;
  250. s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
  251. sqrDist = s1 * ( s1 + 2 * b1 ) + c;
  252.  
  253. } else {
  254.  
  255. // region 2
  256.  
  257. s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
  258. s1 = ( s0 > 0 ) ?
  259.  
  260. segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
  261. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  262.  
  263. }
  264.  
  265. }
  266.  
  267. } else {
  268.  
  269. // Ray and segment are parallel.
  270. // 线段和射线平行
  271.  
  272. s1 = ( a01 > 0 ) ? - segExtent : segExtent;
  273. s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
  274. sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  275.  
  276. }
  277.  
  278. if ( optionalPointOnRay ) {
  279.  
  280. optionalPointOnRay.copy( this.direction.clone().multiplyScalar( s0 ).add( this.origin ) );
  281.  
  282. }
  283.  
  284. if ( optionalPointOnSegment ) {
  285.  
  286. optionalPointOnSegment.copy( segDir.clone().multiplyScalar( s1 ).add( segCenter ) );
  287.  
  288. }
  289.  
  290. return sqrDist; //返回最小长度.
  291.  
  292. },
  293.  
  294. /*
  295. ///isIntersectionSphere方法用来推断当前射线是否与參数sphere球体相交相交.
  296. /// NOTE:isIntersectionSphere方法要求Sphere球体对象,必须有radius和center属性,sphereGeometry无效
  297. */
  298. ///<summary>isIntersectionSphere</summary>
  299. ///<param name ="sphere" type="Sphere">Sphere球体对象,必须有radius和center属性,sphereGeometry无效</param>
  300. ///<returns type="Boolean">返回true 或者 false</returns>
  301. isIntersectionSphere: function ( sphere ) {
  302.  
  303. return this.distanceToPoint( sphere.center ) <= sphere.radius; //返回true 或者 false
  304.  
  305. },
  306.  
  307. /*
  308. ///intersectSphere方法用来推断当前射线是否与參数sphere球体相交,假设相交返回交点.假设不想交返回null
  309. /// NOTE:intersectSphere方法要求Sphere球体对象,必须有radius和center属性,sphereGeometry无效
  310. /// NOTE:intersectSphere方法常常常使用在鼠标拾取球体
  311. */
  312. ///<summary>intersectSphere</summary>
  313. ///<param name ="sphere" type="Sphere">Sphere球体对象,必须有radius和center属性,sphereGeometry无效</param>
  314. ///<param name ="optionalTarget" type="Vector3">optionalTarget是可选參数,假设没有设置,系统自己主动创建一个暂时Vector3对象,用来存储射线与球体的交点</param>
  315. ///<returns type="Boolean">假设相交返回交点.假设不想交返回null</returns>
  316. intersectSphere: function () {
  317.  
  318. // from http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-sphere-intersection/
  319.  
  320. var v1 = new THREE.Vector3();
  321.  
  322. return function ( sphere, optionalTarget ) {
  323.  
  324. v1.subVectors( sphere.center, this.origin );
  325.  
  326. var tca = v1.dot( this.direction );
  327.  
  328. var d2 = v1.dot( v1 ) - tca * tca;
  329.  
  330. var radius2 = sphere.radius * sphere.radius;
  331.  
  332. if ( d2 > radius2 ) return null; //假设不相交返回null
  333.  
  334. var thc = Math.sqrt( radius2 - d2 );
  335.  
  336. // t0 = first intersect point - entrance on front of sphere
  337. // t0射线与球体的第一个交点,从球体的前面进入
  338. var t0 = tca - thc;
  339.  
  340. // t1 = second intersect point - exit point on back of sphere
  341. // t1射线与球体的第二个交点,从球体的背面射出
  342. var t1 = tca + thc;
  343.  
  344. // test to see if both t0 and t1 are behind the ray - if so, return null
  345. // 假设t0,t1都小于0,说明球体在射线端点的后面,返回null.
  346. if ( t0 < 0 && t1 < 0 ) return null;
  347.  
  348. // test to see if t0 is behind the ray:
  349. // 假设t0射线与球体的第一个交点在射线端点的后面,
  350. // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
  351. // 说明射线端点在球体的内部,所以返回射线与球体表面的交点是t1,从球体的背面射出的交点.
  352. // in order to always return an intersect point that is in front of the ray.
  353. // 普通情况下总是返回一个交点,这里返回的是从球体的背面射出的交点.
  354. if ( t0 < 0 ) return this.at( t1, optionalTarget );
  355.  
  356. // else t0 is in front of the ray, so return the first collision point scaled by t0
  357. // 还有一种情况,球体在射线的前面,返回t0,射线从球体体正面射入的交点.
  358. return this.at( t0, optionalTarget );
  359.  
  360. }
  361.  
  362. }(),
  363.  
  364. /*
  365. ///isIntersectionPlane方法用来推断当前射线是否与參数Plane平面相交,常常常使用来推断用户是否选中了场景中的平面.
  366. /// NOTE:isIntersectionPlane方法要求Plane平面对象,必须有normal属性
  367. */
  368. ///<summary>isIntersectionPlane</summary>
  369. ///<param name ="plane" type="Plane">Plane平面对象,必须有normal属性</param>
  370. ///<returns type="Boolean">返回true 或者 false</returns>
  371. isIntersectionPlane: function ( plane ) {
  372.  
  373. // check if the ray lies on the plane first
  374. // 检查射线原点是否在Plane平面上,
  375.  
  376. var distToPoint = plane.distanceToPoint( this.origin ); //获得平面到射线原点(就是鼠标所在位置)的距离
  377.  
  378. if ( distToPoint === 0 ) { //假设在平面上
  379.  
  380. return true; //返回true
  381.  
  382. }
  383.  
  384. var denominator = plane.normal.dot( this.direction ); //调用normal.dot方法获得射线到平面法线的单位向量,并赋值给denominator
  385.  
  386. if ( denominator * distToPoint < 0 ) { //原点到平面的距离乘以单位向量小于0,说明平面在射线的前面.
  387.  
  388. return true; //返回true
  389.  
  390. }
  391.  
  392. // ray origin is behind the plane (and is pointing behind it)
  393. // 射线原点在Plane平面的后面,
  394.  
  395. return false; //返回false
  396.  
  397. },
  398.  
  399. /*
  400. ///distanceToPlane方法将返回參数plane平面到当前射线的最小距离.
  401. /// NOTE:distanceToPlane方法要求Plane平面对象,必须有normal属性
  402. */
  403. ///<summary>distanceToPlane</summary>
  404. ///<param name ="plane" type="Plane">Plane平面对象,必须有normal属性</param>
  405. ///<returns type="Number">返回随意点point到射线的距离或到射线端点的距离t,假设射线在当前平面上返回0.射线与平面永不相交或其它未知定义返回null</returns>
  406. distanceToPlane: function ( plane ) {
  407.  
  408. var denominator = plane.normal.dot( this.direction );
  409. if ( denominator == 0 ) {
  410.  
  411. // line is coplanar, return origin
  412. // 射线和平面共面,返回原点0.
  413. if ( plane.distanceToPoint( this.origin ) == 0 ) {
  414.  
  415. return 0; //假设射线在当前平面上返回0
  416.  
  417. }
  418.  
  419. // Null is preferable to undefined since undefined means.... it is undefined
  420. // 其它未知定义返回null
  421.  
  422. return null; //其它未知定义返回null
  423.  
  424. }
  425.  
  426. var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
  427.  
  428. // Return if the ray never intersects the plane
  429. // 射线与平面永不相交返回null
  430.  
  431. return t >= 0 ?
  432.  
  433. t : null; //射线与平面永不相交返回null,或者返回距离t
  434.  
  435. },
  436.  
  437. /*
  438. ///intersectPlane方法用来推断当前射线是否与參数plane平面相交,假设相交返回交点.假设不想交返回null
  439. /// NOTE:intersectSphere方法要求plane平面对象,必须有normal属性
  440. /// NOTE:intersectSphere方法常常常使用在鼠标拾取plane平面
  441. */
  442. ///<summary>intersectPlane</summary>
  443. ///<param name ="plane" type="Plane">Plane平面对象,必须有normal属性</param>
  444. ///<param name ="optionalTarget" type="Vector3">optionalTarget是可选參数,假设没有设置,系统自己主动创建一个暂时Vector3对象,用来存储射线与平面的交点</param>
  445. ///<returns type="Boolean">假设相交返回交点.假设射线与平面永不相交或其它未知定义返回null</returns>
  446. intersectPlane: function ( plane, optionalTarget ) {
  447.  
  448. var t = this.distanceToPlane( plane ); //调用distanceToPlane方法将返回參数plane平面到当前射线的最小距离
  449.  
  450. if ( t === null ) { //假设射线与平面永不相交或其它未知定义返回null
  451.  
  452. return null; //返回null
  453. }
  454.  
  455. return this.at( t, optionalTarget ); //假设相交返回交点
  456.  
  457. },
  458.  
  459. /*
  460. ///isIntersectionBox方法用来推断当前射线是否与參数Box立方体相交,常常常使用来推断用户是否选中了场景中的Box立方体对象.
  461. /// NOTE:isIntersectionPlane方法要求Box立方体对象,必须有min,max属性
  462. */
  463. ///<summary>isIntersectionBox</summary>
  464. ///<param name ="box" type="Box3">Box立方体对象,必须有min,max属性</param>
  465. ///<returns type="Boolean">返回true 或者 false</returns>
  466. isIntersectionBox: function () {
  467.  
  468. var v = new THREE.Vector3();
  469.  
  470. return function ( box ) {
  471.  
  472. return this.intersectBox( box, v ) !== null; //调用intersectBox()方法,推断是否不等于null,返回true 或者 false
  473.  
  474. };
  475.  
  476. }(),
  477.  
  478. /*
  479. ///intersectBox方法用来推断当前射线是否与參数Box立方体相交,假设相交返回交点.假设不想交返回null
  480. /// NOTE:intersectBox方法要求Box立方体对象,必须有min,max属性
  481. /// NOTE:intersectBox方法常常常使用在鼠标拾取Box立方体
  482. */
  483. ///<summary>intersectBox</summary>
  484. ///<param name ="box" type="Box3">Box立方体对象,必须有min,max属性</param>
  485. ///<param name ="optionalTarget" type="Vector3">optionalTarget是可选參数,假设没有设置,系统自己主动创建一个暂时Vector3对象,用来存储射线与立方体的交点</param>
  486. ///<returns type="Boolean">假设相交返回交点.假设射线与Box立方体永不相交或其它未知定义返回null</returns>
  487. intersectBox: function ( box , optionalTarget ) {
  488.  
  489. // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/
  490.  
  491. var tmin,tmax,tymin,tymax,tzmin,tzmax;
  492.  
  493. var invdirx = 1 / this.direction.x,
  494. invdiry = 1 / this.direction.y,
  495. invdirz = 1 / this.direction.z;
  496.  
  497. var origin = this.origin;
  498. //以下的这些是推断射线的原点在立方体的前后左右,还是立方体内,还是永不相交.假设射线原点在立方体后面或者不相交,返回null
  499. if ( invdirx >= 0 ) {
  500.  
  501. tmin = ( box.min.x - origin.x ) * invdirx;
  502. tmax = ( box.max.x - origin.x ) * invdirx;
  503.  
  504. } else {
  505.  
  506. tmin = ( box.max.x - origin.x ) * invdirx;
  507. tmax = ( box.min.x - origin.x ) * invdirx;
  508. }
  509.  
  510. if ( invdiry >= 0 ) {
  511.  
  512. tymin = ( box.min.y - origin.y ) * invdiry;
  513. tymax = ( box.max.y - origin.y ) * invdiry;
  514.  
  515. } else {
  516.  
  517. tymin = ( box.max.y - origin.y ) * invdiry;
  518. tymax = ( box.min.y - origin.y ) * invdiry;
  519. }
  520.  
  521. if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
  522.  
  523. // These lines also handle the case where tmin or tmax is NaN
  524. // (result of 0 * Infinity). x !== x returns true if x is NaN
  525.  
  526. if ( tymin > tmin || tmin !== tmin ) tmin = tymin;
  527.  
  528. if ( tymax < tmax || tmax !== tmax ) tmax = tymax;
  529.  
  530. if ( invdirz >= 0 ) {
  531.  
  532. tzmin = ( box.min.z - origin.z ) * invdirz;
  533. tzmax = ( box.max.z - origin.z ) * invdirz;
  534.  
  535. } else {
  536.  
  537. tzmin = ( box.max.z - origin.z ) * invdirz;
  538. tzmax = ( box.min.z - origin.z ) * invdirz;
  539. }
  540.  
  541. if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
  542.  
  543. if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
  544.  
  545. if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
  546.  
  547. //return point closest to the ray (positive side)
  548. //返回射线到立方体的垂足(正面的).
  549.  
  550. if ( tmax < 0 ) return null;
  551.  
  552. return this.at( tmin >= 0 ?
  553.  
  554. tmin : tmax, optionalTarget ); //返回交点并设置给可选參数optionalTarget
  555.  
  556. },
  557.  
  558. /*
  559. ///intersectTriangle方法用来推断当前射线是否与參数a,b,c组成的Triangle三角形对象相交,假设相交返回交点.假设不想交返回null
  560. /// NOTE:intersectTriangle方法要求Box立方体对象,必须有min,max属性
  561. /// NOTE:intersectTriangle方法常常常使用在鼠标拾取Triangle三角形
  562. /// NOTE:能够參考博客http://www.cnblogs.com/graphics/archive/2010/08/09/1795348.html
  563. */
  564. ///<summary>intersectTriangle</summary>
  565. ///<param name ="a" type="Vector3">Triangle三角形的角点a</param>
  566. ///<param name ="b" type="Vector3">Triangle三角形的角点b</param>
  567. ///<param name ="c" type="Vector3">Triangle三角形的角点c</param>
  568. ///<param name ="backfaceCulling" type="Boolean">true 或者 false,用来表示是否选择背面</param>
  569. ///<param name ="optionalTarget" type="Vector3">optionalTarget是可选參数,假设没有设置,系统自己主动创建一个暂时Vector3对象,用来存储射线与立方体的交点</param>
  570. ///<returns type="Boolean">假设相交返回交点.假设射线与Triangle三角形永不相交或其它未知定义返回null</returns>
  571. intersectTriangle: function () {
  572.  
  573. // Compute the offset origin, edges, and normal.
  574. var diff = new THREE.Vector3();
  575. var edge1 = new THREE.Vector3();
  576. var edge2 = new THREE.Vector3();
  577. var normal = new THREE.Vector3();
  578.  
  579. return function ( a, b, c, backfaceCulling, optionalTarget ) {
  580.  
  581. // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp
  582.  
  583. edge1.subVectors( b, a );
  584. edge2.subVectors( c, a );
  585. normal.crossVectors( edge1, edge2 );
  586.  
  587. // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
  588. // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
  589. // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
  590. // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
  591. // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
  592. var DdN = this.direction.dot( normal );
  593. var sign;
  594.  
  595. //以下的这些是推断射线的原点在Triangle三角形的前后左右,还是立方体内,还是永不相交.假设射线原点在立方体后面或者不相交,返回null
  596. if ( DdN > 0 ) {
  597.  
  598. if ( backfaceCulling ) return null;
  599. sign = 1;
  600.  
  601. } else if ( DdN < 0 ) {
  602.  
  603. sign = - 1;
  604. DdN = - DdN;
  605.  
  606. } else {
  607.  
  608. return null;
  609.  
  610. }
  611.  
  612. diff.subVectors( this.origin, a );
  613. var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );
  614.  
  615. // b1 < 0, no intersection
  616. // b1 <0 ,不相交
  617. if ( DdQxE2 < 0 ) {
  618.  
  619. return null;
  620.  
  621. }
  622.  
  623. var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );
  624.  
  625. // b2 < 0, no intersection
  626. // b2 <0 ,不相交
  627. if ( DdE1xQ < 0 ) {
  628.  
  629. return null;
  630.  
  631. }
  632.  
  633. // b1+b2 > 1, no intersection
  634. // b1+b2 > 1 ,不相交
  635. if ( DdQxE2 + DdE1xQ > DdN ) {
  636.  
  637. return null;
  638.  
  639. }
  640.  
  641. // Line intersects triangle, check if ray does.
  642. // 射线与三角形相交
  643. var QdN = - sign * diff.dot( normal );
  644.  
  645. // t < 0, no intersection
  646. // t < 0, 不相交
  647. if ( QdN < 0 ) {
  648.  
  649. return null;
  650.  
  651. }
  652.  
  653. // Ray intersects triangle.
  654. // 射线与三角形相交.
  655. return this.at( QdN / DdN, optionalTarget ); //返回交点.
  656.  
  657. };
  658.  
  659. }(),
  660.  
  661. /*
  662. ///applyMatrix4方法通过传递參数matrix4(旋转,缩放,移动等变换矩阵)对当前射线对象的原点及方向矢量,应用变换.
  663. */
  664. ///<summary>applyMatrix4</summary>
  665. ///<param name ="matrix4" type="Matrix4">(旋转,缩放,移动等变换矩阵</param>
  666. ///<returns type="Boolean">返回变换后的射线对象.</returns>
  667. applyMatrix4: function ( matrix4 ) {
  668.  
  669. this.direction.add( this.origin ).applyMatrix4( matrix4 ); //对射线的方向矢量应用变换
  670. this.origin.applyMatrix4( matrix4 ); //对射线的原点应用变换
  671. this.direction.sub( this.origin );
  672. this.direction.normalize();
  673.  
  674. return this; //返回变换后的射线对象
  675. },
  676.  
  677. /*equals方法
  678. ///equals方法相当于比較运算符===,将当前射线和參数ray中的(origin,direction)值进行对照,返回bool型值.
  679. */
  680. ///<summary>equals</summary>
  681. ///<param name ="ray" type="Ray">射线(origin,direction)</param>
  682. ///<returns type="bool">返回true or false</returns>
  683. equals: function ( ray ) {
  684.  
  685. return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); //返回true or false
  686.  
  687. },
  688.  
  689. /*clone方法
  690. ///clone方法克隆一个射线对象.
  691. */
  692. ///<summary>clone</summary>
  693. ///<returns type="Ray">返回射线对象</returns>
  694. clone: function () {
  695.  
  696. return new THREE.Ray().copy( this ); //返回射线对象
  697.  
  698. }
  699.  
  700. };

商域无疆 (http://blog.csdn.net/omni360/)

本文遵循“署名-非商业用途-保持一致”创作公用协议

转载请保留此句:商域无疆 -  本博客专注于 敏捷开发及移动和物联设备研究:数据可视化、GOLANG、Html5、WEBGL、THREE.JS,否则,出自本博客的文章拒绝转载或再转载,谢谢合作。

下面代码是THREE.JS 源代码文件里Math/Ray.js文件的凝视.

很多其它更新在 : https://github.com/omni360/three.js.sourcecode/blob/master/Three.js

版权声明:本文博主原创文章,博客,未经同意不得转载。

three.js 来源目光(十三)Math/Ray.js的更多相关文章

  1. three.js 源代码凝视(十四)Math/Sphere.js

    商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发 ...

  2. three.js 源代码凝视(十)Math/Line3.js

    商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发 ...

  3. three.js 源代码凝视(七)Math/Euler.js

    商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发 ...

  4. three.js 源代码凝视(十六)Math/Frustum.js

    商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发 ...

  5. three.js 源代码凝视(九)Math/Matrix4.js

    商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发 ...

  6. three.js 源代码凝视(十五)Math/Plane.js

    商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发 ...

  7. Dynamic CRM 2013学习笔记(二十三)CRM JS智能提示(CRM 相关的方法、属性以及页面字段),及发布前调试

    我们知道在CRM的js文件里引用XrmPageTemplate.js后,就可以实现智能提示,但每个js文件都引用太麻烦了,其实可以利用vs的功能让每个js文件自动实现智能提示CRM的js: 另外,我们 ...

  8. js基础到精通全面教程--JS教程

    适合阅读范围:对JavaScript一无所知-离精通只差一步之遥的人 基础知识:HTML JavaScript就这么回事1:基础知识 1 创建脚本块 1: <script language=”J ...

  9. Gremlins.js – 模拟用户随机操作的 JS 测试库

    Gremlins.js 是基于 JavaScript 编写的 Monkey 测试库,支持 Node.js 平台和浏览器中使用.Gremlins.js 随机模拟用户操作:单击窗口中的任意位置,在表格中输 ...

随机推荐

  1. Blend4精选案例图解教程(二):找张图片玩特效

    原文:Blend4精选案例图解教程(二):找张图片玩特效 Blend中的特效给了我们在处理资源时更多的想象空间,合理地运用特效往往会得到梦幻般效果,本次教程展示对图片应用特效的常规操作,当然特效不仅限 ...

  2. [转载] RaspberryPi B+ WiringPi 引脚对应图

    Pin Numbering - Raspberry Pi Model B+ Numbering Scheme Expansion Header J8 Pinout (40-pin Header) Ad ...

  3. easyui动力头 &amp;&amp; 动态加入tabs

    今天,在实现了业务时的,我们需要根据后台操作,以产生多个数据tab页,而且每一个tab页表格根据需要动态生成的标题数据. 返回后台数据格例如,下面的公式: 实现方法例如以下: //$("#c ...

  4. 四个漂亮CSS样式表

    1. 单像素的边框CSS表格 这是一个非常所用的表格风格. 源码: <!-- CSS goes in the document HEAD or added to your external st ...

  5. MySQL与逻辑模块

    启动MySQL 1.初始化模块运行&&存储引擎初始化运行 2.1中运行完毕后 ---->连接管理模块接手 3.连接管理模块启动处理client连接请求的监听程序(tcp/ip 网 ...

  6. c++11多线程简介

    C++11开始支持多线程编程,之前多线程编程都需要系统的支持,在不同的系统下创建线程需要不同的API如pthread_create(),Createthread(),beginthread()等,使用 ...

  7. Android访问服务器(TOMCAT)乱码引发的问题

    1.浏览器往服务器发送的请求主要可分为2种:get.post:delete.head等不赘述. GET方式: 从浏览器上直接敲地址,最大特点就是参数直接跟在地址后面. POST方式:表单提交等. 2. ...

  8. ExtJS4 根据分配不同的树形菜单在不同的角色登录后

    继续我的最后.建立cookie后,带他们出去 var userName = Ext.util.Cookies.get('userName'); var userAuthority = Ext.util ...

  9. 求Sn=a+aa+aaa+…+aa…aaa(有n个a)…

    时间限制: 1 Sec  内存限制: 128 MB 提交: 352  解决: 174 [提交][状态][讨论版] 题目描述 求Sn=a+aa+aaa+-+aa-aaa(有n个a)之值,其中a是一个数字 ...

  10. Java经典23结构模型的设计模式(三)------附加代理模式、适配器型号、Facade模式的差异

    本文介绍了7样的结构模型中的其余2种:轻量级.代理模式. 一.享元模式FlyWeight 享元模式比較简单且重要,在非常多场合都被用到.仅仅只是封装起来了用户看不到.其概念:运用共享内存技术最大限度的 ...