OPC_SphereTriOverlap.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // This is collision detection. If you do another distance test for collision *response*,
  2. // if might be useful to simply *skip* the test below completely, and report a collision.
  3. // - if sphere-triangle overlap, result is ok
  4. // - if they don't, we'll discard them during collision response with a similar test anyway
  5. // Overall this approach should run faster.
  6. // Original code by David Eberly in Magic.
  7. BOOL SphereCollider::SphereTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2)
  8. {
  9. // Stats
  10. mNbVolumePrimTests++;
  11. // Early exit if one of the vertices is inside the sphere
  12. Point kDiff = vert2 - mCenter;
  13. float fC = kDiff.SquareMagnitude();
  14. if(fC <= mRadius2) return TRUE;
  15. kDiff = vert1 - mCenter;
  16. fC = kDiff.SquareMagnitude();
  17. if(fC <= mRadius2) return TRUE;
  18. kDiff = vert0 - mCenter;
  19. fC = kDiff.SquareMagnitude();
  20. if(fC <= mRadius2) return TRUE;
  21. // Else do the full distance test
  22. Point TriEdge0 = vert1 - vert0;
  23. Point TriEdge1 = vert2 - vert0;
  24. //Point kDiff = vert0 - mCenter;
  25. float fA00 = TriEdge0.SquareMagnitude();
  26. float fA01 = TriEdge0 | TriEdge1;
  27. float fA11 = TriEdge1.SquareMagnitude();
  28. float fB0 = kDiff | TriEdge0;
  29. float fB1 = kDiff | TriEdge1;
  30. //float fC = kDiff.SquareMagnitude();
  31. float fDet = fabsf(fA00*fA11 - fA01*fA01);
  32. float u = fA01*fB1-fA11*fB0;
  33. float v = fA01*fB0-fA00*fB1;
  34. float SqrDist;
  35. if(u + v <= fDet)
  36. {
  37. if(u < 0.0f)
  38. {
  39. if(v < 0.0f) // region 4
  40. {
  41. if(fB0 < 0.0f)
  42. {
  43. // v = 0.0f;
  44. if(-fB0>=fA00) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; }
  45. else { u = -fB0/fA00; SqrDist = fB0*u+fC; }
  46. }
  47. else
  48. {
  49. // u = 0.0f;
  50. if(fB1>=0.0f) { /*v = 0.0f;*/ SqrDist = fC; }
  51. else if(-fB1>=fA11) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; }
  52. else { v = -fB1/fA11; SqrDist = fB1*v+fC; }
  53. }
  54. }
  55. else // region 3
  56. {
  57. // u = 0.0f;
  58. if(fB1>=0.0f) { /*v = 0.0f;*/ SqrDist = fC; }
  59. else if(-fB1>=fA11) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; }
  60. else { v = -fB1/fA11; SqrDist = fB1*v+fC; }
  61. }
  62. }
  63. else if(v < 0.0f) // region 5
  64. {
  65. // v = 0.0f;
  66. if(fB0>=0.0f) { /*u = 0.0f;*/ SqrDist = fC; }
  67. else if(-fB0>=fA00) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; }
  68. else { u = -fB0/fA00; SqrDist = fB0*u+fC; }
  69. }
  70. else // region 0
  71. {
  72. // minimum at interior point
  73. if(fDet==0.0f)
  74. {
  75. // u = 0.0f;
  76. // v = 0.0f;
  77. SqrDist = MAX_FLOAT;
  78. }
  79. else
  80. {
  81. float fInvDet = 1.0f/fDet;
  82. u *= fInvDet;
  83. v *= fInvDet;
  84. SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC;
  85. }
  86. }
  87. }
  88. else
  89. {
  90. float fTmp0, fTmp1, fNumer, fDenom;
  91. if(u < 0.0f) // region 2
  92. {
  93. fTmp0 = fA01 + fB0;
  94. fTmp1 = fA11 + fB1;
  95. if(fTmp1 > fTmp0)
  96. {
  97. fNumer = fTmp1 - fTmp0;
  98. fDenom = fA00-2.0f*fA01+fA11;
  99. if(fNumer >= fDenom)
  100. {
  101. // u = 1.0f;
  102. // v = 0.0f;
  103. SqrDist = fA00+2.0f*fB0+fC;
  104. }
  105. else
  106. {
  107. u = fNumer/fDenom;
  108. v = 1.0f - u;
  109. SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC;
  110. }
  111. }
  112. else
  113. {
  114. // u = 0.0f;
  115. if(fTmp1 <= 0.0f) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; }
  116. else if(fB1 >= 0.0f) { /*v = 0.0f;*/ SqrDist = fC; }
  117. else { v = -fB1/fA11; SqrDist = fB1*v+fC; }
  118. }
  119. }
  120. else if(v < 0.0f) // region 6
  121. {
  122. fTmp0 = fA01 + fB1;
  123. fTmp1 = fA00 + fB0;
  124. if(fTmp1 > fTmp0)
  125. {
  126. fNumer = fTmp1 - fTmp0;
  127. fDenom = fA00-2.0f*fA01+fA11;
  128. if(fNumer >= fDenom)
  129. {
  130. // v = 1.0f;
  131. // u = 0.0f;
  132. SqrDist = fA11+2.0f*fB1+fC;
  133. }
  134. else
  135. {
  136. v = fNumer/fDenom;
  137. u = 1.0f - v;
  138. SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC;
  139. }
  140. }
  141. else
  142. {
  143. // v = 0.0f;
  144. if(fTmp1 <= 0.0f) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; }
  145. else if(fB0 >= 0.0f) { /*u = 0.0f;*/ SqrDist = fC; }
  146. else { u = -fB0/fA00; SqrDist = fB0*u+fC; }
  147. }
  148. }
  149. else // region 1
  150. {
  151. fNumer = fA11 + fB1 - fA01 - fB0;
  152. if(fNumer <= 0.0f)
  153. {
  154. // u = 0.0f;
  155. // v = 1.0f;
  156. SqrDist = fA11+2.0f*fB1+fC;
  157. }
  158. else
  159. {
  160. fDenom = fA00-2.0f*fA01+fA11;
  161. if(fNumer >= fDenom)
  162. {
  163. // u = 1.0f;
  164. // v = 0.0f;
  165. SqrDist = fA00+2.0f*fB0+fC;
  166. }
  167. else
  168. {
  169. u = fNumer/fDenom;
  170. v = 1.0f - u;
  171. SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC;
  172. }
  173. }
  174. }
  175. }
  176. return fabsf(SqrDist) < mRadius2;
  177. }