GjkEpa.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. // Inspired by http://vec3.ca/gjk/implementation/
  6. #include <AnKi/Collision/GjkEpa.h>
  7. namespace anki
  8. {
  9. /// GJK support
  10. class GjkSupport
  11. {
  12. public:
  13. Vec4 m_v;
  14. Vec4 m_v0;
  15. Vec4 m_v1;
  16. Bool operator==(const GjkSupport& b) const
  17. {
  18. return m_v == b.m_v && m_v0 == b.m_v0 && m_v1 == b.m_v1;
  19. }
  20. };
  21. class GjkContext
  22. {
  23. public:
  24. const void* m_shape0;
  25. const void* m_shape1;
  26. GjkSupportCallback m_shape0Callback;
  27. GjkSupportCallback m_shape1Callback;
  28. Array<GjkSupport, 4> m_simplex;
  29. U32 m_count; ///< Simplex count
  30. Vec4 m_dir;
  31. };
  32. /// Helper of (axb)xa
  33. static Vec4 crossAba(const Vec4& a, const Vec4& b)
  34. {
  35. // We need to calculate the (axb)xa but we can use the triple product property ax(bxc) = b(a.c) - c(a.b) to make it
  36. // faster Vec4 out = b * (a.dot(a)) - a * (a.dot(b));
  37. return a.cross(b.cross(a));
  38. }
  39. static void support(const GjkContext& ctx, GjkSupport& support)
  40. {
  41. support.m_v0 = ctx.m_shape0Callback(ctx.m_shape0, ctx.m_dir);
  42. support.m_v1 = ctx.m_shape1Callback(ctx.m_shape1, -ctx.m_dir);
  43. support.m_v = support.m_v0 - support.m_v1;
  44. }
  45. static Bool update(GjkContext& ctx, const GjkSupport& a)
  46. {
  47. if(ctx.m_count == 2)
  48. {
  49. Vec4 ao = -a.m_v;
  50. // Compute the vectors parallel to the edges we'll test
  51. const Vec4 ab = ctx.m_simplex[1].m_v - a.m_v;
  52. const Vec4 ac = ctx.m_simplex[2].m_v - a.m_v;
  53. // Compute the triangle's normal
  54. const Vec4 abc = ab.cross(ac);
  55. // Compute a vector within the plane of the triangle, Pointing away from the edge ab
  56. const Vec4 abp = ab.cross(abc);
  57. if(abp.dot(ao) > 0.0)
  58. {
  59. // The origin lies outside the triangle, near the edge ab
  60. ctx.m_simplex[2] = ctx.m_simplex[1];
  61. ctx.m_simplex[1] = a;
  62. ctx.m_dir = crossAba(ab, ao);
  63. return false;
  64. }
  65. // Perform a similar test for the edge ac
  66. const Vec4 acp = abc.cross(ac);
  67. if(acp.dot(ao) > 0.0)
  68. {
  69. ctx.m_simplex[1] = a;
  70. ctx.m_dir = crossAba(ac, ao);
  71. return false;
  72. }
  73. // If we get here, then the origin must be within the triangle, but we care whether it is above or below it, so
  74. // test
  75. if(abc.dot(ao) > 0.0)
  76. {
  77. ctx.m_simplex[3] = ctx.m_simplex[2];
  78. ctx.m_simplex[2] = ctx.m_simplex[1];
  79. ctx.m_simplex[1] = a;
  80. ctx.m_dir = abc;
  81. }
  82. else
  83. {
  84. ctx.m_simplex[3] = ctx.m_simplex[1];
  85. ctx.m_simplex[1] = a;
  86. ctx.m_dir = -abc;
  87. }
  88. ctx.m_count = 3;
  89. // Again, need a tetrahedron to enclose the origin
  90. return false;
  91. }
  92. else if(ctx.m_count == 3)
  93. {
  94. const Vec4 ao = -a.m_v;
  95. Vec4 ab = ctx.m_simplex[1].m_v - a.m_v;
  96. Vec4 ac = ctx.m_simplex[2].m_v - a.m_v;
  97. Vec4 abc = ab.cross(ac);
  98. Vec4 ad, acd, adb;
  99. if(abc.dot(ao) > 0.0)
  100. {
  101. // In front of triangle ABC
  102. goto check_face;
  103. }
  104. ad = ctx.m_simplex[3].m_v - a.m_v;
  105. acd = ac.cross(ad);
  106. if(acd.dot(ao) > 0.0)
  107. {
  108. // In front of triangle ACD
  109. ctx.m_simplex[1] = ctx.m_simplex[2];
  110. ctx.m_simplex[2] = ctx.m_simplex[3];
  111. ab = ac;
  112. ac = ad;
  113. abc = acd;
  114. goto check_face;
  115. }
  116. adb = ad.cross(ab);
  117. if(adb.dot(ao) > 0.0)
  118. {
  119. // In front of triangle ADB
  120. ctx.m_simplex[2] = ctx.m_simplex[1];
  121. ctx.m_simplex[1] = ctx.m_simplex[3];
  122. ac = ab;
  123. ab = ad;
  124. abc = adb;
  125. goto check_face;
  126. }
  127. // Behind all three faces, the origin is in the tetrahedron, we're done
  128. ctx.m_simplex[0] = a;
  129. ctx.m_count = 4;
  130. return true;
  131. check_face:
  132. // We have a CCW wound triangle ABC the point is in front of this triangle
  133. // it is NOT "below" edge BC
  134. // it is NOT "above" the plane through A that's parallel to BC
  135. const Vec4 abp = ab.cross(abc);
  136. if(abp.dot(ao) > 0.0)
  137. {
  138. ctx.m_simplex[2] = ctx.m_simplex[1];
  139. ctx.m_simplex[1] = a;
  140. ctx.m_dir = crossAba(ab, ao);
  141. ctx.m_count = 2;
  142. return false;
  143. }
  144. const Vec4 acp = abc.cross(ac);
  145. if(acp.dot(ao) > 0.0)
  146. {
  147. ctx.m_simplex[1] = a;
  148. ctx.m_dir = crossAba(ac, ao);
  149. ctx.m_count = 2;
  150. return false;
  151. }
  152. ctx.m_simplex[3] = ctx.m_simplex[2];
  153. ctx.m_simplex[2] = ctx.m_simplex[1];
  154. ctx.m_simplex[1] = a;
  155. ctx.m_dir = abc;
  156. ctx.m_count = 3;
  157. return false;
  158. }
  159. ANKI_ASSERT(0);
  160. return true;
  161. }
  162. Bool gjkIntersection(const void* shape0, GjkSupportCallback shape0Callback, const void* shape1,
  163. GjkSupportCallback shape1Callback)
  164. {
  165. ANKI_ASSERT(shape0 && shape0Callback && shape1 && shape1Callback);
  166. GjkContext ctx;
  167. ctx.m_shape0 = shape0;
  168. ctx.m_shape1 = shape1;
  169. ctx.m_shape0Callback = shape0Callback;
  170. ctx.m_shape1Callback = shape1Callback;
  171. // Chose random direction
  172. ctx.m_dir = Vec4(1.0, 0.0, 0.0, 0.0);
  173. // Do cases 1, 2
  174. support(ctx, ctx.m_simplex[2]);
  175. if(ctx.m_simplex[2].m_v.dot(ctx.m_dir) < 0.0)
  176. {
  177. return false;
  178. }
  179. ctx.m_dir = -ctx.m_simplex[2].m_v;
  180. support(ctx, ctx.m_simplex[1]);
  181. if(ctx.m_simplex[1].m_v.dot(ctx.m_dir) < 0.0)
  182. {
  183. return false;
  184. }
  185. ctx.m_dir = crossAba(ctx.m_simplex[2].m_v - ctx.m_simplex[1].m_v, -ctx.m_simplex[1].m_v);
  186. ctx.m_count = 2;
  187. U iterations = 20;
  188. while(iterations--)
  189. {
  190. GjkSupport a;
  191. support(ctx, a);
  192. if(a.m_v.dot(ctx.m_dir) < 0.0)
  193. {
  194. return false;
  195. }
  196. if(update(ctx, a))
  197. {
  198. return true;
  199. }
  200. }
  201. return true;
  202. }
  203. } // end namespace anki