Example #1
0
        /// <summary>
        /// Test if a collision sphere intersects with the given ray
        /// </summary>
        /// <param name="ray">A ray in 3D space</param>
        /// <param name="intersectionPoint">The intersection point on the surface of the sphere, if one exists</param>
        /// <returns>True if an intersection occurs, false otherwise</returns>
        public bool intersectsWith(Ray ray, ref Vector3 intersectionPoint)
        {
            // If p0 is the origin of the sphere, and r is the radius, with p being the base point of the ray
            //  and d the unit direction of the ray...
            // An intersection point [x, y, z] will be found if (x - p0_x)^2 + (y - p0_y)^2 + (z - p0_z)^2 = r^2
            // The points [x, y, z] can be defined as some point p + n * d, for some number n.
            // If the number is positive we have an intersection at that point.
            // ((p_x + nd_x) - p0_x)^2 + ((p_y + nd_y) - p0_y)^2 + ((p_z + nd_z) - p0_z)^2 = r^2
            // Do some algebra and apply the quadratic formula
            Vector3 d = ray.Direction;
            Vector3 p = ray.Position;
            Vector3 p0 = Origin;
            float r = Radius;

            float a = 1.0f; // Go figure - it turns out to be (d_x^2 + d_y^2 + d_z^2), the square magnitude of a unit vector... Which is one.
            float b = 2.0f * (d.X * (p.X - p0.X) + d.Y * (p.Y - p0.Y) + d.Z * (p.Z - p0.Z));
            float c = -(r * r) + p0.X * p0.X + p0.Y * p0.Y + p0.Z * p0.Z - 2.0f * (p.X * p0.X + p.Y * p0.Y + p.Z * p0.Z) + p.X * p.X + p.Y * p.Y + p.Z * p.Z;

            float sqrtnum = Sqrt(b * b - 4.0f * a * c);
            // No roots - not a collision
            if (float.IsNaN(sqrtnum))
            {
                return false;
            }

            float sol1 = (-b - sqrtnum) / (2.0f * a);
            float sol2 = (-b + sqrtnum) / (2.0f * a);

            if (sol1 < 0.0f)
            {
                if (sol2 < 0.0f)
                {
                    return false;
                }
                else
                {
                    intersectionPoint = p + d * sol2;
                    return true;
                }
            }
            else
            {
                if (sol2 < 0.0f)
                {
                    intersectionPoint = p + d * sol1;
                    return true;
                }
                else
                {
                    intersectionPoint = p + d * Math.Min(sol1, sol2);
                    return true;
                }
            }
        }
        public void RayIntersectionDetailedTest()
        {
            Sphere unitOriginSphere = new Sphere(Vector3.Zero, 1.0f);
            Sphere positiveXSphere = new Sphere(Vector3.UnitX * 10.0f, 5.0f);

            //
            // Unit intersection tests
            //
            // Test one: ray along positive x axis from negative x direction
            Ray tr1 = new Ray(Vector3.UnitX * -5.0f, Vector3.UnitX);
            Vector3 c1 = Vector3.Zero;
            Assert.IsTrue(unitOriginSphere.intersectsWith(tr1, ref c1), "Unit X ray from negative X origin should intersect unit origin sphere");
            Assert.AreEqual(Vector3.UnitX * -1.0f, c1, "Collision point should be at [-1, 0, 0]");

            // Test two: ray along negative y axis from positive y direction
            Ray tr2 = new Ray(Vector3.UnitY * 5.0f, Vector3.UnitY * -1.0f);
            Vector3 c2 = Vector3.Zero;
            Assert.IsTrue(unitOriginSphere.intersectsWith(tr2, ref c2), "Negative unit Y ray from positive Y origin should intersect unit origin sphere");
            Assert.AreEqual(Vector3.UnitY * 1.0f, c2, "Collision point should be at [0, 1, 0]");

            // Test three: Ray along positive z axis from negative z direction
            Ray tr3 = new Ray(Vector3.UnitZ * -5.0f, Vector3.UnitZ);
            Vector3 c3 = Vector3.Zero;
            Assert.IsTrue(unitOriginSphere.intersectsWith(tr3, ref c3), "Unit Z ray from negative Z origin should intersect unit origin sphere");
            Assert.AreEqual(Vector3.UnitZ * -1.0f, c3, "Collision point should be at [0, 0, -1]");

            //
            // Direct miss tests
            //
            // Near miss
            Ray tr4 = new Ray(new Vector3(0.0f, 5.1f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f));
            Vector3 c4 = Vector3.Zero;
            Assert.IsFalse(positiveXSphere.intersectsWith(tr4, ref c4), "A close miss of a ray with a sphere should yield no collision");
            Assert.AreEqual(Vector3.Zero, c4, "Output array should remain zero vector (assuming input zero vector) after a failed near miss collision");

            // Orthogonal miss
            Ray tr5 = new Ray(new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));
            Vector3 c5 = Vector3.Zero;
            Assert.IsFalse(positiveXSphere.intersectsWith(tr5, ref c5), "An orthogonal miss of a ray with a sphere should yield no collision");
            Assert.AreEqual(Vector3.Zero, c5, "Output array should remain zero vector (assuming input zero vector) after a failed orthogonal collision");

            // Wrong direction miss
            Ray tr6 = new Ray(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(-1.0f, 0.0f, 0.0f));
            Vector3 c6 = Vector3.Zero;
            Assert.IsFalse(positiveXSphere.intersectsWith(tr6, ref c6), "An opposite direction miss of a ray with a sphere should yield no collision");
            Assert.AreEqual(Vector3.Zero, c6, "Output array should remain zero vector (assuming input zero vector) after a failed wrong direction collision");

            //
            // Barely hit test
            //
            Ray tr7 = new Ray(new Vector3(0.0f, 5.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f));
            Vector3 c7 = Vector3.Zero;
            Assert.IsTrue(positiveXSphere.intersectsWith(tr7, ref c7), "A collision with a sphere with a barely intersects point should yield a collision");
            Assert.AreEqual(new Vector3(10.0f, 5.0f, 0.0f), c7, "The collision point of a radius 5 sphere with origin [10, 0, 0] on a ray going along the y=5 axis should be [10, 5, 0])");

            //
            // Ray origin on edge of sphere test
            //
            Ray tr8 = new Ray(new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f));
            Vector3 c8 = Vector3.Zero;
            Assert.IsTrue(unitOriginSphere.intersectsWith(tr8, ref c8), "A collision with a sphere where the ray begins immediately on the sphere should yield a collision");
            Assert.AreEqual(new Vector3(-1.0f, 0.0f, 0.0f), c8, "The collision point of a ray begining on the sphere should be at the origin point of the sphere");

            //
            // Ray origin inside sphere test
            //
            Ray tr9 = new Ray(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f));
            Vector3 c9 = Vector3.Zero;
            Assert.IsTrue(unitOriginSphere.intersectsWith(tr9, ref c9), "A collision with a sphere from a ray based inside the sphere should yield a collision");
            Assert.AreEqual(Vector3.UnitX, c9, "The collision point of an intersection with a ray based inside a sphere should be on the closest edge");
        }
