internal static Intersection TestIntersectionTerrainSpherePerfect(GeoTerrainTriangle triangle, Hitbox caller, Hitbox collider, ref Vector3 offsetCaller) { Vector3 untranslatedPositionOfCaller = caller.Owner.Position + offsetCaller - collider.Owner.Position; float sphereRadius = caller.Owner.Scale.X / 2; float lowestPointOfSphere = untranslatedPositionOfCaller.Y - sphereRadius; float highestPointOfSphere = untranslatedPositionOfCaller.Y + sphereRadius; bool doPreciseTest = IsBetweenOrdered(lowestPointOfSphere, triangle.heightMinUntranslated, triangle.heightMaxUntranslated) || IsBetweenOrdered(highestPointOfSphere, triangle.heightMinUntranslated, triangle.heightMaxUntranslated); if (doPreciseTest != true) { if (lowestPointOfSphere >= triangle.heightMinUntranslated && highestPointOfSphere <= triangle.heightMaxUntranslated) { doPreciseTest = true; } else if (lowestPointOfSphere <= triangle.heightMinUntranslated && highestPointOfSphere >= triangle.heightMaxUntranslated) { doPreciseTest = true; } } if (doPreciseTest) { float heightOnTriangle = triangle.InterpolateHeight(untranslatedPositionOfCaller.X, untranslatedPositionOfCaller.Z); float difference = heightOnTriangle - lowestPointOfSphere; if (difference < 0) { return(null); } float differenceTowardsTriangleNormal = Vector3.Dot(new Vector3(0, difference, 0), triangle.Normal); Vector3 mtvUp = new Vector3(0, difference, 0); Vector3 mtv = triangle.Normal * differenceTowardsTriangleNormal; Intersection o = new Intersection(collider.Owner, caller, collider, mtv, mtvUp, collider.mMesh.Name, triangle.Normal); return(o); } return(null); }
internal static Intersection TestIntersectionSATForTerrain(GeoTerrainTriangle triangle, Hitbox caller, Hitbox collider, ref Vector3 offsetCaller) { if (caller.Owner.IsSpherePerfect()) { return(TestIntersectionTerrainSpherePerfect(triangle, caller, collider, ref offsetCaller)); } float shape1Min, shape1Max, shape2Min, shape2Max; Vector3 o = collider.Owner.Position; float mtvDistance = float.MaxValue; float mtvDirection = 1; float mtvDistanceUp = float.MaxValue; float mtvDirectionUp = 1; MTVTemp = Vector3.Zero; MTVTempUp = Vector3.Zero; int collisionNormalIndex = -2; bool allTrue = true; // Test #1 SatTest(ref triangle.Normal, ref caller.mVertices, out shape1Min, out shape1Max, ref offsetCaller); SatTestOffset(ref triangle.Normal, ref triangle.Vertices, out shape2Min, out shape2Max, ref o); if (Overlaps(shape1Min, shape1Max, shape2Min, shape2Max)) { bool modifyCollisionNormal = CalculateOverlap(ref triangle.Normal, ref shape1Min, ref shape1Max, ref shape2Min, ref shape2Max, ref mtvDistance, ref mtvDistanceUp, ref MTVTemp, ref MTVTempUp, ref mtvDirection, ref mtvDirectionUp, ref caller.mCenter, ref collider.mCenter, ref offsetCaller); if (modifyCollisionNormal) { collisionNormalIndex = -1; // -1 = normal from triangle } for (int j = 0; j < caller.mNormals.Length; j++) { SatTest(ref caller.mNormals[j], ref caller.mVertices, out shape1Min, out shape1Max, ref offsetCaller); SatTestOffset(ref caller.mNormals[j], ref triangle.Vertices, out shape2Min, out shape2Max, ref o); if (Overlaps(shape1Min, shape1Max, shape2Min, shape2Max)) { bool modifyCollisionNormalInLoop = CalculateOverlap(ref caller.mNormals[j], ref shape1Min, ref shape1Max, ref shape2Min, ref shape2Max, ref mtvDistance, ref mtvDistanceUp, ref MTVTemp, ref MTVTempUp, ref mtvDirection, ref mtvDirectionUp, ref caller.mCenter, ref collider.mCenter, ref offsetCaller); if (modifyCollisionNormalInLoop) { collisionNormalIndex = j; } } else { allTrue = false; break; } } if (allTrue) { Intersection tempIntersection; Vector3 rayPos = caller.Owner.GetLargestHitbox().mCenter + offsetCaller + KWEngine.WorldUp * KWEngine.CurrentWorld.WorldDistance; float heightOnTerrain = triangle.InterpolateHeight(rayPos.X - o.X, rayPos.Z - o.Z); MTVTempUp.Y = heightOnTerrain - caller.Owner.Position.Y; MTVTempUp.X = 0; MTVTempUp.Z = 0; if (collisionNormalIndex == -1) { tempIntersection = new Intersection(collider.Owner, caller, collider, MTVTemp, MTVTempUp, collider.Owner.Name, triangle.Normal); } else { tempIntersection = new Intersection(collider.Owner, caller, collider, MTVTemp, MTVTempUp, collider.Owner.Name, caller.Normals[collisionNormalIndex]); } return(tempIntersection); } } return(null); }
internal static Intersection TestIntersection(Hitbox caller, Hitbox collider, Vector3 offsetCaller) { if (caller.Owner.IsSpherePerfect() && !collider.Owner.IsSpherePerfect()) { return(TestIntersectionSphereConvexHull(caller, collider, offsetCaller)); } else if (caller.Owner.IsSpherePerfect() && collider.Owner.IsSpherePerfect()) { return(TestIntersectionSphereSphere(caller, collider, offsetCaller)); } else if (!caller.Owner.IsSpherePerfect() && collider.Owner.IsSpherePerfect()) { return(TestIntersectionConvexHullSphere(caller, collider, offsetCaller)); } float mtvDistance = float.MaxValue; float mtvDirection = 1; float mtvDistanceUp = float.MaxValue; float mtvDirectionUp = 1; MTVTemp = Vector3.Zero; MTVTempUp = Vector3.Zero; int collisionNormalIndex = 0; for (int i = 0; i < caller.mNormals.Length; i++) { float shape1Min, shape1Max, shape2Min, shape2Max; SatTest(ref caller.mNormals[i], ref caller.mVertices, out shape1Min, out shape1Max, ref offsetCaller); SatTest(ref caller.mNormals[i], ref collider.mVertices, out shape2Min, out shape2Max, ref ZeroVector); if (!Overlaps(shape1Min, shape1Max, shape2Min, shape2Max)) { return(null); } else { bool m = CalculateOverlap(ref caller.mNormals[i], ref shape1Min, ref shape1Max, ref shape2Min, ref shape2Max, ref mtvDistance, ref mtvDistanceUp, ref MTVTemp, ref MTVTempUp, ref mtvDirection, ref mtvDirectionUp, ref caller.mCenter, ref collider.mCenter, ref offsetCaller); if (m) { collisionNormalIndex = i; } } } for (int i = 0; i < collider.mNormals.Length; i++) { float shape1Min, shape1Max, shape2Min, shape2Max; SatTest(ref collider.mNormals[i], ref caller.mVertices, out shape1Min, out shape1Max, ref offsetCaller); SatTest(ref collider.mNormals[i], ref collider.mVertices, out shape2Min, out shape2Max, ref ZeroVector); if (!Overlaps(shape1Min, shape1Max, shape2Min, shape2Max)) { return(null); } else { bool m = CalculateOverlap(ref collider.mNormals[i], ref shape1Min, ref shape1Max, ref shape2Min, ref shape2Max, ref mtvDistance, ref mtvDistanceUp, ref MTVTemp, ref MTVTempUp, ref mtvDirection, ref mtvDirectionUp, ref caller.mCenter, ref collider.mCenter, ref offsetCaller); if (m) { collisionNormalIndex = caller.mNormals.Length + i; } } } if (MTVTemp == Vector3.Zero) { return(null); } Vector3 collisionSurfaceNormal; if (collisionNormalIndex < caller.mNormals.Length) { collisionSurfaceNormal = caller.mNormals[collisionNormalIndex]; } else { collisionSurfaceNormal = collider.mNormals[collisionNormalIndex - caller.mNormals.Length]; } Intersection o = new Intersection(collider.Owner, caller, collider, MTVTemp, MTVTempUp, collider.mMesh.Name, collisionSurfaceNormal); return(o); }
private static Intersection TestIntersectionConvexHullSphere(Hitbox caller, Hitbox collider, Vector3 offsetCaller) { float mtvDistance = float.MaxValue; float mtvDirection = 1; float mtvDistanceUp = float.MaxValue; float mtvDirectionUp = 1; MTVTemp = Vector3.Zero; MTVTempUp = Vector3.Zero; bool useSphereNormal = false; float sphereRadius = collider.Owner.Scale.X / 2; Vector3 collisionSurfaceNormal = new Vector3(0, 0, 0); float shape1Min, shape1Max, shape2Min, shape2Max; for (int i = 0; i < caller.mNormals.Length; i++) { SatTest(ref caller.mNormals[i], ref caller.mVertices, out shape1Min, out shape1Max, ref ZeroVector); shape2Min = Vector3.Dot(collider.GetCenter() - caller.mNormals[i] * sphereRadius, caller.mNormals[i]); shape2Max = Vector3.Dot(collider.GetCenter() + caller.mNormals[i] * sphereRadius, caller.mNormals[i]); if (!Overlaps(shape1Min, shape1Max, shape2Min, shape2Max)) { return(null); } else { bool m = CalculateOverlap(ref caller.mNormals[i], ref shape1Min, ref shape1Max, ref shape2Min, ref shape2Max, ref mtvDistance, ref mtvDistanceUp, ref MTVTemp, ref MTVTempUp, ref mtvDirection, ref mtvDirectionUp, ref caller.mCenter, ref collider.mCenter, ref offsetCaller); if (m) { collisionSurfaceNormal = Vector3.NormalizeFast((caller.mCenter + offsetCaller) - collider.mCenter); } } } //collider is sphere: Vector3 sphereToHullDirectionVector = Vector3.NormalizeFast((caller.GetCenter() + offsetCaller) - collider.GetCenter()); SatTest(ref sphereToHullDirectionVector, ref caller.mVertices, out shape1Min, out shape1Max, ref offsetCaller); shape2Min = Vector3.Dot(collider.GetCenter() - sphereToHullDirectionVector * sphereRadius, sphereToHullDirectionVector); shape2Max = Vector3.Dot(collider.GetCenter() + sphereToHullDirectionVector * sphereRadius, sphereToHullDirectionVector); if (!Overlaps(shape1Min, shape1Max, shape2Min, shape2Max)) { return(null); } else { bool m = CalculateOverlap(ref sphereToHullDirectionVector, ref shape1Min, ref shape1Max, ref shape2Min, ref shape2Max, ref mtvDistance, ref mtvDistanceUp, ref MTVTemp, ref MTVTempUp, ref mtvDirection, ref mtvDirectionUp, ref caller.mCenter, ref collider.mCenter, ref offsetCaller); if (m) { useSphereNormal = true; } } if (MTVTemp == Vector3.Zero) { return(null); } Intersection o = new Intersection(collider.Owner, caller, collider, MTVTemp, MTVTempUp, collider.mMesh.Name, useSphereNormal ? sphereToHullDirectionVector : collisionSurfaceNormal); return(o); }
private static Intersection TestIntersectionSphereConvexHull(Hitbox caller, Hitbox collider, Vector3 offsetCaller) { float mtvDistance = float.MaxValue; float mtvDirection = 1; float mtvDistanceUp = float.MaxValue; float mtvDirectionUp = 1; MTVTemp = Vector3.Zero; MTVTempUp = Vector3.Zero; float sphereRadius = caller.Owner.Scale.X / 2; int bestCollisionIndex = 0; float shape1Min, shape1Max, shape2Min, shape2Max; for (int i = 0; i < collider.mNormals.Length; i++) { shape1Min = Vector3.Dot((caller.GetCenter() + offsetCaller) - collider.mNormals[i] * sphereRadius, collider.mNormals[i]); shape1Max = Vector3.Dot((caller.GetCenter() + offsetCaller) + collider.mNormals[i] * sphereRadius, collider.mNormals[i]); SatTest(ref collider.mNormals[i], ref collider.mVertices, out shape2Min, out shape2Max, ref ZeroVector); if (!Overlaps(shape1Min, shape1Max, shape2Min, shape2Max)) { return(null); } else { bool m = CalculateOverlap(ref collider.mNormals[i], ref shape1Min, ref shape1Max, ref shape2Min, ref shape2Max, ref mtvDistance, ref mtvDistanceUp, ref MTVTemp, ref MTVTempUp, ref mtvDirection, ref mtvDirectionUp, ref caller.mCenter, ref collider.mCenter, ref offsetCaller); if (m) { bestCollisionIndex = i; } } } Vector3 hullToSphereDirectionVector = Vector3.NormalizeFast((caller.GetCenter() + offsetCaller) - collider.GetCenter()); shape1Min = Vector3.Dot((caller.GetCenter() + offsetCaller) - hullToSphereDirectionVector * sphereRadius, hullToSphereDirectionVector); shape1Max = Vector3.Dot((caller.GetCenter() + offsetCaller) + hullToSphereDirectionVector * sphereRadius, hullToSphereDirectionVector); SatTest(ref hullToSphereDirectionVector, ref collider.mVertices, out shape2Min, out shape2Max, ref ZeroVector); if (!Overlaps(shape1Min, shape1Max, shape2Min, shape2Max)) { return(null); } else { bool m = CalculateOverlap(ref hullToSphereDirectionVector, ref shape1Min, ref shape1Max, ref shape2Min, ref shape2Max, ref mtvDistance, ref mtvDistanceUp, ref MTVTemp, ref MTVTempUp, ref mtvDirection, ref mtvDirectionUp, ref caller.mCenter, ref collider.mCenter, ref offsetCaller); if (m) { bestCollisionIndex = -100; } } if (MTVTemp == Vector3.Zero) { return(null); } Intersection o = new Intersection(collider.Owner, caller, collider, MTVTemp, MTVTempUp, collider.mMesh.Name, bestCollisionIndex == -100 ? hullToSphereDirectionVector : collider.mNormals[bestCollisionIndex]); return(o); }
internal static List <Vector3> ClipFaces(Hitbox caller, Hitbox collider) { List <Vector3> callerVertices = new List <Vector3>(caller.mVertices); List <Vector3> collisionVolumeVertices = new List <Vector3>(); // Clip caller against collider faces: for (int colliderFaceIndex = 0; colliderFaceIndex < collider.mMesh.Faces.Length; colliderFaceIndex++) { GeoMeshFace colliderClippingFace = collider.mMesh.Faces[colliderFaceIndex]; Vector3 colliderClippingFaceVertex = collider.mVertices[colliderClippingFace.Vertices[0]]; Vector3 colliderClippingFaceNormal = colliderClippingFace.Flip ? collider.mNormals[colliderClippingFace.Normal] : -collider.mNormals[colliderClippingFace.Normal]; for (int callerVertexIndex = 0; callerVertexIndex < callerVertices.Count; callerVertexIndex++) { Vector3 callerVertex1 = callerVertices[callerVertexIndex]; Vector3 callerVertex2 = callerVertices[(callerVertexIndex + 1) % callerVertices.Count]; Vector3 lineDirection = Vector3.NormalizeFast(callerVertex2 - callerVertex1); bool callerVertex1InsideRegion = HelperIntersection.IsInFrontOfPlane(ref callerVertex1, ref colliderClippingFaceNormal, ref colliderClippingFaceVertex); bool callerVertex2InsideRegion = HelperIntersection.IsInFrontOfPlane(ref callerVertex2, ref colliderClippingFaceNormal, ref colliderClippingFaceVertex); if (callerVertex1InsideRegion) { if (callerVertex2InsideRegion) { if (!collisionVolumeVertices.Contains(callerVertex2)) { collisionVolumeVertices.Add(callerVertex2); } } else { Vector3?clippedVertex = ClipLineToPlane(ref callerVertex2, ref lineDirection, ref colliderClippingFaceVertex, ref colliderClippingFaceNormal); if (clippedVertex != null && !collisionVolumeVertices.Contains(clippedVertex.Value)) { collisionVolumeVertices.Add(clippedVertex.Value); } } } else { if (callerVertex2InsideRegion) { Vector3?clippedVertex = ClipLineToPlane(ref callerVertex1, ref lineDirection, ref colliderClippingFaceVertex, ref colliderClippingFaceNormal); if (clippedVertex != null && !collisionVolumeVertices.Contains(clippedVertex.Value)) { collisionVolumeVertices.Add(clippedVertex.Value); } if (!collisionVolumeVertices.Contains(callerVertex2)) { collisionVolumeVertices.Add(callerVertex2); } } } } callerVertices.Clear(); for (int i = 0; i < collisionVolumeVertices.Count; i++) { callerVertices.Add(collisionVolumeVertices[i]); } collisionVolumeVertices.Clear(); } return(callerVertices); }
internal static void TestIntersectionSATForTerrain(ref List <GeoTerrainTriangle> tris, Hitbox caller, Hitbox collider, Vector3 offsetCaller) { trianglesMTV.Clear(); float shape1Min, shape1Max, shape2Min, shape2Max; Vector3 o = collider.Owner.Position; for (int i = 0; i < tris.Count; i++) { GeoTerrainTriangle triangle = tris[i]; // Test #1 SatTest(ref triangle.Normal, ref caller.mVertices, out shape1Min, out shape1Max, ref offsetCaller); SatTestOffset(ref triangle.Normal, ref triangle.Vertices, out shape2Min, out shape2Max, ref o); if (Overlaps(shape1Min, shape1Max, shape2Min, shape2Max)) { // Test #2: SatTest(ref caller.mNormals[0], ref caller.mVertices, out shape1Min, out shape1Max, ref offsetCaller); SatTestOffset(ref caller.mNormals[0], ref triangle.Vertices, out shape2Min, out shape2Max, ref o); if (Overlaps(shape1Min, shape1Max, shape2Min, shape2Max)) { // Test #3: SatTest(ref caller.mNormals[1], ref caller.mVertices, out shape1Min, out shape1Max, ref offsetCaller); SatTestOffset(ref caller.mNormals[1], ref triangle.Vertices, out shape2Min, out shape2Max, ref o); if (Overlaps(shape1Min, shape1Max, shape2Min, shape2Max)) { // Test #4: SatTest(ref caller.mNormals[2], ref caller.mVertices, out shape1Min, out shape1Max, ref offsetCaller); SatTestOffset(ref caller.mNormals[2], ref triangle.Vertices, out shape2Min, out shape2Max, ref o); if (Overlaps(shape1Min, shape1Max, shape2Min, shape2Max)) { // Test #5: B-A x Hitbox-X-Axis Vector3 subVector = triangle.Vertices[1] - triangle.Vertices[0]; //Vector3.Subtract(ref triangle.Vertices[1], ref triangle.Vertices[0], out Vector3 subVector); Vector3.Cross(ref subVector, ref caller.mNormals[0], out Vector3 axisFive);