// This function intializes the collision info class based on given information public CollisionInfo(CollisionHull3D _a, CollisionHull3D _b, float _penetration) { // Is collision A's collision type have less priority to collision B? if (_a.collisionType > _b.collisionType) { // If yes, then switch their priorities a = _b; b = _a; } else { // If no, then keep them as so a = _a; b = _b; } // Based on collision hulls, calculate the rest of the values normal = (b.GetPosition() - a.GetPosition()).normalized; separatingVelocity = CollisionResolution3D.CalculateSeparatingVelocity(a, b, a.GetPosition(), b.GetPosition()); penetration = _penetration; }
// This function calculates OBB to OBB colisions public static CollisionInfo OBBToOBBCollision(CollisionHull3D a, CollisionHull3D b) { List <float> overlaps = new List <float>(); List <Vector3> axes = new List <Vector3>(); // Get the transform values for each axis for each shape Vector3 x1 = a.GetComponent <Particle3D>().transformMatrix.GetColumn(0); Vector3 y1 = a.GetComponent <Particle3D>().transformMatrix.GetColumn(1); Vector3 z1 = a.GetComponent <Particle3D>().transformMatrix.GetColumn(2); Vector3 x2 = b.GetComponent <Particle3D>().transformMatrix.GetColumn(0); Vector3 y2 = b.GetComponent <Particle3D>().transformMatrix.GetColumn(1); Vector3 z2 = b.GetComponent <Particle3D>().transformMatrix.GetColumn(2); // Go through and check through all overlapping axes // Face/Face Object 1 overlaps.Add(CheckOBBAxis(a, b, x1)); axes.Add(x1); if (overlaps[overlaps.Count - 1] < 0) { return(null); } overlaps.Add(CheckOBBAxis(a, b, y1)); axes.Add(y1); if (overlaps[overlaps.Count - 1] < 0) { return(null); } overlaps.Add(CheckOBBAxis(a, b, z1)); axes.Add(z1); if (overlaps[overlaps.Count - 1] < 0) { return(null); } // Face/Face Object 2 overlaps.Add(CheckOBBAxis(a, b, x2)); axes.Add(x2); if (overlaps[overlaps.Count - 1] < 0) { return(null); } overlaps.Add(CheckOBBAxis(a, b, y2)); axes.Add(y2); if (overlaps[overlaps.Count - 1] < 0) { return(null); } overlaps.Add(CheckOBBAxis(a, b, z2)); axes.Add(z2); if (overlaps[overlaps.Count - 1] < 0) { return(null); } // Edge/Edge overlaps.Add(CheckOBBAxis(a, b, Vector3.Cross(x1, x2))); axes.Add(Vector3.Cross(x1, x2)); if (overlaps[overlaps.Count - 1] < 0) { return(null); } overlaps.Add(CheckOBBAxis(a, b, Vector3.Cross(x1, y2))); axes.Add(Vector3.Cross(x1, y2)); if (overlaps[overlaps.Count - 1] < 0) { return(null); } overlaps.Add(CheckOBBAxis(a, b, Vector3.Cross(x1, z2))); axes.Add(Vector3.Cross(x1, z2)); if (overlaps[overlaps.Count - 1] < 0) { return(null); } overlaps.Add(CheckOBBAxis(a, b, Vector3.Cross(y1, x2))); axes.Add(Vector3.Cross(y1, x2)); if (overlaps[overlaps.Count - 1] < 0) { return(null); } overlaps.Add(CheckOBBAxis(a, b, Vector3.Cross(y1, y2))); axes.Add(Vector3.Cross(y1, y2)); if (overlaps[overlaps.Count - 1] < 0) { return(null); } overlaps.Add(CheckOBBAxis(a, b, Vector3.Cross(y1, z2))); axes.Add(Vector3.Cross(y1, z2)); if (overlaps[overlaps.Count - 1] < 0) { return(null); } overlaps.Add(CheckOBBAxis(a, b, Vector3.Cross(z1, x2))); axes.Add(Vector3.Cross(z1, x2)); if (overlaps[overlaps.Count - 1] < 0) { return(null); } overlaps.Add(CheckOBBAxis(a, b, Vector3.Cross(z1, y2))); axes.Add(Vector3.Cross(z1, y2)); if (overlaps[overlaps.Count - 1] < 0) { return(null); } overlaps.Add(CheckOBBAxis(a, b, Vector3.Cross(z1, z2))); axes.Add(Vector3.Cross(z1, z2)); if (overlaps[overlaps.Count - 1] < 0) { return(null); } float bestOverlap = Mathf.Infinity; int bestIndex = 0; for (int i = 0; i < overlaps.Count; i++) { if (overlaps[i] < bestOverlap) { bestOverlap = overlaps[i]; bestIndex = i; } } if (bestIndex > 2) { Vector3 normal = axes[bestIndex]; Vector3 axis = axes[bestIndex]; if (Vector3.Dot(axis, (b.GetPosition() - a.GetPosition())) > 0) { axis *= -1; } Vector3 vertex = a.GetDimensions(); if (Vector3.Dot(a.GetComponent <Particle3D>().transformMatrix.GetColumn(0), normal) > 0) { vertex.x = -vertex.x; } if (Vector3.Dot(a.GetComponent <Particle3D>().transformMatrix.GetColumn(1), normal) > 0) { vertex.y = -vertex.y; } if (Vector3.Dot(a.GetComponent <Particle3D>().transformMatrix.GetColumn(2), normal) > 0) { vertex.z = -vertex.z; } vertex = a.GetComponent <Particle3D>().invTransformMatrix.MultiplyPoint(vertex); // If all axis are overlaping, then we have a collision ReportCollisionToParent(a, b); return(new CollisionInfo(a, b, CollisionResolution.GetFinalPenetration(overlaps), normal, vertex, CollisionResolution3D.CalculateSeparatingVelocity(a, b, a.GetPosition(), b.GetPosition()))); } else if (bestIndex > 5) { Vector3 normal = axes[bestIndex]; Vector3 axis = axes[bestIndex]; if (Vector3.Dot(axis, (a.GetPosition() - b.GetPosition())) > 0) { axis *= -1; } Vector3 vertex = b.GetDimensions(); if (Vector3.Dot(b.GetComponent <Particle3D>().transformMatrix.GetColumn(0), normal) > 0) { vertex.x = -vertex.x; } if (Vector3.Dot(b.GetComponent <Particle3D>().transformMatrix.GetColumn(1), normal) > 0) { vertex.y = -vertex.y; } if (Vector3.Dot(b.GetComponent <Particle3D>().transformMatrix.GetColumn(2), normal) > 0) { vertex.z = -vertex.z; } vertex = b.GetComponent <Particle3D>().invTransformMatrix.MultiplyPoint(vertex); // If all axis are overlaping, then we have a collision ReportCollisionToParent(a, b); return(new CollisionInfo(a, b, CollisionResolution.GetFinalPenetration(overlaps), normal, vertex, CollisionResolution3D.CalculateSeparatingVelocity(a, b, a.GetPosition(), b.GetPosition()))); } else { int index = bestIndex - 6; int oneIndex = index / 3; int twoIndex = index % 3; Vector3 oneAxis = axes[oneIndex]; Vector3 twoAxis = axes[twoIndex]; Vector3 axis = axes[bestIndex].normalized; if (Vector3.Dot(axis, b.GetPosition() - a.GetPosition()) > 0) { axis *= -1; } Vector3 pointOnOneEdge = a.GetDimensions(); Vector3 pointOnTwoEdge = b.GetDimensions(); if (oneIndex == 0) { pointOnOneEdge.x = 0; } else if (Vector2.Dot(x1, axis) > 0) { pointOnOneEdge.x = -pointOnOneEdge.x; } if (twoIndex == 3) { pointOnTwoEdge.x = 0; } else if (Vector2.Dot(x2, axis) > 0) { pointOnTwoEdge.x = -pointOnTwoEdge.x; } if (oneIndex == 1) { pointOnOneEdge.y = 0; } else if (Vector2.Dot(y1, axis) > 0) { pointOnOneEdge.y = -pointOnOneEdge.y; } if (twoIndex == 4) { pointOnTwoEdge.y = 0; } else if (Vector2.Dot(y2, axis) > 0) { pointOnTwoEdge.y = -pointOnTwoEdge.y; } if (oneIndex == 2) { pointOnOneEdge.z = 0; } else if (Vector2.Dot(z1, axis) > 0) { pointOnOneEdge.z = -pointOnOneEdge.z; } if (twoIndex == 5) { pointOnTwoEdge.z = 0; } else if (Vector2.Dot(z2, axis) > 0) { pointOnTwoEdge.z = -pointOnTwoEdge.z; } pointOnOneEdge = a.GetComponent <Particle3D>().invTransformMatrix.MultiplyPoint(pointOnOneEdge); pointOnTwoEdge = b.GetComponent <Particle3D>().invTransformMatrix.MultiplyPoint(pointOnTwoEdge); Vector3 contactPoint = GetCollisionPoint(pointOnOneEdge, oneAxis, a.GetDimensions().x, pointOnTwoEdge, twoAxis, b.GetDimensions().x, bestIndex > 2); ReportCollisionToParent(a, b); return(new CollisionInfo(a, b, CollisionResolution.GetFinalPenetration(overlaps), axis, contactPoint, CollisionResolution3D.CalculateSeparatingVelocity(a, b, a.GetPosition(), b.GetPosition()))); } }
// This function calculate Circle to ABB collisions public static CollisionInfo CircleToOBBCollision(CollisionHull3D a, CollisionHull3D b) { // Find the relative centre by transforming the center of the circle to the local space of the AABB Vector3 relativeCentre = b.GetComponent <Particle3D>().invTransformMatrix.MultiplyPoint(a.GetPosition()); Vector3 closestPointToCircle = new Vector3(Math.Max(b.GetMinimumCorner().x, Math.Min(relativeCentre.x, b.GetMaximumCorner().x)), Math.Max(b.GetMinimumCorner().y, Math.Min(relativeCentre.y, b.GetMaximumCorner().y)), Math.Max(b.GetMinimumCorner().z, Math.Min(relativeCentre.z, b.GetMaximumCorner().z))); Vector3 distance = relativeCentre - closestPointToCircle; float distanceSquared = Vector3.Dot(distance, distance); float penetration = a.GetDimensions().x - Mathf.Sqrt(distanceSquared); // Is the penetration a positive value if (penetration >= 0) { // If yes, then inform the parents of the complex shape object (if applicable) ReportCollisionToParent(a, b); } else { // If no, return nothing return(null); } // Return full details of the Collision list if the two collide return(new CollisionInfo(a, b, penetration, (closestPointToCircle - relativeCentre).normalized, closestPointToCircle, CollisionResolution3D.CalculateSeparatingVelocity(a, b, a.GetPosition(), b.GetPosition()))); }
public static CollisionInfo SphereToPlaneCollision(CollisionHull3D a, CollisionHull3D b) { // Find the relative centre by transforming the center of the circle to the local space of the AABB Vector3 relativeCentre = b.GetComponent <Particle3D>().invTransformMatrix.MultiplyPoint(a.GetPosition()); Vector3 closestPointToCircle = new Vector3(Math.Max(b.GetMinimumCorner().x, Math.Min(relativeCentre.x, b.GetMaximumCorner().x)), Math.Max(b.GetMinimumCorner().y, Math.Min(relativeCentre.y, b.GetMaximumCorner().y)), Math.Max(b.GetMinimumCorner().z, Math.Min(relativeCentre.z, b.GetMaximumCorner().z))); // Calculate the distance between both colliders Vector3 distance = relativeCentre - closestPointToCircle; // Are the Radii less than or equal to the distance between both circles? if (Vector3.Dot(distance, distance) < a.GetDimensions().x *a.GetDimensions().x) { // If yes, then inform the parents of the complex shape object (if applicable) ReportCollisionToParent(a, b); } else { // If no, return nothing return(null); } float penetration = a.GetDimensions().x - Mathf.Sqrt(Vector3.Dot(distance, distance)); Vector3 closestPointWorld = b.GetComponent <Particle3D>().transformMatrix.MultiplyPoint(closestPointToCircle); // Return result return(new CollisionInfo(a, b, penetration, (closestPointWorld - a.GetPosition()).normalized, Vector3.zero, CollisionResolution3D.CalculateSeparatingVelocity(a, b, a.GetPosition(), closestPointWorld))); }
// Update is called once per frame void Update() { collisions.Clear(); for (int i = 0; i < particles.Count; i++) { if (particles[i] != null) { particles[i].ResetCollidingChecker(); particles[i].ResetColliding(); particles[i].GetComponent <Particle3D>().collidingGameObject = null; } } // Iterate through all particles for (int x = 0; x < particles.Count; x++) { for (int y = 0; y < particles.Count; y++) { if (particles[x] != null && particles[y] != null) { // If the one being checked equal to itself? if (x != y && (particles[x].transform.parent != particles[y].transform.parent || particles[x].transform.parent == null)) { CollisionPairKey3D key = new CollisionPairKey3D(particles[y].collisionType, particles[x].collisionType); CollisionInfo collision; if (particles[x].collisionType > particles[y].collisionType) { collision = _collisionTypeCollisionTestFunctions[key](particles[y], particles[x]); } else { collision = _collisionTypeCollisionTestFunctions[key](particles[x], particles[y]); } if (collision != null) { if ((collision.a.GetComponent <Particle3D>().isCharacterController&& !collision.a.GetComponent <Particle3D>().isUsingGravity) || (collision.b.GetComponent <Particle3D>().isCharacterController&& !collision.b.GetComponent <Particle3D>().isUsingGravity)) { } else { if (collision.a.GetComponent <WindZoneScript>() != null) { collision.b.GetComponent <Particle3D>().AddForce(collision.a.GetComponent <WindZoneScript>().force); } else if (collision.b.GetComponent <WindZoneScript>() != null) { collision.a.GetComponent <Particle3D>().AddForce(collision.b.GetComponent <WindZoneScript>().force); } bool isDuplicate = false; for (int i = 0; i < collisions.Count; i++) { if ((collisions[i].a == particles[y] && collisions[i].b == particles[x]) || (collisions[i].a == particles[x] && collisions[i].b == particles[y])) { isDuplicate = true; } } if (!isDuplicate) { collisions.Add(collision); } } } } } } } CollisionResolution3D.ResolveCollisions(collisions, Time.deltaTime); }