Reference: http://www.dyn4j.org/2010/04/gjk-gilbert-johnson-keerthi/
As with the SAT (split axis) method, the GJK can determine whether two convex shapes overlap. Compared to the SAT, GJK is able to handle all the graphics in the same way, while the SAT determines that two different shapes (polygon-polygon/polygon-circle/Circle-circle) are treated differently.
GJK principle: If the Minkowski of two convex graphs contains the origin, then these two graphs overlap. So the question turns into judging whether a Minkowski graph contains the origin.
Minkowski the points in the two graphs as vectors, adding the vector points of the two graphs together to get a new shape.
Minkowski the vector of one of the graphs is reversed, which is equivalent to the reversal of the origin, and then the two figure for Minkowski.
GJK does not directly ask for two graphs of the Minkowski, but through the following auxiliary function, enter a different search direction, return to Minkowski a point on the difference, iteratively using these points to form a sub-shape, to determine whether the child shape contains the origin point.
Proc Getsupportpoint (S1:sprite2d, S2:sprite2d, dir:vector2d): vector2d = let invM1 = S1.invmatrix invM2 = s 2.invMatrix v1 = S1.matrix * S1.graph.getFarthestPointInDirection (invM1 * dir-invm1 * VECTOR2D (x:0, y:0)) v2 = S2.matrix * S2.graph.getFarthestPointInDirection (INVM2 * dir.negate ()-invM2 * VECTOR2D (x:0, y:0)) return V1-v2
The above function returns the farthest point of the Minkowski graph in one direction. This first transforms the search direction into the object space, and the object finds itself at the farthest point in the search direction, then transforms it back into world space.
The function to find the farthest point of the polygon in the lookup direction is as follows. Distance is judged based on the size of the projection by projecting all vertices into the lookup direction.
Method getfarthestpointindirection* (Self:polygon, direction:vector2d): vector2d = var curr = self[0] Bestprojection:float32 = Curr * Direction projection:float32 result = Curr for i in 1..self.len-1: Curr = Self[i] projection = Curr * Direction if projection > bestprojection: bestprojection = projection result = Curr
Circular. Norm is the unit vector.
Method getfarthestpointindirection* (Self:circle, direction:vector2d): vector2d = direction.norm () * Self.radius
GJK each generated sub-shape is a simplex (simplex). The simplex is a triangle at 2D and a tetrahedron under 3D.
The GJK pseudo-code given on the wiki is as follows:
function gjk_intersection (shape p, shape Q, vector initial_axis): vector A = support (P, Initial_axis)-Support (q ,-initial_axis) simplex s = {a} vector D =-a loop: a = Support (P, D)-Support (q,-D) if Dot (A, D) < 0: reject s = s∪a s, D, Contains_origin = Nearestsimplex (s) if Contains_origin: Accept
The specific implementation of the individual is as follows:
Suppose Minkowski's shape is elliptical.
The first point A on the simplex is found by using the Getsupportpoint function with an initial lookup direction. At this point, the vector OA is projected onto the find direction vector. If the projection is negative, then the Origin o must be outside the Minkowski (on the right side of the red dashed line that is over a), which determines that the two graphic does not overlap. Each time a single vertex is found, it is so judged.
Then, reverse the lookup direction (or use the AO direction) to find the second point B. Then judge that the origin is not on the left side of the dotted line B.
Connect A and B to find a vector perpendicular to AB in the direction of the AO as the search direction, and get the point C. Now, where the origin may be, there are three red dashed lines surrounded by a quad with AB.
The vector acperp perpendicular to the ab direction of the AC is obtained, and the vector bcperp that is perpendicular to the BC is directed toward the BA direction.
The AO is projected onto the acperp, and if the projection is negative, then the origin is not in the simplex. At this time discard the point at the farthest from the origin of B, with point A and point C as the new point a ' and point B ', repeat the above process.
The OB is projected onto the bcperp, as above to determine whether the origin is inside or outside the BC. If it is outside the BC, discard the one farthest from the origin, using B and C as the new points A and B, repeating the above process.
If the two projections are non-negative, then the origin is within the simplex ABC, and the two graphs are judged to overlap.
Proc isintersect* (S1, s2:sprite2d): bool = var dir = vector2d (x:1, y:0) Simplexa, Simplexb, Simplexc: vector2d Simplexa = getsupportpoint (S1, S2, dir) if Simplexa * dir < 0:return false dir = Simplexa.negate () Simplexb = Getsupportpoint (S1, S2, dir) if Simplexb * Dir < 0:return false let AO = Simplexa.negate () AB = Simplexb-simplexa dir = tripleproduct (AB, AO, ab) while True:simplexc = Getsupportpoint (S1, S2, DIR) If Simplexc * Dir < 0:return false let BA = Simplexa-simplexb AC = simplexc-simplexa BC = Simplexc-simplexb acperp = Tripleproduct (AC, ba.negate (), AC) bcperp = tripleproduct (BC, BA, BC) if ACPERP * simplexa > 0:SIMPLEXB = Simplexc dir = acperp.negate () elif bcperp * simplexb > 0:simplexa = simplexc dir = bcperp. Negate () Else:reTurn true
The upper tripleproduct is a continuous two-pronged multiplication, and the axbxa will get a vector perpendicular to a in the direction of B.
Proc tripleproduct* (v1, v2, v3:vector2d): vector2d = result.x =-(v1.x * V2.Y-V1.Y * v2.x) * v3.y Result.y = (v 1.x * V2.Y-V1.Y * v2.x) * v3.x
GJK (Gilbert–johnson–keerthi) to determine if arbitrary convex graphs overlap