/// <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 TGCVector3 moveCharacter(TgcBoundingElipsoid characterElipsoid, TGCVector3 movementVector, List <Collider> colliders) { //Guardar posicion original del Elipsoide var originalElipsoidCenter = characterElipsoid.Center; //Pasar elipsoid space var eCenter = TGCVector3.Div(characterElipsoid.Center, characterElipsoid.Radius); var eMovementVector = TGCVector3.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 = TGCVector3.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 = TGCVector3.Mul(eSphere.Center - eOrigCenter, characterElipsoid.Radius); characterElipsoid.moveCenter(movement); //Ajustar resultados result.realMovmentVector = TGCVector3.Mul(result.realMovmentVector, characterElipsoid.Radius); result.collisionPoint = TGCVector3.Mul(result.collisionPoint, characterElipsoid.Radius); return(movement); }
/// <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, TGCVector3 eMovementVector, TGCVector3 eRadius, TgcBoundingSphere movementSphere, out float minT, out TGCVector3 minQ, out TGCVector3 n) { minQ = TGCVector3.Empty; minT = float.MaxValue; n = TGCVector3.Empty; var collisionPlane = TGCPlane.Zero; //Colision contra cada triangulo del collider, quedarse con el menor TGCVector3 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(TGCVector3.Div(triangle.A, eRadius), TGCVector3.Div(triangle.B, eRadius), TGCVector3.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); }
/// <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, TGCVector3 eMovementVector, TGCVector3 eRadius, TgcBoundingSphere movementSphere, out float t, out TGCVector3 q, out TGCVector3 n) { //Pasar AABB a Elipsoid Space eAABB.setExtremes(TGCVector3.Div(Aabb.PMin, eRadius), TGCVector3.Div(Aabb.PMax, eRadius)); t = -1f; q = TGCVector3.Empty; n = TGCVector3.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 TGCVector3 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 TGCVector3(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 TGCVector3(extent.X * extentDir[0], extent.Y * extentDir[1], extent.Z * extentDir[2]); extentDir[zeroIndex] = -1; var capsuleB = center + new TGCVector3(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 TGCVector3(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 TGCVector3(extent.X * sign[0], extent.Y * sign[1], extent.Z * sign[2]); TGCVector3 capsuleB; capsuleB = center + new TGCVector3(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 TGCVector3(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 TGCVector3(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 TGCVector3(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); }