/// <summary>
        ///     Colisiona un Elipsoide en movimiento contra un conjunto de triangulos.
        ///     Si hay colision devuelve el instante t de colision, el punto q de colision y el vector normal n de la superficie
        ///     contra la que
        ///     se colisiona.
        ///     Todo se devuelve en Elipsoid space.
        ///     Pasa cada triangulo a Elipsoid space para hacer el testeo.
        /// </summary>
        /// <param name="eSphere">BoundingSphere de radio 1 en Elipsoid space</param>
        /// <param name="eMovementVector">movimiento en Elipsoid space</param>
        /// <param name="eRadius">radio del Elipsoide</param>
        /// <param name="movementSphere">
        ///     BoundingSphere que abarca el sphere en su punto de origen mas el sphere en su punto final
        ///     deseado
        /// </param>
        /// <param name="minT">Menor instante de colision, en Elipsoid space</param>
        /// <param name="minQ">Punto mas cercano de colision, en Elipsoid space</param>
        /// <param name="n">Vector normal de la superficie contra la que se colisiona</param>
        /// <returns>True si hay colision</returns>
        public override bool intersectMovingElipsoid(TgcBoundingSphere eSphere, Vector3 eMovementVector, Vector3 eRadius,
                                                     TgcBoundingSphere movementSphere, out float minT, out Vector3 minQ, out Vector3 n)
        {
            minQ = Vector3.Empty;
            minT = float.MaxValue;
            n    = Vector3.Empty;
            var collisionPlane = Plane.Empty;

            //Colision contra cada triangulo del collider, quedarse con el menor
            Vector3 q;
            float   t;

            for (var i = 0; i < Triangles.Length; i++)
            {
                var triangle = Triangles[i];

                //Primero hacer un Sphere-Sphere test
                if (TgcCollisionUtils.testSphereSphere(movementSphere, triangle.BoundingSphere))
                {
                    //Pasar triangle a Elipsoid Space
                    var eTriangle = new Triangle(
                        TgcVectorUtils.div(triangle.A, eRadius),
                        TgcVectorUtils.div(triangle.B, eRadius),
                        TgcVectorUtils.div(triangle.C, eRadius),
                        null
                        );

                    //Interseccion Moving Sphere-Triangle
                    if (intersectMovingSphereTriangle(eSphere, eMovementVector, eTriangle, out t, out q))
                    {
                        if (t < minT)
                        {
                            minT           = t;
                            minQ           = q;
                            collisionPlane = triangle.Plane;
                        }
                    }
                }
            }

            if (minT != float.MaxValue)
            {
                n = TgcCollisionUtils.getPlaneNormal(collisionPlane);
                return(true);
            }

            return(false);
        }
Пример #2
0
        /// <summary>
        ///     Mover Elipsoide con detección de colisiones, sliding y gravedad.
        ///     Se actualiza la posición del centro del Elipsoide
        /// </summary>
        /// <param name="characterElipsoid">Elipsoide del cuerpo a mover</param>
        /// <param name="movementVector">Movimiento a realizar</param>
        /// <param name="colliders">Obstáculos contra los cuales se puede colisionar</param>
        /// <returns>Desplazamiento relativo final efecutado al Elipsoide</returns>
        public Vector3 moveCharacter(TgcBoundingElipsoid characterElipsoid, Vector3 movementVector, List <Collider> colliders)
        {
            //Guardar posicion original del Elipsoide
            var originalElipsoidCenter = characterElipsoid.Center;

            //Pasar elipsoid space
            var eCenter         = TgcVectorUtils.div(characterElipsoid.Center, characterElipsoid.Radius);
            var eMovementVector = TgcVectorUtils.div(movementVector, characterElipsoid.Radius);

            eSphere.setValues(eCenter, 1);
            var eOrigCenter = eSphere.Center;

            //Ver si la distancia a recorrer es para tener en cuenta
            var distanceToTravelSq = movementVector.LengthSq();

            if (distanceToTravelSq >= EPSILON)
            {
                //Mover la distancia pedida
                selectPotentialColliders(characterElipsoid, movementVector, colliders);
                result = doCollideWithWorld(eSphere, eMovementVector, characterElipsoid.Radius, objetosCandidatos, 0,
                                            movementSphere, 1);
            }

            //Aplicar gravedad
            if (GravityEnabled)
            {
                //Mover con gravedad
                var eGravity = TgcVectorUtils.div(GravityForce, characterElipsoid.Radius);
                selectPotentialColliders(characterElipsoid, eGravity, colliders);
                result = doCollideWithWorld(eSphere, eGravity, characterElipsoid.Radius, objetosCandidatos, 0,
                                            movementSphere, OnGroundMinDotValue);
            }

            //Mover Elipsoid pasando valores de colision a R3
            var movement = TgcVectorUtils.mul(eSphere.Center - eOrigCenter, characterElipsoid.Radius);

            characterElipsoid.moveCenter(movement);

            //Ajustar resultados
            result.realMovmentVector = TgcVectorUtils.mul(result.realMovmentVector, characterElipsoid.Radius);
            result.collisionPoint    = TgcVectorUtils.mul(result.collisionPoint, characterElipsoid.Radius);

            return(movement);
        }
