dRay_CCylinder.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // Ripped from Magic Software
  2. #include "Include\dRay.h"
  3. #include "dxRay.h"
  4. int Find(const dVector3 Origin, dVector3 Direction, dReal Length, const dVector3 CCPos, const dMatrix3 CCRot, dReal CCRadius, dReal CCLength, dReal T[2]){
  5. dVector3 U, V, W;
  6. Decompose(CCRot, U, V, W);
  7. dVector3 CCOrigin;
  8. CCOrigin[0] = CCPos[0] - (W[0] * CCLength / 2);
  9. CCOrigin[1] = CCPos[1] - (W[1] * CCLength / 2);
  10. CCOrigin[2] = CCPos[2] - (W[2] * CCLength / 2);
  11. CCOrigin[3] = CCPos[3] - (W[3] * CCLength / 2);
  12. dVector3 D;
  13. D[0] = dDOT(U, Direction);
  14. D[1] = dDOT(V, Direction);
  15. D[2] = dDOT(W, Direction);
  16. dReal DMag = Length;
  17. dReal InvDMag = REAL(1.0) / DMag;
  18. dVector3 Diff;
  19. Diff[0] = Origin[0] - CCOrigin[0];
  20. Diff[1] = Origin[1] - CCOrigin[1];
  21. Diff[2] = Origin[2] - CCOrigin[2];
  22. Diff[3] = Origin[3] - CCOrigin[3];
  23. dVector3 P;
  24. P[0] = dDOT(U, Diff);
  25. P[1] = dDOT(V, Diff);
  26. P[2] = dDOT(W, Diff);
  27. dReal CCRadiusSq = CCRadius * CCRadius;
  28. dReal Epsilon = 1e-12f;
  29. if (dFabs(D[2]) >= REAL(1.0) - Epsilon){ // line is parallel to capsule axis
  30. dReal Discr = CCRadiusSq - P[0] * P[0] - P[1] * P[1];
  31. if (Discr >= REAL(0.0)){
  32. dReal Root = dSqrt(Discr);
  33. T[0] = (-P[2] + Root) * InvDMag;
  34. T[1] = (CCLength - P[2] + Root) * InvDMag;
  35. return 2;
  36. }
  37. else return 0;
  38. }
  39. // test intersection with infinite cylinder
  40. dReal A = D[0] * D[0] + D[1] * D[1];
  41. dReal B = P[0] * D[0] + P[1] * D[1];
  42. dReal C = P[0] * P[0] + P[1] * P[1] - CCRadiusSq;
  43. dReal Discr = B * B - A * C;
  44. if (Discr < REAL(0.0)){ // line does not intersect infinite cylinder
  45. return 0;
  46. }
  47. int Count = 0;
  48. if (Discr > REAL(0.0)){ // line intersects infinite cylinder in two places
  49. dReal Root = dSqrt(Discr);
  50. dReal Inv = REAL(1.0) / A;
  51. dReal TTemp = (-B - Root) * Inv;
  52. dReal Tmp = P[2] + TTemp * D[2];
  53. if (REAL(0.0) <= Tmp && Tmp <= CCLength){
  54. T[Count++] = TTemp * InvDMag;
  55. }
  56. TTemp = (-B + Root) * Inv;
  57. Tmp = P[2] + TTemp * D[2];
  58. if (REAL(0.0) <= Tmp && Tmp <= CCLength){
  59. T[Count++] = TTemp * InvDMag;
  60. }
  61. if (Count == 2){ // line intersects capsule wall in two places
  62. return 2;
  63. }
  64. }
  65. else{ // line is tangent to infinite cylinder
  66. dReal TTemp = -B / A;
  67. dReal Tmp = P[2] + TTemp * D[2];
  68. if (REAL(0.0) <= Tmp && Tmp <= CCLength){
  69. T[0] = TTemp * InvDMag;
  70. return 1;
  71. }
  72. }
  73. // test intersection with bottom hemisphere
  74. // fA = 1
  75. B += P[2] * D[2];
  76. C += P[2] * P[2];
  77. Discr = B * B - C;
  78. if (Discr > REAL(0.0)){
  79. dReal Root = dSqrt(Discr);
  80. dReal TTemp = -B - Root;
  81. dReal Tmp = P[2] + TTemp * D[2];
  82. if (Tmp <= REAL(0.0)){
  83. T[Count++] = TTemp * InvDMag;
  84. if (Count == 2){
  85. return 2;
  86. }
  87. }
  88. TTemp = -B + Root;
  89. Tmp = P[2] + TTemp * D[2];
  90. if (Tmp <= REAL(0.0)){
  91. T[Count++] = TTemp * InvDMag;
  92. if (Count == 2){
  93. return 2;
  94. }
  95. }
  96. }
  97. else if (Discr == REAL(0.0)){
  98. dReal TTemp = -B;
  99. dReal Tmp = P[2] + TTemp * D[2];
  100. if (Tmp <= REAL(0.0)){
  101. T[Count++] = TTemp * InvDMag;
  102. if (Count == 2){
  103. return 2;
  104. }
  105. }
  106. }
  107. // test intersection with top hemisphere
  108. // fA = 1
  109. B -= D[2] * CCLength;
  110. C += CCLength * (CCLength - REAL(2.0) * P[2]);
  111. Discr = B * B - C;
  112. if (Discr > REAL(0.0)){
  113. dReal Root = dSqrt(Discr);
  114. dReal TTemp = -B - Root;
  115. dReal Tmp = P[2] + TTemp * D[2];
  116. if (Tmp >= CCLength){
  117. T[Count++] = TTemp * InvDMag;
  118. if (Count == 2){
  119. return 2;
  120. }
  121. }
  122. TTemp = -B + Root;
  123. Tmp = P[2] + TTemp * D[2];
  124. if (Tmp >= CCLength){
  125. T[Count++] = TTemp * InvDMag;
  126. if (Count == 2){
  127. return 2;
  128. }
  129. }
  130. }
  131. else if (Discr == REAL(0.0)){
  132. dReal TTemp = -B;
  133. dReal Tmp = P[2] + TTemp * D[2];
  134. if (Tmp >= CCLength){
  135. T[Count++] = TTemp * InvDMag;
  136. if (Count == 2){
  137. return 2;
  138. }
  139. }
  140. }
  141. return Count;
  142. }
  143. int dCollideCCR(dxGeom* RayGeom, dxGeom* CCGeom, int Flags, dContactGeom* Contacts, int Stride){
  144. const dVector3& CCPos = *(const dVector3*)dGeomGetPosition(CCGeom);
  145. const dMatrix3& CCRot = *(const dMatrix3*)dGeomGetRotation(CCGeom);
  146. dReal CCRadius, CCLength;
  147. dGeomCCylinderGetParams(CCGeom, &CCRadius, &CCLength);
  148. dVector3 Origin, Direction;
  149. dGeomRayGet(RayGeom, Origin, Direction);
  150. dReal Length = dGeomRayGetLength(RayGeom);
  151. dReal T[2];
  152. int Count = Find(Origin, Direction, Length, CCPos, CCRot, CCRadius, CCLength, T);
  153. int ContactCount = 0;
  154. for (int i = 0; i < Count; i++){
  155. if (T[i] >= 0.0){
  156. dContactGeom* Contact = CONTACT(Flags, Contacts, ContactCount, Stride);
  157. Contact->pos[0] = Origin[0] + T[i] * Direction[0] * Length;
  158. Contact->pos[1] = Origin[1] + T[i] * Direction[1] * Length;
  159. Contact->pos[2] = Origin[2] + T[i] * Direction[2] * Length;
  160. Contact->pos[3] = Origin[3] + T[i] * Direction[3] * Length;
  161. //Contact->normal = 0;
  162. Contact->depth = 0.0f;
  163. Contact->g1 = RayGeom;
  164. Contact->g2 = CCGeom;
  165. ContactCount++;
  166. }
  167. }
  168. return ContactCount;
  169. }