Esempio n. 1
0
        public static bool CollisionTest(Ray ray, float[] heightmap, int columns, int rows, float height, out float dist)
        {
            const float TOLERANCE = 1.0e-8f;

            // Find the entry point of the ray into the heightmap's AABB
            AABB heightmapAABB = new AABB(Vector3.Zero, new Vector3((float)columns, (float)rows, height));
            float exitDist;

            if (!RayAABB.CollisionTestSmits(heightmapAABB, ray, out dist, out exitDist))
                return false;

            Vector3 direction = new Vector3(ray.I, ray.J, ray.K);
            Vector3 entryPoint = ray.GetPoint(dist);
            Vector3 exitPoint = ray.GetPoint(exitDist);

            Vector3 delta = exitPoint - entryPoint;
            float incX = (Math.Abs(delta.X) < TOLERANCE) ? 1.0f / TOLERANCE : 1.0f / Math.Abs(delta.X);
            float incY = (Math.Abs(delta.Y) < TOLERANCE) ? 1.0f / TOLERANCE : 1.0f / Math.Abs(delta.Y);

            // Heightmap coordinates
            int x = (int)entryPoint.X;
            int y = (int)entryPoint.Y;
            int dx = (ray.I < 0.0f) ? -1 : (ray.I > 0.0f) ? 1 : 0;
            int dy = (ray.J < 0.0f) ? -1 : (ray.J > 0.0f) ? 1 : 0;

            float accumX = (delta.X < 0.0f) ? (entryPoint.X - (float)x) * incX : ((float)(x + 1) - entryPoint.X) * incX;
            float accumY = (delta.Y < 0.0f) ? (entryPoint.Y - (float)y) * incY : ((float)(y + 1) - entryPoint.Y) * incY;
            float t = 0.0f;

            // Digital differential analyzer (DDA) loop over the heightmap
            while (t <= 1.0f)
            {
                // TODO: We could further optimize this by testing if the current
                // z value passes below HighestAlt(heightmap, columns, rows, x, y)
                if (Intersects(entryPoint, direction, heightmap, columns, rows, x, y, out dist))
                    return true;

                if (accumX < accumY)
                {
                    t = accumX;
                    accumX += incX;
                    x += dx;
                }
                else
                {
                    t = accumY;
                    accumY += incY;
                    y += dy;
                }
            }

            return false;
        }
Esempio n. 2
0
        public static bool CollisionTest(AABB box, Vector3 position, float radius)
        {
            // The center of the sphere relative to the center of the AABB
            Vector3 sphereCenterRelBox = position - box.Center;
            // The point on the surface of the box closest to the center of the sphere
            Vector3 boxPoint;

            float halfXLength = box.XLength * 0.5f;
            float halfYLength = box.YLength * 0.5f;
            float halfZLength = box.ZLength * 0.5f;

            // X
            if (sphereCenterRelBox.X < -halfXLength)
                boxPoint.X = -halfXLength;
            else if (sphereCenterRelBox.X > halfXLength)
                boxPoint.X = halfXLength;
            else
                boxPoint.X = sphereCenterRelBox.X;

            // Y
            if (sphereCenterRelBox.Y < -halfYLength)
                boxPoint.Y = -halfYLength;
            else if (sphereCenterRelBox.Y > halfYLength)
                boxPoint.Y = halfYLength;
            else
                boxPoint.Y = sphereCenterRelBox.Y;

            // Z
            if (sphereCenterRelBox.Z < -halfZLength)
                boxPoint.Z = -halfZLength;
            else if (sphereCenterRelBox.Z > halfZLength)
                boxPoint.Z = halfZLength;
            else
                boxPoint.Z = sphereCenterRelBox.Z;

            // Get the distance from the closest point on the box to the center of the
            // sphere and test if it is less than the sphere radius
            return Vector3.DistanceSquared(sphereCenterRelBox, boxPoint) < (radius * radius);
        }
