PageRenderTime 104ms CodeModel.GetById 40ms app.highlight 22ms RepoModel.GetById 38ms app.codeStats 0ms

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