Last active
October 22, 2019 09:30
-
-
Save Refsa/47f1e35771e16e305f71daf533c8ec1f to your computer and use it in GitHub Desktop.
Seperate Axis Theorem on two box bounds
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class BetterBounds | |
{ | |
public Vector3 center; | |
public Vector3 size; | |
public Quaternion rotation; | |
public Vector3[ ] GetAxes ( ) | |
{ | |
return new Vector3[ ] { rotation * Vector3.right, rotation * Vector3.up, rotation * Vector3.forward }; | |
} | |
public Vector3[ ] GetVertices ( ) | |
{ | |
var halfsize = size / 2f; | |
return new Vector3[ ] | |
{ | |
center + rotation * new Vector3 (-halfsize.x, halfsize.y, halfsize.z), | |
center + rotation * new Vector3 (halfsize.x, halfsize.y, halfsize.z), | |
center + rotation * new Vector3 (-halfsize.x, halfsize.y, -halfsize.z), | |
center + rotation * new Vector3 (halfsize.x, halfsize.y, -halfsize.z), | |
center + rotation * new Vector3 (-halfsize.x, -halfsize.y, halfsize.z), | |
center + rotation * new Vector3 (halfsize.x, -halfsize.y, halfsize.z), | |
center + rotation * new Vector3 (-halfsize.x, -halfsize.y, -halfsize.z), | |
center + rotation * new Vector3 (halfsize.x, -halfsize.y, -halfsize.z) | |
}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class EditorPhysics : MonoBehaviour | |
{ | |
[SerializeField] bool autoRotate; | |
Quaternion rotationB = Quaternion.Euler (0f, 0f, 0f); | |
void OnDrawGizmos ( ) | |
{ | |
if (autoRotate) | |
{ | |
rotationB = Quaternion.Slerp (rotationB, rotationB * Quaternion.Euler (1f, 1f, 0f), 1f); | |
} | |
else | |
rotationB = Quaternion.Euler (0f, 45f, 0f); | |
BetterBounds a = new BetterBounds | |
{ | |
center = Vector3.right * 7f, | |
size = Vector3.one * 10f, | |
rotation = Quaternion.Euler (0f, 0f, 0f) | |
}; | |
BetterBounds b = new BetterBounds | |
{ | |
center = Vector3.left * 5f, | |
size = Vector3.one * 10f, | |
rotation = rotationB | |
}; | |
if (SeparateAxisTheorem.CheckCollision (a, b)) | |
{ | |
Gizmos.color = Color.red; | |
} | |
else | |
{ | |
Gizmos.color = Color.green; | |
} | |
Gizmos.DrawWireSphere (a.center, 0.25f); | |
Gizmos.DrawWireSphere (b.center, 0.25f); | |
var oldmatrix = Gizmos.matrix; | |
Gizmos.matrix = Matrix4x4.TRS (a.center, a.rotation, a.size); | |
Gizmos.DrawWireCube (Vector3.zero, Vector3.one); | |
Gizmos.matrix = Matrix4x4.TRS (b.center, b.rotation, b.size); | |
Gizmos.DrawWireCube (Vector3.zero, Vector3.one); | |
Gizmos.matrix = oldmatrix; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Math from: https://unitylist.com/p/5uc/Unity-Separating-Axis-SAT | |
/// </summary> | |
public static class SeparateAxisTheorem | |
{ | |
public static bool CheckCollision (BetterBounds a, BetterBounds b) | |
{ | |
var aAxes = a.GetAxes ( ); | |
var bAxes = b.GetAxes ( ); | |
var AllAxes = new Vector3[ ] | |
{ | |
aAxes[0], | |
aAxes[1], | |
aAxes[2], | |
bAxes[0], | |
bAxes[1], | |
bAxes[2], | |
Vector3.Cross (aAxes[0], bAxes[0]), | |
Vector3.Cross (aAxes[0], bAxes[1]), | |
Vector3.Cross (aAxes[0], bAxes[2]), | |
Vector3.Cross (aAxes[1], bAxes[0]), | |
Vector3.Cross (aAxes[1], bAxes[1]), | |
Vector3.Cross (aAxes[1], bAxes[2]), | |
Vector3.Cross (aAxes[2], bAxes[0]), | |
Vector3.Cross (aAxes[2], bAxes[1]), | |
Vector3.Cross (aAxes[2], bAxes[2]) | |
}; | |
int aAxesLength = aAxes.Length; | |
int bAxesLength = bAxes.Length; | |
var aVertices = a.GetVertices ( ); | |
var bVertices = b.GetVertices ( ); | |
int aVertsLength = aVertices.Length; | |
int bVertsLength = bVertices.Length; | |
bool hasOverlap = false; | |
if (ProjectionHasOverlap (AllAxes.Length, AllAxes, bVertsLength, bVertices, aVertsLength, aVertices)) | |
{ | |
hasOverlap = true; | |
} | |
else if (ProjectionHasOverlap (AllAxes.Length, AllAxes, aVertsLength, aVertices, bVertsLength, bVertices)) | |
{ | |
hasOverlap = true; | |
} | |
return hasOverlap; | |
} | |
/// Detects whether or not there is overlap on all separating axes. | |
private static bool ProjectionHasOverlap (int aAxesLength, Vector3[ ] aAxes, int bVertsLength, Vector3[ ] bVertices, int aVertsLength, Vector3[ ] aVertices) | |
{ | |
var penetrationAxes = new List<Vector3> ( ); | |
var penetrationAxesDistance = new List<float> ( ); | |
float minOverlap = float.PositiveInfinity; | |
Vector3 minOverlapAxis = Vector3.zero; | |
for (int i = 0; i < aAxesLength; i++) | |
{ | |
float bProjMin = float.MaxValue, aProjMin = float.MaxValue; | |
float bProjMax = float.MinValue, aProjMax = float.MinValue; | |
Vector3 axis = aAxes[i]; | |
// Handles the cross product = {0,0,0} case | |
if (aAxes[i] == Vector3.zero) return true; | |
for (int j = 0; j < bVertsLength; j++) | |
{ | |
float val = FindScalarProjection ((bVertices[j]), axis); | |
if (val < bProjMin) | |
{ | |
bProjMin = val; | |
} | |
if (val > bProjMax) | |
{ | |
bProjMax = val; | |
} | |
} | |
for (int j = 0; j < aVertsLength; j++) | |
{ | |
float val = FindScalarProjection ((aVertices[j]), axis); | |
if (val < aProjMin) | |
{ | |
aProjMin = val; | |
} | |
if (val > aProjMax) | |
{ | |
aProjMax = val; | |
} | |
} | |
float overlap = FindOverlap (aProjMin, aProjMax, bProjMin, bProjMax); | |
if (overlap < minOverlap) | |
{ | |
minOverlap = overlap; | |
minOverlapAxis = axis; | |
penetrationAxes.Add (axis); | |
penetrationAxesDistance.Add (overlap); | |
} | |
if (overlap <= 0) | |
{ | |
// Separating Axis Found Early Out | |
return false; | |
} | |
} | |
return true; // A penetration has been found | |
} | |
/// Calculates the scalar projection of one vector onto another, assumes normalised axes | |
private static float FindScalarProjection (Vector3 point, Vector3 axis) | |
{ | |
return Vector3.Dot (point, axis); | |
} | |
/// Calculates the amount of overlap of two intervals. | |
private static float FindOverlap (float astart, float aend, float bstart, float bend) | |
{ | |
if (astart < bstart) | |
{ | |
if (aend < bstart) | |
{ | |
return 0f; | |
} | |
return aend - bstart; | |
} | |
if (bend < astart) | |
{ | |
return 0f; | |
} | |
return bend - astart; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Short gif showing collision on separate-axis: https://i.imgur.com/LBVjItu.mp4