/src/away3d/tools/utils/Ray.as

http://github.com/away3d/away3d-core-fp11 · ActionScript · 254 lines · 134 code · 42 blank · 78 comment · 16 complexity · 0542f813cbc5d4ea2760d617a7b9e16f MD5 · raw file

  1. package away3d.tools.utils
  2. {
  3. import flash.geom.Vector3D;
  4. public class Ray
  5. {
  6. private var _orig:Vector3D = new Vector3D(0.0, 0.0, 0.0);
  7. private var _dir:Vector3D = new Vector3D(0.0, 0.0, 0.0);
  8. private var _tu:Vector3D = new Vector3D(0.0, 0.0, 0.0);
  9. private var _tv:Vector3D = new Vector3D(0.0, 0.0, 0.0);
  10. private var _w:Vector3D = new Vector3D(0.0, 0.0, 0.0);
  11. private var _pn:Vector3D = new Vector3D(0.0, 0.0, 0.0);
  12. private var _npn:Vector3D = new Vector3D(0.0, 0.0, 0.0);
  13. private var _a:Number;
  14. private var _b:Number;
  15. private var _c:Number;
  16. private var _d:Number;
  17. function Ray()
  18. {
  19. }
  20. /**
  21. * Defines the origin point of the Ray object
  22. * @return Vector3D The origin point of the Ray object
  23. */
  24. public function set orig(o:Vector3D):void
  25. {
  26. _orig.x = o.x;
  27. _orig.y = o.y;
  28. _orig.z = o.z;
  29. }
  30. public function get orig():Vector3D
  31. {
  32. return _orig;
  33. }
  34. /**
  35. * Defines the directional vector of the Ray object
  36. * @return Vector3D The directional vector
  37. */
  38. public function set dir(n:Vector3D):void
  39. {
  40. _dir.x = n.x;
  41. _dir.y = n.y;
  42. _dir.z = n.z;
  43. }
  44. public function get dir():Vector3D
  45. {
  46. return _dir;
  47. }
  48. /**
  49. * Defines the directional normal of the Ray object
  50. * @return Vector3D The normal of the plane
  51. */
  52. public function get planeNormal():Vector3D
  53. {
  54. return _pn;
  55. }
  56. /**
  57. * Checks if a ray intersects a sphere.
  58. *@param pOrig Vector3D. The origin vector of the ray.
  59. *@param dir Vector3D. The normalized direction vector of the ray.
  60. *@param sPos Vector3D. The position of the sphere.
  61. *@param radius Number. The radius of the sphere.
  62. *
  63. * @return Boolean If the ray intersects the sphere
  64. */
  65. public function intersectsSphere(pOrig:Vector3D, dir:Vector3D, sPos:Vector3D, radius:Number):Boolean
  66. {
  67. return Boolean(hasSphereIntersection(pOrig, dir, sPos, radius) > 0);
  68. }
  69. /**
  70. * Returns a Vector3D where the ray intersects a sphere. Return null if the ray misses the sphere
  71. *
  72. *@param pOrig Vector3D. The origin of the ray.
  73. *@param dir Vector3D. The direction of the ray.
  74. *@param sPos Vector3D. The position of the sphere.
  75. *@param radius Number. The radius of the sphere.
  76. *@param bNearest [optional] Boolean. If the ray traverses the sphere and if true the returned hit is the nearest to ray origin. Default is true.
  77. *@param bNormal [optional] Boolean. If the returned vector is the normal of the hitpoint. Default is false.
  78. *
  79. * @return Vector3D The intersection vector3D or the normal vector3D of the hitpoint. Default is false.
  80. *
  81. * example of a ray triggered from mouse
  82. var pMouse:Vector3D = _view.unproject(_view.mouseX, _view.mouseY, 1);
  83. var cam:Vector3D = _view.camera.position;
  84. var dir:Vector3D = new Vector3D( pMouse.x-cam.x, pMouse.y-cam.y, pMouse.z-cam.z);
  85. dir.normalize();
  86. var spherePosition:Vector3D = new Vector3D(200, 200, 200);
  87. //hittest
  88. trace("Ray intersects sphere :"+ _ray.intersectsSphere(pMouse, dir, spherePosition, 500) );
  89. var sintersect:Vector3D = _ray.getRayToSphereIntersection(pMouse, dir, spherePosition, 500, true, false);
  90. if sintersect == null no hit, else sintersect = intersection vector3d or the normal of the intersection
  91. */
  92. public function getRayToSphereIntersection(pOrig:Vector3D, dir:Vector3D, sPos:Vector3D, radius:Number, bNearest:Boolean = true, bNormal:Boolean = false, outVector3D:Vector3D = null):Vector3D
  93. {
  94. _d = hasSphereIntersection(pOrig, dir, sPos, radius);
  95. // no intersection, ray misses sphere
  96. if (_d < 0)
  97. return null;
  98. _d = Math.sqrt(_d);
  99. var t:Number = (bNearest)? (-0.5)*(_b - _d)/_a : (-0.5)*(_b + _d)/_a;
  100. if (t == 0.0)
  101. return null;
  102. var result:Vector3D = outVector3D || new Vector3D(0.0, 0.0, 0.0);
  103. result.x = pOrig.x + (_pn.x*t);
  104. result.y = pOrig.y + (_pn.y*t);
  105. result.z = pOrig.z + (_pn.z*t);
  106. //todo, add dist return. var dist:Number = Math.sqrt(a)*t;
  107. if (bNormal) {
  108. _pn.x = (result.x - sPos.x)/radius;
  109. _pn.y = (result.y - sPos.y)/radius;
  110. _pn.z = (result.z - sPos.z)/radius;
  111. return _pn;
  112. }
  113. return result;
  114. }
  115. /**
  116. * Returns a Vector3D where the ray intersects a plane inside a triangle
  117. * Returns null if no hit is found.
  118. *
  119. *@param p0 Vector3D. The origin of the ray.
  120. *@param p1 Vector3D. The end of the ray.
  121. *@param v0 Vector3D. The first scenespace vertex of the face.
  122. *@param v1 Vector3D. The second scenespace vertex of the face.
  123. *@param v2 Vector3D. The third scenespace vertex of the face.
  124. *@param outVector3D Vector3D. Optional user defined Vector3D returned with result values
  125. *
  126. * example: fire a ray from camera position to 0,0,0 and test if it hits the triangle.
  127. view.camera.x = 100;
  128. view.camera.y = 100;
  129. view.camera.z = 500;
  130. var v0:Vector3D = new Vector3D(-200, 100, 60);
  131. var v1:Vector3D = new Vector3D(200, 100, 60);
  132. var v2:Vector3D = new Vector3D(0, -200, 60);
  133. var dest: Vector3D = new Vector3D(0, 0, 0);
  134. var intersect:Vector3D = _ray.getRayToTriangleIntersection(_view.camera.position, dest, v0, v1, v2 );
  135. trace("intersect ray: "+intersect);
  136. *
  137. * @return Vector3D The intersection point
  138. */
  139. public function getRayToTriangleIntersection(p0:Vector3D, p1:Vector3D, v0:Vector3D, v1:Vector3D, v2:Vector3D, outVector3D:Vector3D = null):Vector3D
  140. {
  141. _tu.x = v1.x - v0.x;
  142. _tu.y = v1.y - v0.y;
  143. _tu.z = v1.z - v0.z;
  144. _tv.x = v2.x - v0.x;
  145. _tv.y = v2.y - v0.y;
  146. _tv.z = v2.z - v0.z;
  147. _pn.x = _tu.y*_tv.z - _tu.z*_tv.y;
  148. _pn.y = _tu.z*_tv.x - _tu.x*_tv.z;
  149. _pn.z = _tu.x*_tv.y - _tu.y*_tv.x;
  150. if (_pn.length == 0)
  151. return null;
  152. _dir.x = p1.x - p0.x;
  153. _dir.y = p1.y - p0.y;
  154. _dir.z = p1.z - p0.z;
  155. _orig.x = p0.x - v0.x;
  156. _orig.y = p0.y - v0.y;
  157. _orig.z = p0.z - v0.z;
  158. _npn.x = -_pn.x;
  159. _npn.y = -_pn.y;
  160. _npn.z = -_pn.z;
  161. var a:Number = _npn.x*_orig.x + _npn.y*_orig.y + _npn.z*_orig.z;
  162. if (a == 0)
  163. return null;
  164. var b:Number = _pn.x*_dir.x + _pn.y*_dir.y + _pn.z*_dir.z;
  165. var r:Number = a/b;
  166. if (r < 0 || r > 1)
  167. return null;
  168. var result:Vector3D = outVector3D || new Vector3D(0.0, 0.0, 0.0);
  169. result.x = p0.x + (_dir.x*r);
  170. result.y = p0.y + (_dir.y*r);
  171. result.z = p0.z + (_dir.z*r);
  172. var uu:Number = _tu.x*_tu.x + _tu.y*_tu.y + _tu.z*_tu.z;
  173. var uv:Number = _tu.x*_tv.x + _tu.y*_tv.y + _tu.z*_tv.z;
  174. var vv:Number = _tv.x*_tv.x + _tv.y*_tv.y + _tv.z*_tv.z;
  175. _w.x = result.x - v0.x;
  176. _w.y = result.y - v0.y;
  177. _w.z = result.z - v0.z;
  178. var wu:Number = _w.x*_tu.x + _w.y*_tu.y + _w.z*_tu.z;
  179. var wv:Number = _w.x*_tv.x + _w.y*_tv.y + _w.z*_tv.z;
  180. var d:Number = uv*uv - uu*vv;
  181. var v:Number = (uv*wv - vv*wu)/d;
  182. if (v < 0 || v > 1)
  183. return null;
  184. var t:Number = (uv*wu - uu*wv)/d;
  185. if (t < 0 || (v + t) > 1.0)
  186. return null;
  187. return result;
  188. }
  189. private function hasSphereIntersection(pOrig:Vector3D, dir:Vector3D, sPos:Vector3D, radius:Number):Number
  190. {
  191. _pn.x = -dir.x;
  192. _pn.y = -dir.y;
  193. _pn.z = -dir.z;
  194. dir = _pn;
  195. _a = _pn.x*_pn.x + _pn.y*_pn.y + _pn.z*_pn.z;
  196. _b = _pn.x*(2*(pOrig.x - sPos.x)) + _pn.y*(2*(pOrig.y - sPos.y)) + _pn.z*(2*(pOrig.z - sPos.z));
  197. _c = sPos.x*sPos.x + sPos.y*sPos.y + sPos.z*sPos.z;
  198. _c += pOrig.x*pOrig.x + pOrig.y*pOrig.y + pOrig.z*pOrig.z;
  199. _c -= 2*(sPos.x*pOrig.x + sPos.y*pOrig.y + sPos.z*pOrig.z);
  200. _c -= radius*radius;
  201. return _b*_b + (-4.0)*_a*_c;
  202. }
  203. }
  204. }