Example #3
0
 /// <summary>
 /// Test if the collision sphere intersects the given ray
 /// </summary>
 /// <param name="ray"></param>
 /// <returns></returns>
 public bool intersectsWith(Ray ray)
 {
     // TODO KAM: Try to use a more efficient ray/sphere collision method
     Vector3 foo = Vector3.Zero;
     return intersectsWith(ray, ref foo);
 }
        public void RayIntersectionTest()
        {
            Sphere unitOriginSphere = new Sphere(Vector3.Zero, 1.0f);
            Sphere positiveXSphere = new Sphere(Vector3.UnitX * 10.0f, 5.0f);

            //
            // Unit intersection tests
            //
            // Test one: ray along positive x axis from negative x direction
            Ray tr1 = new Ray(Vector3.UnitX * -5.0f, Vector3.UnitX);
            Assert.IsTrue(unitOriginSphere.intersectsWith(tr1), "Unit X ray from negative X origin should intersect unit origin sphere");

            // Test two: ray along negative y axis from positive y direction
            Ray tr2 = new Ray(Vector3.UnitY * 5.0f, Vector3.UnitY * -1.0f);
            Assert.IsTrue(unitOriginSphere.intersectsWith(tr2), "Negative unit Y ray from positive Y origin should intersect unit origin sphere");

            // Test three: Ray along positive z axis from negative z direction
            Ray tr3 = new Ray(Vector3.UnitZ * -5.0f, Vector3.UnitZ);
            Assert.IsTrue(unitOriginSphere.intersectsWith(tr3), "Unit Z ray from negative Z origin should intersect unit origin sphere");

            //
            // Direct miss tests
            //
            // Near miss
            Ray tr4 = new Ray(new Vector3(0.0f, 5.1f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f));
            Assert.IsFalse(positiveXSphere.intersectsWith(tr4), "A close miss of a ray with a sphere should yield no collision");

            // Orthogonal miss
            Ray tr5 = new Ray(new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));
            Assert.IsFalse(positiveXSphere.intersectsWith(tr5), "An orthogonal miss of a ray with a sphere should yield no collision");

            // Wrong direction miss
            Ray tr6 = new Ray(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(-1.0f, 0.0f, 0.0f));
            Assert.IsFalse(positiveXSphere.intersectsWith(tr6), "An opposite direction miss of a ray with a sphere should yield no collision");

            //
            // Barely hit test
            //
            Ray tr7 = new Ray(new Vector3(0.0f, 5.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f));
            Assert.IsTrue(positiveXSphere.intersectsWith(tr7), "A collision with a sphere with a barely intersects point should yield a collision");

            //
            // Ray origin on edge of sphere test
            //
            Ray tr8 = new Ray(new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f));
            Assert.IsTrue(unitOriginSphere.intersectsWith(tr8), "A collision with a sphere where the ray begins immediately on the sphere should yield a collision");

            //
            // Ray origin inside sphere test
            //
            Ray tr9 = new Ray(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f));
            Assert.IsTrue(unitOriginSphere.intersectsWith(tr9), "A collision with a sphere from a ray based inside the sphere should yield a collision");
        }