Beispiel #1
0
        /// <summary>
        ///     Interseccion entre un Ray y un AABB
        /// </summary>
        /// <param name="ray">Ray</param>
        /// <param name="aabb">AABB</param>
        /// <param name="tmin">Instante minimo de colision</param>
        /// <param name="q">Punto minimo de colision</param>
        /// <returns>True si hay colision</returns>
        private bool intersectRayAABB(TgcRay.RayStruct ray, TgcBoundingBox.AABBStruct aabb, out float tmin,
                                      out Vector3 q)
        {
            var aabbMin = TgcCollisionUtils.toArray(aabb.min);
            var aabbMax = TgcCollisionUtils.toArray(aabb.max);
            var p       = TgcCollisionUtils.toArray(ray.origin);
            var d       = TgcCollisionUtils.toArray(ray.direction);

            tmin = 0.0f;               // set to -FLT_MAX to get first hit on line
            var tmax = float.MaxValue; // set to max distance ray can travel (for segment)

            q = Vector3.Empty;

            // For all three slabs
            for (var i = 0; i < 3; i++)
            {
                if (FastMath.Abs(d[i]) < float.Epsilon)
                {
                    // Ray is parallel to slab. No hit if origin not within slab
                    if (p[i] < aabbMin[i] || p[i] > aabbMax[i])
                    {
                        return(false);
                    }
                }
                else
                {
                    // Compute intersection t value of ray with near and far plane of slab
                    var ood = 1.0f / d[i];
                    var t1  = (aabbMin[i] - p[i]) * ood;
                    var t2  = (aabbMax[i] - p[i]) * ood;
                    // Make t1 be intersection with near plane, t2 with far plane
                    if (t1 > t2)
                    {
                        TgcCollisionUtils.swap(ref t1, ref t2);
                    }
                    // Compute the intersection of slab intersection intervals
                    tmin = TgcCollisionUtils.max(tmin, t1);
                    tmax = TgcCollisionUtils.min(tmax, t2);
                    // Exit with no collision as soon as slab intersection becomes empty
                    if (tmin > tmax)
                    {
                        return(false);
                    }
                }
            }
            // Ray intersects all 3 slabs. Return point (q) and intersection t value (tmin)
            q = ray.origin + ray.direction * tmin;
            return(true);
        }