Пример #3
0
        /// <summary>
        ///     Colisiona un Elipsoide en movimiento contra el BoundingBox.
        ///     Si hay colision devuelve el instante t de colision, el punto q de colision y el vector normal n de la superficie
        ///     contra la que
        ///     se colisiona.
        ///     Todo se devuelve en Elipsoid space.
        ///     El BoundingBox se pasa a Elipsoid space para comparar.
        /// </summary>
        /// <param name="eSphere">BoundingSphere de radio 1 en Elipsoid space</param>
        /// <param name="eMovementVector">movimiento en Elipsoid space</param>
        /// <param name="eRadius">radio del Elipsoide</param>
        /// <param name="movementSphere">
        ///     BoundingSphere que abarca el sphere en su punto de origen mas el sphere en su punto final
        ///     deseado
        /// </param>
        /// <param name="t">Menor instante de colision, en Elipsoid space</param>
        /// <param name="q">Punto mas cercano de colision, en Elipsoid space</param>
        /// <param name="n">Vector normal de la superficie contra la que se colisiona</param>
        /// <returns>True si hay colision</returns>
        public override bool intersectMovingElipsoid(TgcBoundingSphere eSphere, Vector3 eMovementVector, Vector3 eRadius,
                                                     TgcBoundingSphere movementSphere, out float t, out Vector3 q, out Vector3 n)
        {
            //Pasar AABB a Elipsoid Space
            eAABB.setExtremes(
                TgcVectorUtils.div(Aabb.PMin, eRadius),
                TgcVectorUtils.div(Aabb.PMax, eRadius)
                );

            t = -1f;
            q = Vector3.Empty;
            n = Vector3.Empty;

            // Compute the AABB resulting from expanding b by sphere radius r
            var e = eAABB.toStruct();

            e.min.X -= eSphere.Radius;
            e.min.Y -= eSphere.Radius;
            e.min.Z -= eSphere.Radius;
            e.max.X += eSphere.Radius;
            e.max.Y += eSphere.Radius;
            e.max.Z += eSphere.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;
            var     ray = new TgcRay.RayStruct();

            ray.origin    = eSphere.Center;
            ray.direction = eMovementVector;
            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
            var i    = 0;
            var sign = new int[3];

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

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

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

            //Box extent and center
            var extent = eAABB.calculateAxisRadius();
            var center = eAABB.PMin + extent;

            //Edge
            if (i == 2)
            {
                //Generar los dos puntos extremos del Edge
                float[] extentDir = { sign[0], sign[1], sign[2] };
                var     zeroIndex = sign[0] == 0 ? 0 : (sign[1] == 0 ? 1 : 2);
                extentDir[zeroIndex] = 1;
                var capsuleA = center + new Vector3(extent.X * extentDir[0], extent.Y * extentDir[1], extent.Z * extentDir[2]);
                extentDir[zeroIndex] = -1;
                var 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, eSphere.Radius), out t))
                {
                    n = new Vector3(sign[0], sign[1], sign[2]);
                    n.Normalize();
                    q = eSphere.Center + t * eMovementVector - eSphere.Radius * n;
                    return(true);
                }
            }

            //Vertex
            if (i == 3)
            {
                var     tmin     = float.MaxValue;
                var     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, eSphere.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, eSphere.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, eSphere.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 = eSphere.Center + t * eMovementVector - eSphere.Radius * n;
                return(true); // Intersection at time t == tmin
            }

            return(false);
        }