Esempio n. 3
0
        /// <summary>
        /// A very fast Ray-AABB collision test that only returns true/false
        /// </summary>
        public static bool CollisionTestPluecker(AABB b, Ray r)
        {
            if (Contains(b, new Vector3(r.X, r.Y, r.Z)))
                return true;

            // This source code accompanies the Journal of Graphics Tools paper:
            // "Fast Ray-Axis Aligned Bounding Box Overlap Tests With Pluecker Coordinates" by
            // Jeffrey Mahovsky and Brian Wyvill
            // Department of Computer Science, University of Calgary
            // This source code is public domain, but please mention us if you use it.

            switch (r.Type)
            {
                case Ray.RayType.MMM:
                    // side(R,HD) < 0 or side(R,FB) > 0 or side(R,EF) > 0 or side(R,DC) < 0 or side(R,CB) < 0 or side(R,HE) > 0 to miss
                    if ((r.X < b.Min.X) || (r.Y < b.Min.Y) || (r.Z < b.Min.Z) ||
                        (r.R0 + r.I * b.Min.Y - r.J * b.Max.X < 0f) ||
                        (r.R0 + r.I * b.Max.Y - r.J * b.Min.X > 0f) ||
                        (r.R1 + r.I * b.Max.Z - r.K * b.Min.X > 0f) ||
                        (r.R1 + r.I * b.Min.Z - r.K * b.Max.X < 0f) ||
                        (r.R3 - r.K * b.Max.Y + r.J * b.Min.Z < 0f) ||
                        (r.R3 - r.K * b.Min.Y + r.J * b.Max.Z > 0f))
                        return false;

                    return true;
                case Ray.RayType.MMP:
                    // side(R,HD) < 0 or side(R,FB) > 0 or side(R,HG) > 0 or side(R,AB) < 0 or side(R,DA) < 0 or side(R,GF) > 0 to miss
                    if ((r.X < b.Min.X) || (r.Y < b.Min.Y) || (r.Z > b.Max.Z) ||
                        (r.R0 + r.I * b.Min.Y - r.J * b.Max.X < 0f) ||
                        (r.R0 + r.I * b.Max.Y - r.J * b.Min.X > 0f) ||
                        (r.R1 + r.I * b.Max.Z - r.K * b.Max.X > 0f) ||
                        (r.R1 + r.I * b.Min.Z - r.K * b.Min.X < 0f) ||
                        (r.R3 - r.K * b.Min.Y + r.J * b.Min.Z < 0f) ||
                        (r.R3 - r.K * b.Max.Y + r.J * b.Max.Z > 0f))
                        return false;

                    return true;
                case Ray.RayType.MPM:
                    // side(R,EA) < 0 or side(R,GC) > 0 or side(R,EF) > 0 or side(R,DC) < 0 or side(R,GF) < 0 or side(R,DA) > 0 to miss
                    if ((r.X < b.Min.X) || (r.Y > b.Max.Y) || (r.Z < b.Min.Z) ||
                        (r.R0 + r.I * b.Min.Y - r.J * b.Min.X < 0f) ||
                        (r.R0 + r.I * b.Max.Y - r.J * b.Max.X > 0f) ||
                        (r.R1 + r.I * b.Max.Z - r.K * b.Min.X > 0f) ||
                        (r.R1 + r.I * b.Min.Z - r.K * b.Max.X < 0f) ||
                        (r.R3 - r.K * b.Max.Y + r.J * b.Max.Z < 0f) ||
                        (r.R3 - r.K * b.Min.Y + r.J * b.Min.Z > 0f))
                        return false;

                    return true;
                case Ray.RayType.MPP:
                    // side(R,EA) < 0 or side(R,GC) > 0 or side(R,HG) > 0 or side(R,AB) < 0 or side(R,HE) < 0 or side(R,CB) > 0 to miss
                    if ((r.X < b.Min.X) || (r.Y > b.Max.Y) || (r.Z > b.Max.Z) ||
                        (r.R0 + r.I * b.Min.Y - r.J * b.Min.X < 0f) ||
                        (r.R0 + r.I * b.Max.Y - r.J * b.Max.X > 0f) ||
                        (r.R1 + r.I * b.Max.Z - r.K * b.Max.X > 0f) ||
                        (r.R1 + r.I * b.Min.Z - r.K * b.Min.X < 0f) ||
                        (r.R3 - r.K * b.Min.Y + r.J * b.Max.Z < 0f) ||
                        (r.R3 - r.K * b.Max.Y + r.J * b.Min.Z > 0f))
                        return false;

                    return true;
                case Ray.RayType.PMM:
                    // side(R,GC) < 0 or side(R,EA) > 0 or side(R,AB) > 0 or side(R,HG) < 0 or side(R,CB) < 0 or side(R,HE) > 0 to miss
                    if ((r.X > b.Max.X) || (r.Y < b.Min.Y) || (r.Z < b.Min.Z) ||
                        (r.R0 + r.I * b.Max.Y - r.J * b.Max.X < 0f) ||
                        (r.R0 + r.I * b.Min.Y - r.J * b.Min.X > 0f) ||
                        (r.R1 + r.I * b.Min.Z - r.K * b.Min.X > 0f) ||
                        (r.R1 + r.I * b.Max.Z - r.K * b.Max.X < 0f) ||
                        (r.R3 - r.K * b.Max.Y + r.J * b.Min.Z < 0f) ||
                        (r.R3 - r.K * b.Min.Y + r.J * b.Max.Z > 0f))
                        return false;

                    return true;
                case Ray.RayType.PMP:
                    // side(R,GC) < 0 or side(R,EA) > 0 or side(R,DC) > 0 or side(R,EF) < 0 or side(R,DA) < 0 or side(R,GF) > 0 to miss
                    if ((r.X > b.Max.X) || (r.Y < b.Min.Y) || (r.Z > b.Max.Z) ||
                        (r.R0 + r.I * b.Max.Y - r.J * b.Max.X < 0f) ||
                        (r.R0 + r.I * b.Min.Y - r.J * b.Min.X > 0f) ||
                        (r.R1 + r.I * b.Min.Z - r.K * b.Max.X > 0f) ||
                        (r.R1 + r.I * b.Max.Z - r.K * b.Min.X < 0f) ||
                        (r.R3 - r.K * b.Min.Y + r.J * b.Min.Z < 0f) ||
                        (r.R3 - r.K * b.Max.Y + r.J * b.Max.Z > 0f))
                        return false;

                    return true;
                case Ray.RayType.PPM:
                    // side(R,FB) < 0 or side(R,HD) > 0 or side(R,AB) > 0 or side(R,HG) < 0 or side(R,GF) < 0 or side(R,DA) > 0 to miss
                    if ((r.X > b.Max.X) || (r.Y > b.Max.Y) || (r.Z < b.Min.Z) ||
                        (r.R0 + r.I * b.Max.Y - r.J * b.Min.X < 0f) ||
                        (r.R0 + r.I * b.Min.Y - r.J * b.Max.X > 0f) ||
                        (r.R1 + r.I * b.Min.Z - r.K * b.Min.X > 0f) ||
                        (r.R1 + r.I * b.Max.Z - r.K * b.Max.X < 0f) ||
                        (r.R3 - r.K * b.Max.Y + r.J * b.Max.Z < 0f) ||
                        (r.R3 - r.K * b.Min.Y + r.J * b.Min.Z > 0f))
                        return false;

                    return true;
                case Ray.RayType.PPP:
                    // side(R,FB) < 0 or side(R,HD) > 0 or side(R,DC) > 0 or side(R,EF) < 0 or side(R,HE) < 0 or side(R,CB) > 0 to miss
                    if ((r.X > b.Max.X) || (r.Y > b.Max.Y) || (r.Z > b.Max.Z) ||
                        (r.R0 + r.I * b.Max.Y - r.J * b.Min.X < 0f) ||
                        (r.R0 + r.I * b.Min.Y - r.J * b.Max.X > 0f) ||
                        (r.R1 + r.I * b.Min.Z - r.K * b.Max.X > 0f) ||
                        (r.R1 + r.I * b.Max.Z - r.K * b.Min.X < 0f) ||
                        (r.R3 - r.K * b.Min.Y + r.J * b.Max.Z < 0f) ||
                        (r.R3 - r.K * b.Max.Y + r.J * b.Min.Z > 0f))
                        return false;

                    return true;
            }

            return false;
        }