Beispiel #2
0
        /// <summary>
        /// Colisiona un BoundingSphere en movimiento contra el BoundingBox.
        /// Si hay colision devuelve el instante t de colision mas proximo y el punto q de colision mas cercano
        /// </summary>
        /// <param name="sphere">BoundingSphere</param>
        /// <param name="movementVector">movimiento del BoundingSphere</param>
        /// <param name="t">Menor instante de colision</param>
        /// <param name="q">Punto mas cercano de colision</param>
        /// <param name="n">Normal de la cara colisionada</param>
        /// <returns>True si hay colision</returns>
        public override bool intersectMovingSphere(TgcBoundingSphere sphere, Vector3 movementVector, TgcBoundingSphere movementSphere, out float t, out Vector3 q, out Vector3 n)
        {
            t = -1f;
            q = Vector3.Empty;
            n = Vector3.Empty;

            // Compute the AABB resulting from expanding b by sphere radius r
            TgcBoundingBox.AABBStruct e = aabb.toStruct();
            e.min.X -= sphere.Radius; e.min.Y -= sphere.Radius; e.min.Z -= sphere.Radius;
            e.max.X += sphere.Radius; e.max.Y += sphere.Radius; e.max.Z += sphere.Radius;

            // Intersect ray against expanded AABB e. Exit with no intersection if ray
            // misses e, else get intersection point p and time t as result
            Vector3 p;

            TgcRay.RayStruct ray = new TgcRay.RayStruct();
            ray.origin    = sphere.Center;
            ray.direction = movementVector;
            if (!intersectRayAABB(ray, e, out t, out p) || t > 1.0f)
            {
                return(false);
            }

            // Compute which min and max faces of b the intersection point p lies
            // outside of. Note, u and v cannot have the same bits set and
            // they must have at least one bit set among them
            int i = 0;

            int[] sign = new int[3];
            if (p.X < aabb.PMin.X)
            {
                sign[0] = -1;
                i++;
            }
            if (p.X > aabb.PMax.X)
            {
                sign[0] = 1;
                i++;
            }
            if (p.Y < aabb.PMin.Y)
            {
                sign[1] = -1;
                i++;
            }
            if (p.Y > aabb.PMax.Y)
            {
                sign[1] = 1;
                i++;
            }
            if (p.Z < aabb.PMin.Z)
            {
                sign[2] = -1;
                i++;
            }
            if (p.Z > aabb.PMax.Z)
            {
                sign[2] = 1;
                i++;
            }



            //Face
            if (i == 1)
            {
                n = new Vector3(sign[0], sign[1], sign[2]);
                q = sphere.Center + t * movementVector - sphere.Radius * n;
                return(true);
            }

            // Define line segment [c, c+d] specified by the sphere movement
            Segment seg = new Segment(sphere.Center, sphere.Center + movementVector);

            //Box extent and center
            Vector3 extent = aabb.calculateAxisRadius();
            Vector3 center = aabb.PMin + extent;

            //Edge
            if (i == 2)
            {
                //Generar los dos puntos extremos del Edge
                float[] extentDir = new float[] { sign[0], sign[1], sign[2] };
                int     zeroIndex = sign[0] == 0 ? 0 : (sign[1] == 0 ? 1 : 2);
                extentDir[zeroIndex] = 1;
                Vector3 capsuleA = center + new Vector3(extent.X * extentDir[0], extent.Y * extentDir[1], extent.Z * extentDir[2]);
                extentDir[zeroIndex] = -1;
                Vector3 capsuleB = center + new Vector3(extent.X * extentDir[0], extent.Y * extentDir[1], extent.Z * extentDir[2]);

                //Colision contra el Edge hecho Capsula
                if (intersectSegmentCapsule(seg, new Capsule(capsuleA, capsuleB, sphere.Radius), out t))
                {
                    n = new Vector3(sign[0], sign[1], sign[2]);
                    n.Normalize();
                    q = sphere.Center + t * movementVector - sphere.Radius * n;
                    return(true);
                }
            }



            //Vertex
            if (i == 3)
            {
                float   tmin     = float.MaxValue;
                Vector3 capsuleA = center + new Vector3(extent.X * sign[0], extent.Y * sign[1], extent.Z * sign[2]);
                Vector3 capsuleB;

                capsuleB = center + new Vector3(extent.X * -sign[0], extent.Y * sign[1], extent.Z * sign[2]);
                if (intersectSegmentCapsule(seg, new Capsule(capsuleA, capsuleB, sphere.Radius), out t))
                {
                    tmin = TgcCollisionUtils.min(t, tmin);
                }

                capsuleB = center + new Vector3(extent.X * sign[0], extent.Y * -sign[1], extent.Z * sign[2]);
                if (intersectSegmentCapsule(seg, new Capsule(capsuleA, capsuleB, sphere.Radius), out t))
                {
                    tmin = TgcCollisionUtils.min(t, tmin);
                }

                capsuleB = center + new Vector3(extent.X * sign[0], extent.Y * sign[1], extent.Z * -sign[2]);
                if (intersectSegmentCapsule(seg, new Capsule(capsuleA, capsuleB, sphere.Radius), out t))
                {
                    tmin = TgcCollisionUtils.min(t, tmin);
                }

                if (tmin == float.MaxValue)
                {
                    return(false);                        // No intersection
                }
                t = tmin;
                n = new Vector3(sign[0], sign[1], sign[2]);
                n.Normalize();
                q = sphere.Center + t * movementVector - sphere.Radius * n;
                return(true); // Intersection at time t == tmin
            }


            return(false);
        }