private void TestToStringWithCulture(CultureInfo culture) { CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = culture; try { string listSeparator = culture.TextInfo.ListSeparator; string decimalSeparator = culture.NumberFormat.NumberDecimalSeparator; var o = new Ray3F(new Vec3F(1.1f, 2.2f, 3.3f), new Vec3F(4.4f, 5.5f, 6.6f)); string s = o.ToString(null, null); TestToStringResults(o, s, listSeparator, decimalSeparator); string s2 = o.ToString(); Assert.AreEqual(s, s2); s = o.ToString("G", culture); TestToStringResults(o, s, listSeparator, decimalSeparator); s = o.ToString("R", culture); TestToStringResults(o, s, listSeparator, decimalSeparator); } finally { Thread.CurrentThread.CurrentCulture = originalCulture; } }
private void TestToStringResults(Ray3F o, string s, string listSeparator, string decimalSeparator) { string[] results = s.Split(new[] { listSeparator }, StringSplitOptions.RemoveEmptyEntries); Assert.AreEqual(results.Length, 6); foreach (string oneFloatString in results) Assert.True(oneFloatString.Contains(decimalSeparator)); Assert.AreEqual(float.Parse(results[0]), o.Origin.X); Assert.AreEqual(float.Parse(results[1]), o.Origin.Y); Assert.AreEqual(float.Parse(results[2]), o.Origin.Z); Assert.AreEqual(float.Parse(results[3]), o.Direction.X); Assert.AreEqual(float.Parse(results[4]), o.Direction.Y); Assert.AreEqual(float.Parse(results[5]), o.Direction.Z); }
/// <summary> /// Tests if a specified ray intersects this sphere</summary> /// <param name="ray">The ray, with an origin and unit-length direction. Only intersections in /// front of the ray count.</param> /// <param name="x">The intersection point, if there was an intersection</param> /// <returns>True iff ray intersects this sphere</returns> /// <remarks>Algorithm is from _Real-Time Rendering_, p. 299</remarks> public bool Intersects(Ray3F ray, out Vec3F x) { // vector from ray's origin to sphere's center Vec3F oToC = Center - ray.Origin; // 'd' is the distance from the ray's origin to the nearest point on the ray to Center. // Assumes that Direction has unit length. float d = Vec3F.Dot(oToC, ray.Direction); // distToCenterSquared is the distance from ray's origin to Center, squared. float distToCenterSquared = oToC.LengthSquared; float radiusSquared = Radius * Radius; // if the sphere is behind the ray and the ray's origin is outside the sphere... if (d < 0 && distToCenterSquared > radiusSquared) { x = new Vec3F(); return(false); } // 'm' is the distance from the ray to the center. Pythagorean's theorem. float mSquared = distToCenterSquared - d * d; if (mSquared > radiusSquared) { x = new Vec3F(); return(false); } // 'q' is the distance from the first intersection point to the nearest point // on the ray to Center. Pythagorean's theorem. float q = (float)Math.Sqrt(radiusSquared - mSquared); // 't' is the distance along 'ray' to the point of first intersection. float t; if (distToCenterSquared > radiusSquared) { // ray's origin is outside the sphere. t = d - q; } else { // ray's origin is inside the sphere. t = d + q; } // the point of intersection is ray's origin plus distance along ray's direction x = ray.Origin + t * ray.Direction; return(true); }
public HitRegion Pick(Matrix4F world, Matrix4F view, Ray3F rayL, Ray3F rayV, float s) { m_hitRegion = HitRegion.None; m_hitRayV = rayV; m_hitMatrix.Set(world); m_hitWorldView = world * view; float sl = s * SquareLength; // test xy square. Vec3F p1 = new Vec3F(0, 0, 0); Vec3F p2 = new Vec3F(sl, 0, 0); Vec3F p3 = new Vec3F(sl, sl, 0); Vec3F p4 = new Vec3F(0, sl, 0); Plane3F plane = new Plane3F(p1, p2, p3); Vec3F p; if (rayL.IntersectPlane(plane, out p)) { // test point in 2d rectangle. if (p.X > p1.X && p.X < p2.X && p.Y > p1.Y && p.Y < p4.Y) { m_hitRegion = HitRegion.XYSquare; return m_hitRegion; } } // test xz square p1 = new Vec3F(0, 0, 0); p2 = new Vec3F(sl, 0, 0); p3 = new Vec3F(sl, 0, sl); p4 = new Vec3F(0, 0, sl); plane = new Plane3F(p1, p2, p3); if (rayL.IntersectPlane(plane, out p)) { // test point in 2d rectangle. if (p.X > p1.X && p.X < p2.X && p.Z > p1.Z && p.Z < p4.Z) { m_hitRegion = HitRegion.XZSquare; return m_hitRegion; } } // test yz square p1 = new Vec3F(0, 0, 0); p2 = new Vec3F(0, 0, sl); p3 = new Vec3F(0, sl, sl); p4 = new Vec3F(0, sl, 0); plane = new Plane3F(p1, p2, p3); if (rayL.IntersectPlane(plane, out p)) { // test point in 2d rectangle. if (p.Z > p1.Z && p.Z < p2.Z && p.Y > p1.Z && p.Y < p4.Y) { m_hitRegion = HitRegion.YZSquare; return m_hitRegion; } } Vec3F min = new Vec3F(-0.5f, -0.5f, -0.5f); Vec3F max = new Vec3F(0.5f, 0.5f, 0.5f); AABB box = new AABB(min, max); Matrix4F boxScale = new Matrix4F(); Matrix4F boxTrans = new Matrix4F(); Matrix4F BoxMtrx = new Matrix4F(); // X axis boxScale.Scale(new Vec3F(s, s * br, s * br)); boxTrans.Translation = new Vec3F(s / 2, 0, 0); BoxMtrx = boxScale * boxTrans; Ray3F ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.XAxis; return m_hitRegion; } // y axis boxScale.Scale(new Vec3F(s * br, s, s * br)); boxTrans.Translation = new Vec3F(0, s / 2, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.YAxis; return m_hitRegion; } // z axis boxScale.Scale(new Vec3F(s * br, s * br, s)); boxTrans.Translation = new Vec3F(0, 0, s / 2); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.ZAxis; } return m_hitRegion; }
public Vec3F OnDragging(Ray3F rayV) { if (m_hitRegion == HitRegion.None) return Vec3F.ZeroVector; Vec3F xLocal = m_hitMatrix.XAxis; Vec3F yLocal = m_hitMatrix.YAxis; Vec3F zLocal = m_hitMatrix.ZAxis; Vec3F xAxis = m_hitWorldView.XAxis; Vec3F yAxis = m_hitWorldView.YAxis; Vec3F zAxis = m_hitWorldView.ZAxis; Vec3F origin = m_hitWorldView.Translation; Vec3F translate; float a1, a2; switch (m_hitRegion) { case HitRegion.XAxis: { a1 = Math.Abs(Vec3F.Dot(m_hitRayV.Direction, yAxis)); a2 = Math.Abs(Vec3F.Dot(m_hitRayV.Direction, zAxis)); Vec3F axis = (a1 > a2 ? yAxis : zAxis); Vec3F p0 = m_hitRayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin)); Vec3F p1 = rayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin)); float dragAmount = Vec3F.Dot((p1 - p0), xAxis); translate = dragAmount * xLocal; } break; case HitRegion.YAxis: { a1 = Math.Abs(Vec3F.Dot(m_hitRayV.Direction, zAxis)); a2 = Math.Abs(Vec3F.Dot(m_hitRayV.Direction, xAxis)); Vec3F axis = (a1 > a2 ? zAxis : xAxis); Vec3F p0 = m_hitRayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin)); Vec3F p1 = rayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin)); float dragAmount = Vec3F.Dot((p1 - p0), yAxis); translate = dragAmount * yLocal; } break; case HitRegion.ZAxis: { a1 = Math.Abs(Vec3F.Dot(m_hitRayV.Direction, xAxis)); a2 = Math.Abs(Vec3F.Dot(m_hitRayV.Direction, yAxis)); Vec3F axis = (a1 > a2 ? xAxis : yAxis); Vec3F p0 = m_hitRayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin)); Vec3F p1 = rayV.IntersectPlane(axis, -Vec3F.Dot(axis, origin)); float dragAmount = Vec3F.Dot((p1 - p0), zAxis); translate = dragAmount * zLocal; } break; case HitRegion.XYSquare: { Vec3F p0 = m_hitRayV.IntersectPlane(zAxis, -Vec3F.Dot(zAxis, origin)); Vec3F p1 = rayV.IntersectPlane(zAxis, -Vec3F.Dot(zAxis, origin)); Vec3F deltaLocal = p1 - p0; float dragX = Vec3F.Dot(xAxis, deltaLocal); float dragY = Vec3F.Dot(yAxis, deltaLocal); translate = dragX * xLocal + dragY * yLocal; } break; case HitRegion.YZSquare: { Vec3F p0 = m_hitRayV.IntersectPlane(xAxis, -Vec3F.Dot(xAxis, origin)); Vec3F p1 = rayV.IntersectPlane(xAxis, -Vec3F.Dot(xAxis, origin)); Vec3F deltaLocal = p1 - p0; float dragY = Vec3F.Dot(yAxis, deltaLocal); float dragZ = Vec3F.Dot(zAxis, deltaLocal); translate = dragY * yLocal + dragZ * zLocal; } break; case HitRegion.XZSquare: { Vec3F p0 = m_hitRayV.IntersectPlane(yAxis, -Vec3F.Dot(yAxis, origin)); Vec3F p1 = rayV.IntersectPlane(yAxis, -Vec3F.Dot(yAxis, origin)); Vec3F deltaLocal = p1 - p0; float dragX = Vec3F.Dot(xAxis, deltaLocal); float dragZ = Vec3F.Dot(zAxis, deltaLocal); translate = dragX * xLocal + dragZ * zLocal; } break; default: throw new ArgumentOutOfRangeException(); } return translate; }
public static HitRecord[] RayPick(Matrix4F viewxform, Matrix4F projxfrom, Ray3F rayW, bool skipSelected) { HitRecord* nativeHits = null; int count; fixed (float* ptr1 = &viewxform.M11, ptr2 = &projxfrom.M11) { NativeRayPick( ptr1, ptr2, &rayW, skipSelected, &nativeHits, out count); } var objects = new List<HitRecord>(); for (int k = 0; k < count; k++) { objects.Add(*nativeHits); nativeHits++; } return objects.ToArray(); }
public static bool RayPick(Matrix4F viewxform, Matrix4F projxfrom, Ray3F rayW, bool skipSelected, out HitRecord hit) { HitRecord* nativeHits = null; int count; //bool skipSelected, fixed (float* ptr1 = &viewxform.M11, ptr2 = &projxfrom.M11) { NativeRayPick( ptr1, ptr2, &rayW, skipSelected, &nativeHits, out count); } if(count > 0) { hit = *nativeHits; } else { hit = new HitRecord(); } return count > 0; }
/// <summary> /// Tests if specified ray intersects the box</summary> /// <param name="ray">The ray</param> /// <returns>True iff ray intersects box</returns> public bool Intersects(Ray3F ray) { // http://www.gametutorials.com/gtstore/pc-429-9-ray-and-aabb-collision.aspx // Compute the ray delta Vec3F rayDelta = ray.Direction * 100000f; // First we check to see if the origin of the ray is // inside the AABB. If it is, the ray intersects the AABB so // we'll return true. We start by assuming the ray origin is // inside the AABB bool inside = true; // This stores the distance from either the min or max (x,y,z) to the ray's // origin (x,y,z) respectively, divided by the length of the ray. The largest // value has the delta time of a possible intersection. float xt, yt, zt; // Test the X component of the ray's origin to see if we are inside or not if (ray.Origin.X < Min.X) { xt = Min.X - ray.Origin.X; if (xt > rayDelta.X) // If the ray is moving away from the AABB, there is no intersection { return(false); } xt /= rayDelta.X; inside = false; } else if (ray.Origin.X > Max.X) { xt = Max.X - ray.Origin.X; if (xt < rayDelta.X) // If the ray is moving away from the AABB, there is no intersection { return(false); } xt /= rayDelta.X; inside = false; } else { // Later on we use the "xt", "yt", and "zt" variables to determine which plane (either // xy, xz, or yz) we may collide with. Since the x component of the ray // origin is in between, the AABB's left and right side (which reside in the yz plane), // we know we don't have to test those sides so we set this to a negative value. xt = -1.0f; } // Test the X component of the ray's origin to see if we are inside or not if (ray.Origin.Y < Min.Y) { yt = Min.Y - ray.Origin.Y; if (yt > rayDelta.Y) // If the ray is moving away from the AABB, there is no intersection { return(false); } yt /= rayDelta.Y; inside = false; } else if (ray.Origin.Y > Max.Y) { yt = Max.Y - ray.Origin.Y; if (yt < rayDelta.Y) // If the ray is moving away from the AABB, there is no intersection { return(false); } yt /= rayDelta.Y; inside = false; } else { // Later on we use the "xt", "yt", and "zt" variables to determine which plane (either // xy, xz, or yz) we may collide with. Since the y component of the ray // origin is in between, the AABB's top and bottom side (which reside in the xz plane), // we know we don't have to test those sides so we set this to a negative value. yt = -1.0f; } if (ray.Origin.Z < Min.Z) { zt = Min.Z - ray.Origin.Z; if (zt > rayDelta.Z) // If the ray is moving away from the AABB, there is no intersection { return(false); } zt /= rayDelta.Z; inside = false; } else if (ray.Origin.Z > Max.Z) { zt = Max.Z - ray.Origin.Z; if (zt < rayDelta.Z) // If the ray is moving away from the AABB, there is no intersection { return(false); } zt /= rayDelta.Z; inside = false; } else { // Later on we use the "xt", "yt", and "zt" variables to determine which plane (either // xy, xz, or yz) we may collide with. Since the z component of the ray // origin is in between, the AABB's front and back side (which reside in the xy plane), // we know we don't have to test those sides so we set this to a negative value. zt = -1.0f; } // If the origin inside the AABB if (inside) { return(true); // The ray intersects the AABB } // Otherwise we have some checking to do... // We want to test the AABB planes with largest value out of xt, yt, and zt. So // first we determine which value is the largest. float t = xt; if (yt > t) { t = yt; } if (zt > t) { t = zt; } // **NOTE** Normally comparing two floating point numbers won't necessarily work, however, // since we set to explicitly to equal either xt, yt, or zt above, the equality test // will pass if (t == xt) // If the ray intersects with the AABB's YZ plane { // Compute intersection values float y = ray.Origin.Y + rayDelta.Y * t; float z = ray.Origin.Z + rayDelta.Z * t; // Test to see if collision takes place within the bounds of the AABB if (y < Min.Y || y > Max.Y) { return(false); } else if (z < Min.Z || z > Max.Z) { return(false); } } else if (t == yt) // Intersects with the XZ plane { // Compute intersection values float x = ray.Origin.X + rayDelta.X * t; float z = ray.Origin.Z + rayDelta.Z * t; // Test to see if collision takes place within the bounds of the AABB if (x < Min.X || x > Max.X) { return(false); } else if (z < Min.Z || z > Max.Z) { return(false); } } else // Intersects with the XY plane { // Compute intersection values float x = ray.Origin.X + rayDelta.X * t; float y = ray.Origin.Y + rayDelta.Y * t; // Test to see if collision takes place within the bounds of the AABB if (x < Min.X || x > Max.X) { return(false); } else if (y < Min.Y || y > Max.Y) { return(false); } } // The ray intersects the AABB return(true); }
public bool Intersect(Ray3F r) { float tmin; float tmax; Vec3F pos; Vec3F norm; bool result = Intersect(r, out tmin,out tmax, out pos, out norm); return result; }
/// <summary> /// compute ray in given space starting from /// screen space x,y. /// The space of the computed ray depends on the value of mtrx: /// world * view * projection // ray in local space (object space). /// view * projection // ray in world space. /// projection // ray in view space. /// </summary> public Ray3F GetRay(Point scrPt, Matrix4F mtrx) { Vec3F min = Unproject(new Vec3F(scrPt.X, scrPt.Y, 0), mtrx); Vec3F max = Unproject(new Vec3F(scrPt.X, scrPt.Y, 1), mtrx); Vec3F dir = Vec3F.Normalize(max - min); Ray3F ray = new Ray3F(min, dir); return ray; }
/// <summary> /// compute ray in world space starting from /// screen space x,y. /// </summary> public Ray3F GetWorldRay(Point scrPt) { Matrix4F vp = Camera.ViewMatrix * Camera.ProjectionMatrix; Vec3F min = Unproject(new Vec3F(scrPt.X, scrPt.Y, 0), vp); Vec3F max = Unproject(new Vec3F(scrPt.X, scrPt.Y, 1), vp); Vec3F dir = Vec3F.Normalize(max - min); Ray3F ray = new Ray3F(min, dir); return ray; }
public virtual bool Pick(ViewControl vc, Point scrPt) { Matrix4F normWorld = GetManipulatorMatrix(); if (normWorld == null) return false; HitRayV = vc.GetRay(scrPt, vc.Camera.ProjectionMatrix); HitMatrix.Set(normWorld); return true; }
private bool CalculateTerrainIntersection(ViewControl vc, Ray3F ray, GUILayer.IntersectionTestSceneWrapper testScene, out Vec3F result) { var nativeVC = vc as NativeDesignControl; if (nativeVC == null) { result = Vec3F.ZeroVector; return false; } var pick = XLEBridgeUtils.Picking.RayPick(nativeVC.Adapter, ray, XLEBridgeUtils.Picking.Flags.Terrain); if (pick != null && pick.Length > 0) { result = pick[0].hitPt; return true; } result = Vec3F.ZeroVector; return false; }
/// <summary> /// Creates a ray originating at the given normalized window coordinates and pointing into /// the screen, along -Z axis. Normalized window coordinates are in the range [-0.5,0.5] /// with +x pointing to the right and +y pointing up.</summary> /// <param name="x">The x normalized window coordinate</param> /// <param name="y">The y normalized window coordinate</param> /// <returns>The ray</returns> public Ray3F CreateRay(float x, float y) { float height, width; // Setup ray Ray3F ray = new Ray3F(); // World height on origin's z value if (Frustum.IsOrtho) { width = Frustum.Right - Frustum.Left; height = Frustum.Top - Frustum.Bottom; ray.Origin = new Vec3F(x * width, y * height, -NearZ); ray.Direction = new Vec3F(0, 0, -1); } else { height = Frustum.Far * (float)Math.Tan(Frustum.FovY / 2.0f) * 2.0f; width = Frustum.Far * (float)Math.Tan(Frustum.FovX / 2.0f) * 2.0f; ray.Origin = new Vec3F(0, 0, 0); ray.Direction = new Vec3F(x * width, y * height, -Frustum.Far); float l = ray.Direction.Length; ray.Direction = ray.Direction / l; } return ray; }
private bool CalculateTerrainIntersection(ViewControl vc, Ray3F ray, GUILayer.IntersectionTestSceneWrapper testScene, out Vec3F result) { var pick = XLEBridgeUtils.Picking.RayPick(vc, ray, XLEBridgeUtils.Picking.Flags.Terrain); if (pick != null && pick.Length > 0) { result = pick[0].hitPt; return true; } result = new Vec3F(0.0f, 0.0f, 0.0f); return false; }
/// <summary> /// Projects the ghost</summary> private void ProjectGhost(DomNode ghost, Ray3F rayw, HitRecord? hit) { ITransformable xformnode = ghost.Cast<ITransformable>(); IBoundable bnode = ghost.As<IBoundable>(); AABB box = bnode.BoundingBox; Vec3F pt; if (hit.HasValue && hit.Value.hasNormal) { Vec3F rad = box.Radius; Vec3F norm = hit.Value.normal; Vec3F absNorm = Vec3F.Abs(norm); Vec3F offset = Vec3F.ZeroVector; if (absNorm.X > absNorm.Y) { if (absNorm.X > absNorm.Z) offset.X = norm.X > 0 ? rad.X : -rad.X; else offset.Z = norm.Z > 0 ? rad.Z : -rad.Z; } else { if (absNorm.Y > absNorm.Z) offset.Y = norm.Y > 0 ? rad.Y : -rad.Y; else offset.Z = norm.Z > 0 ? rad.Z : -rad.Z; } Vec3F localCenter = box.Center - xformnode.Translation; pt = hit.Value.hitPt + (offset - localCenter); } else { float offset = 6.0f * box.Radius.Length; pt = rayw.Origin + offset * rayw.Direction; } if (ViewType == ViewTypes.Front) pt.Z = 0.0f; else if (ViewType == ViewTypes.Top) pt.Y = 0.0f; else if (ViewType == ViewTypes.Left) pt.X = 0.0f; xformnode.Translation = pt; }
public bool RayPick(Ray3F rayw, out RayPickRetVal retval) { INativeObject nobj = this.As<INativeObject>(); IntPtr retvalPtr = IntPtr.Zero; IntPtr rayptr = new IntPtr(&rayw); nobj.InvokeFunction("RayPick", rayptr, out retvalPtr); if (retvalPtr != IntPtr.Zero) retval = *(RayPickRetVal*)retvalPtr; else retval = new RayPickRetVal(); return retval.picked; }
public bool Intersect(Ray3F r, out float out_tmin, out float out_tmax, out Vec3F out_pos, out Vec3F out_nor) { out_pos = Vec3F.ZeroVector; out_nor = Vec3F.ZeroVector; out_tmin = 0.0f; out_tmax = 0.0f; Vec3F p = r.Origin; Vec3F d = r.Direction; float tmin = float.MinValue; float tmax = float.MaxValue; // check vs. all three 'slabs' of the aabb for (int i = 0; i < 3; ++i) { if (Math.Abs(d[i]) < float.Epsilon) { // ray is parallel to slab, no hit if origin not within slab if (p[i] < Min[i] || p[i] > Max[i]) { return false; } } else { // compute intersection t values of ray with near and far plane of slab float ood = 1.0f / d[i]; float t1 = (Min[i] - p[i]) * ood; float t2 = (Max[i] - p[i]) * ood; tmin = Math.Max(tmin, Math.Min(t1, t2)); tmax = Math.Min(tmax, Math.Max(t1, t2)); // exit with no collision as soon as slab intersection becomes empty if (tmin > tmax) { return false; } } } if (tmax < 0.0f) { // entire bounding box is behind us return false; } else if (tmin < 0.0f) { // we are inside the bounding box out_tmin = 0.0f; out_tmax = tmax; out_pos = p + d * tmax; out_nor = Vec3F.Normalize(Center - out_pos); // use 'sphere' type normal calculation to approximate. return true; } else { // ray intersects all 3 slabs. return point and normal of intersection out_tmin = tmin; out_pos = p + d * tmin; out_nor = Vec3F.Normalize(Center - out_pos); // use 'sphere' type normal calculation to approximate. return true; } }
/// <summary> /// Tests if specified ray intersects the box</summary> /// <param name="ray">The ray</param> /// <returns>True iff ray intersects box</returns> public bool Intersects(Ray3F ray) { // http://www.gametutorials.com/gtstore/pc-429-9-ray-and-aabb-collision.aspx // Compute the ray delta Vec3F rayDelta = ray.Direction * 100000f; // First we check to see if the origin of the ray is // inside the AABB. If it is, the ray intersects the AABB so // we'll return true. We start by assuming the ray origin is // inside the AABB bool inside = true; // This stores the distance from either the min or max (x,y,z) to the ray's // origin (x,y,z) respectively, divided by the length of the ray. The largest // value has the delta time of a possible intersection. float xt, yt, zt; // Test the X component of the ray's origin to see if we are inside or not if (ray.Origin.X < Min.X) { xt = Min.X - ray.Origin.X; if (xt > rayDelta.X) // If the ray is moving away from the AABB, there is no intersection return false; xt /= rayDelta.X; inside = false; } else if (ray.Origin.X > Max.X) { xt = Max.X - ray.Origin.X; if (xt < rayDelta.X) // If the ray is moving away from the AABB, there is no intersection return false; xt /= rayDelta.X; inside = false; } else { // Later on we use the "xt", "yt", and "zt" variables to determine which plane (either // xy, xz, or yz) we may collide with. Since the x component of the ray // origin is in between, the AABB's left and right side (which reside in the yz plane), // we know we don't have to test those sides so we set this to a negative value. xt = -1.0f; } // Test the X component of the ray's origin to see if we are inside or not if (ray.Origin.Y < Min.Y) { yt = Min.Y - ray.Origin.Y; if (yt > rayDelta.Y) // If the ray is moving away from the AABB, there is no intersection return false; yt /= rayDelta.Y; inside = false; } else if (ray.Origin.Y > Max.Y) { yt = Max.Y - ray.Origin.Y; if (yt < rayDelta.Y) // If the ray is moving away from the AABB, there is no intersection return false; yt /= rayDelta.Y; inside = false; } else { // Later on we use the "xt", "yt", and "zt" variables to determine which plane (either // xy, xz, or yz) we may collide with. Since the y component of the ray // origin is in between, the AABB's top and bottom side (which reside in the xz plane), // we know we don't have to test those sides so we set this to a negative value. yt = -1.0f; } if (ray.Origin.Z < Min.Z) { zt = Min.Z - ray.Origin.Z; if (zt > rayDelta.Z) // If the ray is moving away from the AABB, there is no intersection return false; zt /= rayDelta.Z; inside = false; } else if (ray.Origin.Z > Max.Z) { zt = Max.Z - ray.Origin.Z; if (zt < rayDelta.Z) // If the ray is moving away from the AABB, there is no intersection return false; zt /= rayDelta.Z; inside = false; } else { // Later on we use the "xt", "yt", and "zt" variables to determine which plane (either // xy, xz, or yz) we may collide with. Since the z component of the ray // origin is in between, the AABB's front and back side (which reside in the xy plane), // we know we don't have to test those sides so we set this to a negative value. zt = -1.0f; } // If the origin inside the AABB if (inside) return true; // The ray intersects the AABB // Otherwise we have some checking to do... // We want to test the AABB planes with largest value out of xt, yt, and zt. So // first we determine which value is the largest. float t = xt; if (yt > t) t = yt; if (zt > t) t = zt; // **NOTE** Normally comparing two floating point numbers won't necessarily work, however, // since we set to explicitly to equal either xt, yt, or zt above, the equality test // will pass if (t == xt) // If the ray intersects with the AABB's YZ plane { // Compute intersection values float y = ray.Origin.Y + rayDelta.Y * t; float z = ray.Origin.Z + rayDelta.Z * t; // Test to see if collision takes place within the bounds of the AABB if (y < Min.Y || y > Max.Y) return false; else if (z < Min.Z || z > Max.Z) return false; } else if (t == yt) // Intersects with the XZ plane { // Compute intersection values float x = ray.Origin.X + rayDelta.X * t; float z = ray.Origin.Z + rayDelta.Z * t; // Test to see if collision takes place within the bounds of the AABB if (x < Min.X || x > Max.X) return false; else if (z < Min.Z || z > Max.Z) return false; } else // Intersects with the XY plane { // Compute intersection values float x = ray.Origin.X + rayDelta.X * t; float y = ray.Origin.Y + rayDelta.Y * t; // Test to see if collision takes place within the bounds of the AABB if (x < Min.X || x > Max.X) return false; else if (y < Min.Y || y > Max.Y) return false; } // The ray intersects the AABB return true; }
private static float CalcAngle(Vec3F origin, Plane3F plane, Ray3F ray0, Ray3F ray1, float snapAngle) { float theta = 0; Vec3F p0; Vec3F p1; if( ray0.IntersectPlane(plane, out p0) && ray1.IntersectPlane(plane, out p1)) { Vec3F v0 = Vec3F.Normalize(p0 - origin); Vec3F v1 = Vec3F.Normalize(p1 - origin); theta = CalcAngle(v0, v1, plane.Normal, snapAngle); } return theta; }
/// <summary> /// Tests if a specified ray intersects this sphere</summary> /// <param name="ray">The ray, with an origin and unit-length direction. Only intersections in /// front of the ray count.</param> /// <param name="x">The intersection point, if there was an intersection</param> /// <returns>True iff ray intersects this sphere</returns> /// <remarks>Algorithm is from _Real-Time Rendering_, p. 299</remarks> public bool Intersects(Ray3F ray, out Vec3F x) { // vector from ray's origin to sphere's center Vec3F oToC = Center - ray.Origin; // 'd' is the distance from the ray's origin to the nearest point on the ray to Center. // Assumes that Direction has unit length. float d = Vec3F.Dot(oToC, ray.Direction); // distToCenterSquared is the distance from ray's origin to Center, squared. float distToCenterSquared = oToC.LengthSquared; float radiusSquared = Radius * Radius; // if the sphere is behind the ray and the ray's origin is outside the sphere... if (d < 0 && distToCenterSquared > radiusSquared) { x = new Vec3F(); return false; } // 'm' is the distance from the ray to the center. Pythagorean's theorem. float mSquared = distToCenterSquared - d * d; if (mSquared > radiusSquared) { x = new Vec3F(); return false; } // 'q' is the distance from the first intersection point to the nearest point // on the ray to Center. Pythagorean's theorem. float q = (float)Math.Sqrt(radiusSquared - mSquared); // 't' is the distance along 'ray' to the point of first intersection. float t; if (distToCenterSquared > radiusSquared) { // ray's origin is outside the sphere. t = d - q; } else { // ray's origin is inside the sphere. t = d + q; } // the point of intersection is ray's origin plus distance along ray's direction x = ray.Origin + t * ray.Direction; return true; }