// http://gamedev.stackexchange.com/questions/18436/most-efficient-aabb-vs-ray-collision-algorithms // release 0.050010 us // debug 0.069480 us public static RayDHitInfo CastRay(this RayD ray, Bounds bounds) { // lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner // r.org is origin of ray double tt1 = (bounds.Min.X - ray.origin.X) / ray.direction.X; double t2 = (bounds.Max.X - ray.origin.X) / ray.direction.X; double t3 = (bounds.Min.Y - ray.origin.Y) / ray.direction.Y; double t4 = (bounds.Max.Y - ray.origin.Y) / ray.direction.Y; double t5 = (bounds.Min.Z - ray.origin.Z) / ray.direction.Z; double t6 = (bounds.Max.Z - ray.origin.Z) / ray.direction.Z; double tmin = Math.Max(Math.Max(Math.Min(tt1, t2), Math.Min(t3, t4)), Math.Min(t5, t6)); double tmax = Math.Min(Math.Min(Math.Max(tt1, t2), Math.Max(t3, t4)), Math.Max(t5, t6)); // if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us if (tmax < 0) { //t0 = tmax; return(RayDHitInfo.NoHit); } //if (tmin > t1) return false; // if tmin > tmax, ray doesn't intersect AABB if (tmin > tmax) { //t0 = tmax; return(RayDHitInfo.NoHit); } return(RayDHitInfo.HitAtRayDistance(tmin)); //t1 = tmin; }
public static RayDHitInfo CastRay(this RayD ray, SphereD sphere) { var u = ray.direction; var A = ray.origin; var S = sphere.center; var r = sphere.radius; double _a = 1; // if u is not normalized then: //_a = u.x * u.x + u.y * u.y + u.z * u.z; double _b = ( (A.X * u.X) - (u.X * S.X) + (A.Y * u.Y) - (u.Y * S.Y) + (A.Z * u.Z) - (u.Z * S.Z) ) * 2; double _c = ((A.X - S.X) * (A.X - S.X)) + ((A.Y - S.Y) * (A.Y - S.Y)) + ((A.Z - S.Z) * (A.Z - S.Z)) + -(r * r); // a*t*t + b*t + c double determinant = _b * _b - 4 * _a * _c; if (determinant < 0) { return(RayDHitInfo.NoHit); // no hit } double _2a = 2 * _a; if (determinant > 0) // two hits { double dSqrt = (double)Math.Sqrt(determinant); double t1 = (-_b + dSqrt) / _2a; double t2 = (-_b - dSqrt) / _2a; if (t1 < t2) { return(RayDHitInfo.HitAtRayDistance(t1)); } else { return(RayDHitInfo.HitAtRayDistance(t2)); } } if (determinant == 0) // one hit { double t1 = -_b / _2a; return(RayDHitInfo.HitAtRayDistance(t1)); } return(RayDHitInfo.NoHit); }
// Thomas Moller ray triangle intersection // or http://www.lighthouse3d.com/tutorials/maths/ray-triangle-intersection/ // release 0.054317 us // debug 0.602176 us public static RayDHitInfo CastRay(this RayD ray, TriangleD triangle) { // TODO /* * Zde doplòte kód pro testování existence prùseèíku parsku s trojúhelníkem. * Vypoètený parametr t spoleènì s trojúhelníkem triangle vložte ma konci této metody * do metody ray.closest_hit, napø. takto * * return ray.closest_hit( t, triangle ); * * Tato metoda vrátí true v pøípadì, že zadaný parametr t je menší než pøedchozí a zapíše * do paprsku i ukazatel na zasažený trojúhelník, pøes který (metoda target) je možno následnì zjistit * normálu (target.normal()) nebo materiál v bodì zásahu. */ const double ____EPSILON = 0.000001f; Vector3d V1 = triangle.a; Vector3d V2 = triangle.b; Vector3d V3 = triangle.c; Vector3d O = ray.origin; //RayD origin Vector3d D = ray.direction; //RayD direction Vector3d e1, e2; //Edge1, Edge2 Vector3d P, Q, T; double det, inv_det, u, v; double t; //Find vectors for two edges sharing V1 e1 = V2 - V1; e2 = V3 - V1; //Begin calculating determinant - also used to calculate u parameter P = D.Cross(e2); //if determinant is near zero, ray lies in plane of triangle det = e1.Dot(P); //NOT CULLING if (det > -____EPSILON && det < ____EPSILON) { return(RayDHitInfo.NoHit); } inv_det = 1.0f / det; //calculate distance from V1 to ray origin T = O - V1; //Calculate u parameter and test bound u = T.Dot(P) * inv_det; //The intersection lies outside of the triangle if (u < 0.0f || u > 1.0f) { return(RayDHitInfo.NoHit); } //Prepare to test v parameter Q = T.Cross(e1); //Calculate V parameter and test bound v = D.Dot(Q) * inv_det; //The intersection lies outside of the triangle if (v < 0.0f || u + v > 1.0f) { return(RayDHitInfo.NoHit); } t = e2.Dot(Q) * inv_det; if (t > ____EPSILON) { //ray intersection return(RayDHitInfo.HitAtRayDistance(t)); } return(RayDHitInfo.NoHit); // trojúhelník nenalezen }