예제 #1
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);
        }
예제 #2
0
        /// <summary>
        /// Retorna true si hubo interseccion con el terreno y setea el collisionPoint.
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="collisionPoint"></param>
        /// <returns></returns>
        public bool intersectRay(TgcRay ray, out Vector3 collisionPoint)
        {
            collisionPoint = Vector3.Empty;
            Matrix  scaleInv = Matrix.Scaling(new Vector3(1 / ScaleXZ, 1 / ScaleY, 1 / ScaleXZ));
            Vector3 a        = Vector3.TransformCoordinate(ray.Origin, scaleInv) - traslation;
            Vector3 r        = Vector3.TransformCoordinate(ray.Direction, scaleInv);


            if (a.Y < minIntensity)
            {
                return(false);
            }

            Vector3 q;

            //Me fijo si intersecta con el BB del terreno.
            if (!TgcCollisionUtils.intersectRayAABB(new TgcRay(a, r).toStruct(), aabb.toStruct(), out q))
            {
                return(false);
            }

            float minT = 0;

            //Obtengo el T de la interseccion.
            if (q != a)
            {
                if (r.X != 0)
                {
                    minT = (q.X - a.X) / r.X;
                }
                else if (r.Y != 0)
                {
                    minT = (q.Y - a.Y) / r.Y;
                }
                else if (r.Z != 0)
                {
                    minT = (q.Z - a.Z) / r.Z;
                }
            }


            //Me desplazo por el rayo hasta que su altura sea menor a la del terreno en ese punto
            //o me salga del AABB.
            float t    = 0;
            float step = 1;

            for (t = minT; ; t += step)
            {
                collisionPoint = a + t * r;
                float y;

                if (!interpoledIntensity(collisionPoint.X, collisionPoint.Z, out y))
                {
                    return(false);
                }


                if (collisionPoint.Y <= y + float.Epsilon)
                {
                    collisionPoint.Y = y;
                    collisionPoint   = Vector3.TransformCoordinate(collisionPoint + traslation, Matrix.Scaling(ScaleXZ, ScaleY, ScaleXZ));
                    return(true);
                }
            }
        }