Esempio n. 4
0
 private static bool Contains(AABB a, Vector3 b)
 {
     return
         b.X >= a.Min.X &&
         b.Y >= a.Min.Y &&
         b.Z >= a.Min.Z &&
         b.X <= a.Max.X &&
         b.Y <= a.Max.Y &&
         b.Z <= a.Max.Z;
 }
Esempio n. 5
0
        /// <summary>
        /// A reasonably fast Ray-AABB collision test that returns true/false 
        /// and the collision point along the ray
        /// </summary>
        public static bool CollisionTestSmits(AABB b, Ray r, out float tNear, out float tFar)
        {
            // This source code accompanies the Journal of Graphics Tools paper:
            // "Fast Ray-Axis Aligned Bounding Box Overlap Tests With Pluecker Coordinates" by
            // Jeffrey Mahovsky and Brian Wyvill
            // Department of Computer Science, University of Calgary
            // This source code is public domain, but please mention us if you use it.

            tNear = -1.0e6f;
            tFar = 1.0e6f;

            switch (r.Type)
            {
                case Ray.RayType.MMM:
                    {
                        // multiply by the inverse instead of dividing
                        float t1 = (b.Max.X - r.X) * r.II;
                        float t2 = (b.Min.X - r.X) * r.II;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Max.Y - r.Y) * r.IJ;
                        float t2 = (b.Min.Y - r.Y) * r.IJ;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Max.Z - r.Z) * r.IK;
                        float t2 = (b.Min.Z - r.Z) * r.IK;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }

                    tNear = Math.Max(tNear, 0.0f);
                    return true;
                case Ray.RayType.MMP:
                    {
                        float t1 = (b.Max.X - r.X) * r.II;
                        float t2 = (b.Min.X - r.X) * r.II;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Max.Y - r.Y) * r.IJ;
                        float t2 = (b.Min.Y - r.Y) * r.IJ;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Min.Z - r.Z) * r.IK;
                        float t2 = (b.Max.Z - r.Z) * r.IK;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }

                    tNear = Math.Max(tNear, 0.0f);
                    return true;
                case Ray.RayType.MPM:
                    {
                        float t1 = (b.Max.X - r.X) * r.II;
                        float t2 = (b.Min.X - r.X) * r.II;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Min.Y - r.Y) * r.IJ;
                        float t2 = (b.Max.Y - r.Y) * r.IJ;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Max.Z - r.Z) * r.IK;
                        float t2 = (b.Min.Z - r.Z) * r.IK;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }

                    tNear = Math.Max(tNear, 0.0f);
                    return true;
                case Ray.RayType.MPP:
                    {
                        float t1 = (b.Max.X - r.X) * r.II;
                        float t2 = (b.Min.X - r.X) * r.II;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Min.Y - r.Y) * r.IJ;
                        float t2 = (b.Max.Y - r.Y) * r.IJ;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Min.Z - r.Z) * r.IK;
                        float t2 = (b.Max.Z - r.Z) * r.IK;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }

                    tNear = Math.Max(tNear, 0.0f);
                    return true;
                case Ray.RayType.PMM:
                    {
                        float t1 = (b.Min.X - r.X) * r.II;
                        float t2 = (b.Max.X - r.X) * r.II;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Max.Y - r.Y) * r.IJ;
                        float t2 = (b.Min.Y - r.Y) * r.IJ;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Max.Z - r.Z) * r.IK;
                        float t2 = (b.Min.Z - r.Z) * r.IK;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }

                    tNear = Math.Max(tNear, 0.0f);
                    return true;
                case Ray.RayType.PMP:
                    {
                        float t1 = (b.Min.X - r.X) * r.II;
                        float t2 = (b.Max.X - r.X) * r.II;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Max.Y - r.Y) * r.IJ;
                        float t2 = (b.Min.Y - r.Y) * r.IJ;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Min.Z - r.Z) * r.IK;
                        float t2 = (b.Max.Z - r.Z) * r.IK;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }

                    tNear = Math.Max(tNear, 0.0f);
                    return true;
                case Ray.RayType.PPM:
                    {
                        float t1 = (b.Min.X - r.X) * r.II;
                        float t2 = (b.Max.X - r.X) * r.II;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Min.Y - r.Y) * r.IJ;
                        float t2 = (b.Max.Y - r.Y) * r.IJ;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Max.Z - r.Z) * r.IK;
                        float t2 = (b.Min.Z - r.Z) * r.IK;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }

                    tNear = Math.Max(tNear, 0.0f);
                    return true;
                case Ray.RayType.PPP:
                    {
                        float t1 = (b.Min.X - r.X) * r.II;
                        float t2 = (b.Max.X - r.X) * r.II;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Min.Y - r.Y) * r.IJ;
                        float t2 = (b.Max.Y - r.Y) * r.IJ;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }
                    {
                        float t1 = (b.Min.Z - r.Z) * r.IK;
                        float t2 = (b.Max.Z - r.Z) * r.IK;

                        if (t1 > tNear)
                            tNear = t1;
                        if (t2 < tFar)
                            tFar = t2;

                        if (tNear > tFar)
                            return false;
                        if (tFar < 0f)
                            return false;
                    }

                    tNear = Math.Max(tNear, 0.0f);
                    return true;
            }

            return false;
        }