Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Ray class #71

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/away3d/tools/utils/Ray.as
Original file line number Diff line number Diff line change
@@ -1 +1 @@
package away3d.tools.utils{ import flash.geom.Vector3D; public class Ray{ private var _orig:Vector3D = new Vector3D(); private var _dir:Vector3D = new Vector3D(); private var _intersect:Vector3D = new Vector3D(); private var _tu:Vector3D = new Vector3D(); private var _tv:Vector3D = new Vector3D(); private var _w:Vector3D = new Vector3D(); private var _pn:Vector3D = new Vector3D(); private var _npn:Vector3D = new Vector3D(); private var _a:Number; private var _b:Number; private var _c:Number; private var _d:Number; function Ray(){} /** * Defines the origin point of the Ray object * @return Vector3D The origin point of the Ray object */ public function set orig(o:Vector3D):void { _orig.x = o.x; _orig.y = o.y; _orig.z = o.z; } public function get orig():Vector3D { return _orig; } /** * Defines the directional vector of the Ray object * @return Vector3D The directional vector */ public function set dir(n:Vector3D):void { _dir.x = n.x; _dir.y = n.y; _dir.z = n.z; } public function get dir():Vector3D { return _dir; } /** * Defines the directional normal of the Ray object * @return Vector3D The normal of the plane */ public function get planeNormal():Vector3D { return _pn; } /** * Checks if ray intersects a sphere. dir en orig setters must be defined first. *@param sPos Vector3D. The position of the sphere. *@param radius Number. The radius of the sphere. * * @return Boolean If the ray intersects the sphere */ public function intersectBoundingRadius(pOrig:Vector3D, dir:Vector3D, sPos:Vector3D, radius:Number):Boolean { return Boolean( isIntersectSphere(pOrig, dir, sPos, radius) > 0); } /** * Returns a Vector3D where the ray intersects a sphere. Return null if the ray misses the sphere * *@param pOrig Vector3D. The origin of the ray. *@param dir Vector3D. The direction of the ray. *@param sPos Vector3D. The position of the sphere. *@param radius Number. The radius of the sphere. *@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. *@param bNormal [optional] Boolean. If the returned vector is the normal of the hitpoint. Default is false. * * @return Vector3D The intersection point or the normal of the hitpoint if normal is true * example of a ray triggered from mouse var pMouse:Vector3D = _view.unproject(_view.mouseX, _view.mouseY); var cam:Vector3D = _view.camera.position; var dir:Vector3D = new Vector3D( pMouse.x-cam.x, pMouse.y-cam.y, pMouse.z-cam.z); dir.normalize(); var spherePosition:Vector3D = new Vector3D(200, 200, 200); //hittest trace("ray hits? :"+ _ray.intersectBoundingRadius(pMouse, dir, spherePosition, 500) ); var sintersect:Vector3D = _ray.getIntersectSphere(pMouse, dir, spherePosition, 500, true, false); if sintersect == null no hit, else sintersect = intersection vector3d or the normal of the intersection */ public function getIntersectSphere(pOrig:Vector3D, dir:Vector3D, sPos:Vector3D, radius:Number, bNearest:Boolean = true, bNormal:Boolean = false):Vector3D { _d = isIntersectSphere(pOrig, dir, sPos, radius); // no intersection, ray misses sphere if (_d < 0) return null; _d = Math.sqrt(_d); var t:Number = (bNearest)? (-0.5)*(_b-_d)/_a : (-0.5)*(_b+_d)/_a; if (t == 0.0) return null; _intersect.x = pOrig.x + (_pn.x* t); _intersect.y = pOrig.y + (_pn.y* t); _intersect.z = pOrig.z + (_pn.z* t); //todo, add dist return. var dist:Number = Math.sqrt(a)*t; if(bNormal){ _pn.x = (_intersect.x - sPos.x) / radius; _pn.y = (_intersect.y - sPos.y) / radius; _pn.z = (_intersect.z - sPos.z) / radius; return _pn; } return _intersect; } /** * Returns a Vector3D where the ray intersects a plane inside a triangle * Returns null if no hit is found. * @return Vector3D The intersection point */ public function getIntersect(p0:Vector3D, p1:Vector3D, v0:Vector3D, v1:Vector3D, v2:Vector3D):Vector3D { _tu.x = v1.x - v0.x; _tu.y = v1.y - v0.y; _tu.z = v1.z - v0.z; _tv.x = v2.x - v0.x; _tv.y = v2.y - v0.y; _tv.z = v2.z - v0.z; _pn.x = _tu.y*_tv.z - _tu.z*_tv.y; _pn.y = _tu.z*_tv.x - _tu.x*_tv.z; _pn.z = _tu.x*_tv.y - _tu.y*_tv.x; if (_pn.length == 0) return null; _dir.x = p1.x - p0.x; _dir.y = p1.y - p0.y; _dir.z = p1.z - p0.z; _orig.x = p0.x - v0.x; _orig.y = p0.y - v0.y; _orig.z = p0.z - v0.z; _npn.x = -_pn.x; _npn.y = -_pn.y; _npn.z = -_pn.z; var a:Number = _npn.x * _orig.x + _npn.y * _orig.y + _npn.z * _orig.z; if (a ==0) return null; var b:Number = _pn.x * _dir.x + _pn.y * _dir.y + _pn.z * _dir.z; var r:Number = a / b; if (r < 0 || r > 1) return null; _intersect.x = p0.x+(_dir.x*r); _intersect.y = p0.y+(_dir.y*r); _intersect.z = p0.z+(_dir.z*r); var uu:Number = _tu.x * _tu.x + _tu.y * _tu.y + _tu.z * _tu.z; var uv:Number = _tu.x * _tv.x + _tu.y * _tv.y + _tu.z * _tv.z; var vv:Number = _tv.x * _tv.x + _tv.y * _tv.y + _tv.z * _tv.z; _w.x = _intersect.x - v0.x; _w.y = _intersect.y - v0.y; _w.z = _intersect.z - v0.z; var wu:Number = _w.x * _tu.x + _w.y * _tu.y + _w.z * _tu.z; var wv:Number = _w.x * _tv.x + _w.y * _tv.y + _w.z * _tv.z; var d:Number = uv * uv - uu * vv; var v:Number = (uv * wv - vv * wu) / d; if (v < 0 || v > 1) return null; var t:Number = (uv * wu - uu * wv) / d; if (t < 0 || (v + t) > 1.0) return null; return _intersect; } private function isIntersectSphere(pOrig:Vector3D, dir:Vector3D, sPos:Vector3D, radius:Number):Number { _pn.x = -dir.x; _pn.y = -dir.y; _pn.z = -dir.z; dir = _pn; _a = _pn.x * _pn.x + _pn.y * _pn.y + _pn.z * _pn.z; _b = _pn.x * (2 * (pOrig.x - sPos.x)) + _pn.y * (2 * (pOrig.y - sPos.y)) + _pn.z * (2 * (pOrig.z - sPos.z)); _c = sPos.x * sPos.x + sPos.y * sPos.y + sPos.z * sPos.z; _c += pOrig.x * pOrig.x + pOrig.y * pOrig.y + pOrig.z * pOrig.z; _c -= 2 * (sPos.x * pOrig.x + sPos.y * pOrig.y + sPos.z * pOrig.z); _c -= radius * radius; return _b*_b + (-4.0)*_a*_c; } }}
package away3d.tools.utils{ import flash.geom.Vector3D; public class Ray{ private var _orig:Vector3D = new Vector3D(); private var _dir:Vector3D = new Vector3D(); private var _intersect:Vector3D = new Vector3D(); private var _tu:Vector3D = new Vector3D(); private var _tv:Vector3D = new Vector3D(); private var _w:Vector3D = new Vector3D(); private var _pn:Vector3D = new Vector3D(); private var _npn:Vector3D = new Vector3D(); private var _a:Number; private var _b:Number; private var _c:Number; private var _d:Number; function Ray(){} /** * Defines the origin point of the Ray object * @return Vector3D The origin point of the Ray object */ public function set orig(o:Vector3D):void { _orig.x = o.x; _orig.y = o.y; _orig.z = o.z; } public function get orig():Vector3D { return _orig; } /** * Defines the directional vector of the Ray object * @return Vector3D The directional vector */ public function set dir(n:Vector3D):void { _dir.x = n.x; _dir.y = n.y; _dir.z = n.z; } public function get dir():Vector3D { return _dir; } /** * Defines the directional normal of the Ray object * @return Vector3D The normal of the plane */ public function get planeNormal():Vector3D { return _pn; } /** * Checks if a ray intersects a sphere. *@param pOrig Vector3D. The origin vector of the ray. *@param dir Vector3D. The normalized direction vector of the ray. *@param sPos Vector3D. The position of the sphere. *@param radius Number. The radius of the sphere. * * @return Boolean If the ray intersects the sphere */ public function intersectsSphere(pOrig:Vector3D, dir:Vector3D, sPos:Vector3D, radius:Number):Boolean { return Boolean( hasSphereIntersection(pOrig, dir, sPos, radius) > 0); } /** * Returns a Vector3D where the ray intersects a sphere. Return null if the ray misses the sphere * *@param pOrig Vector3D. The origin of the ray. *@param dir Vector3D. The direction of the ray. *@param sPos Vector3D. The position of the sphere. *@param radius Number. The radius of the sphere. *@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. *@param bNormal [optional] Boolean. If the returned vector is the normal of the hitpoint. Default is false. * * @return Vector3D The intersection vector3D or the normal vector3D of the hitpoint. Default is false. * * example of a ray triggered from mouse var pMouse:Vector3D = _view.unproject(_view.mouseX, _view.mouseY); var cam:Vector3D = _view.camera.position; var dir:Vector3D = new Vector3D( pMouse.x-cam.x, pMouse.y-cam.y, pMouse.z-cam.z); dir.normalize(); var spherePosition:Vector3D = new Vector3D(200, 200, 200); //hittest trace("Ray intersects sphere :"+ _ray.intersectsSphere(pMouse, dir, spherePosition, 500) ); var sintersect:Vector3D = _ray.getRayToSphereIntersection(pMouse, dir, spherePosition, 500, true, false); if sintersect == null no hit, else sintersect = intersection vector3d or the normal of the intersection */ public function getRayToSphereIntersection(pOrig:Vector3D, dir:Vector3D, sPos:Vector3D, radius:Number, bNearest:Boolean = true, bNormal:Boolean = false):Vector3D { _d = hasSphereIntersection(pOrig, dir, sPos, radius); // no intersection, ray misses sphere if (_d < 0) return null; _d = Math.sqrt(_d); var t:Number = (bNearest)? (-0.5)*(_b-_d)/_a : (-0.5)*(_b+_d)/_a; if (t == 0.0) return null; _intersect.x = pOrig.x + (_pn.x* t); _intersect.y = pOrig.y + (_pn.y* t); _intersect.z = pOrig.z + (_pn.z* t); //todo, add dist return. var dist:Number = Math.sqrt(a)*t; if(bNormal){ _pn.x = (_intersect.x - sPos.x) / radius; _pn.y = (_intersect.y - sPos.y) / radius; _pn.z = (_intersect.z - sPos.z) / radius; return _pn; } return _intersect; } /** * Returns a Vector3D where the ray intersects a plane inside a triangle * Returns null if no hit is found. * *@param p0 Vector3D. The origin of the ray. *@param p1 Vector3D. The end of the ray. *@param v0 Vector3D. The first scenespace vertex of the face. *@param v1 Vector3D. The second scenespace vertex of the face. *@param v2 Vector3D. The third scenespace vertex of the face. * * example: fire a ray from camera position to 0,0,0 and test if it hits the triangle. view.camera.x = 100; view.camera.y = 100; view.camera.z = 500; var v0:Vector3D = new Vector3D(-200, 100, 60); var v1:Vector3D = new Vector3D(200, 100, 60); var v2:Vector3D = new Vector3D(0, -200, 60); var dest: Vector3D = new Vector3D(0, 0, 0); var intersect:Vector3D = _ray.getRayToTriangleIntersection(_view.camera.position, dest, v0, v1, v2 ); trace("intersect ray: "+intersect); * * @return Vector3D The intersection point */ public function getRayToTriangleIntersection(p0:Vector3D, p1:Vector3D, v0:Vector3D, v1:Vector3D, v2:Vector3D):Vector3D { _tu.x = v1.x - v0.x; _tu.y = v1.y - v0.y; _tu.z = v1.z - v0.z; _tv.x = v2.x - v0.x; _tv.y = v2.y - v0.y; _tv.z = v2.z - v0.z; _pn.x = _tu.y*_tv.z - _tu.z*_tv.y; _pn.y = _tu.z*_tv.x - _tu.x*_tv.z; _pn.z = _tu.x*_tv.y - _tu.y*_tv.x; if (_pn.length == 0) return null; _dir.x = p1.x - p0.x; _dir.y = p1.y - p0.y; _dir.z = p1.z - p0.z; _orig.x = p0.x - v0.x; _orig.y = p0.y - v0.y; _orig.z = p0.z - v0.z; _npn.x = -_pn.x; _npn.y = -_pn.y; _npn.z = -_pn.z; var a:Number = _npn.x * _orig.x + _npn.y * _orig.y + _npn.z * _orig.z; if (a ==0) return null; var b:Number = _pn.x * _dir.x + _pn.y * _dir.y + _pn.z * _dir.z; var r:Number = a / b; if (r < 0 || r > 1) return null; _intersect.x = p0.x+(_dir.x*r); _intersect.y = p0.y+(_dir.y*r); _intersect.z = p0.z+(_dir.z*r); var uu:Number = _tu.x * _tu.x + _tu.y * _tu.y + _tu.z * _tu.z; var uv:Number = _tu.x * _tv.x + _tu.y * _tv.y + _tu.z * _tv.z; var vv:Number = _tv.x * _tv.x + _tv.y * _tv.y + _tv.z * _tv.z; _w.x = _intersect.x - v0.x; _w.y = _intersect.y - v0.y; _w.z = _intersect.z - v0.z; var wu:Number = _w.x * _tu.x + _w.y * _tu.y + _w.z * _tu.z; var wv:Number = _w.x * _tv.x + _w.y * _tv.y + _w.z * _tv.z; var d:Number = uv * uv - uu * vv; var v:Number = (uv * wv - vv * wu) / d; if (v < 0 || v > 1) return null; var t:Number = (uv * wu - uu * wv) / d; if (t < 0 || (v + t) > 1.0) return null; return _intersect; } private function hasSphereIntersection(pOrig:Vector3D, dir:Vector3D, sPos:Vector3D, radius:Number):Number { _pn.x = -dir.x; _pn.y = -dir.y; _pn.z = -dir.z; dir = _pn; _a = _pn.x * _pn.x + _pn.y * _pn.y + _pn.z * _pn.z; _b = _pn.x * (2 * (pOrig.x - sPos.x)) + _pn.y * (2 * (pOrig.y - sPos.y)) + _pn.z * (2 * (pOrig.z - sPos.z)); _c = sPos.x * sPos.x + sPos.y * sPos.y + sPos.z * sPos.z; _c += pOrig.x * pOrig.x + pOrig.y * pOrig.y + pOrig.z * pOrig.z; _c -= 2 * (sPos.x * pOrig.x + sPos.y * pOrig.y + sPos.z * pOrig.z); _c -= radius * radius; return _b*_b + (-4.0)*_a*_c; } }}
Expand Down