box.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. AABB3 boxUnion(AABB3 a, AABB3 b) {
  2. return (AABB3) {
  3. {fmin(a.min.x, b.min.x), fmin(a.min.y, b.min.y), fmin(a.min.z, b.min.z)},
  4. {fmax(a.max.x, b.max.x), fmax(a.max.y, b.max.y), fmax(a.max.z, b.max.z)}
  5. };
  6. }
  7. // this version has no branching, but only answers yes or no.
  8. // algorithm explanation here. hopefully my extrapolation into 3 dimensions is correct.
  9. // http://tavianator.com/fast-branchless-raybounding-box-intersections/
  10. int boxRayIntersectFast3p(const AABB3* b, const Ray3* r) {
  11. Vector3 t1, t2;
  12. float tmin, tmax;
  13. Vector3 id;
  14. vInv3p(&r->d, &id);
  15. t1.x = (b->min.x - r->o.x) * id.x;
  16. t2.x = (b->max.x - r->o.x) * id.x;
  17. tmin = fminf(t1.x, t2.x);
  18. tmax = fmaxf(t1.x, t2.x);
  19. t1.y = (b->min.y - r->o.y) * id.y;
  20. t2.y = (b->max.y - r->o.y) * id.y;
  21. tmin = fmaxf(tmin, fminf(t1.y, t2.y));
  22. tmax = fminf(tmax, fmaxf(t1.y, t2.y));
  23. t1.z = (b->min.z - r->o.z) * id.z;
  24. t2.z = (b->max.z - r->o.z) * id.z;
  25. tmin = fmaxf(tmin, fminf(t1.z, t2.z));
  26. tmax = fminf(tmax, fmaxf(t1.z, t2.z));
  27. return tmax >= tmin && tmax > 0.0f;
  28. }
  29. // this version has no branching, but only answers yes or no.
  30. // http://tavianator.com/fast-branchless-raybounding-box-intersections/
  31. int boxRayIntersectFast2(const AABB2* b, const Ray2* r) {
  32. Vector2 t1, t2;
  33. float tmin, tmax;
  34. Vector2 id;
  35. vInv2p(&r->d, &id);
  36. t1.x = (b->min.x - r->o.x) * id.x;
  37. t2.x = (b->max.x - r->o.x) * id.x;
  38. tmin = fminf(t1.x, t2.x);
  39. tmax = fmaxf(t1.x, t2.x);
  40. t1.y = (b->min.y - r->o.y) * id.y;
  41. t2.y = (b->max.y - r->o.y) * id.y;
  42. // tmin = fmaxf(tmin, fminf(t1.y, t2.y));
  43. tmax = fminf(tmax, fmaxf(t1.y, t2.y));
  44. return tmax >= tmin && tmax > 0.0f;
  45. }
  46. // this version gives the point of intersection as well as distance
  47. // algorithm explanation here. hopefully my extrapolation into 3 dimensions is correct.
  48. // http://tavianator.com/fast-branchless-raybounding-box-intersections/
  49. int boxRayIntersect3p(const AABB3* b, const Ray3* r, Vector3* ipoint, float* idist) {
  50. Vector3 t1, t2, id;
  51. float tmin, tmax;
  52. vInv3p(&r->d, &id);
  53. t1.x = (b->min.x - r->o.x) * id.x;
  54. t2.x = (b->max.x - r->o.x) * id.x;
  55. tmin = fminf(t1.x, t2.x);
  56. tmax = fmaxf(t1.x, t2.x);
  57. t1.y = (b->min.y - r->o.y) * id.y;
  58. t2.y = (b->max.y - r->o.y) * id.y;
  59. tmin = fmaxf(tmin, fminf(t1.y, t2.y));
  60. tmax = fminf(tmax, fmaxf(t1.y, t2.y));
  61. t1.z = (b->min.z - r->o.z) * id.z;
  62. t2.z = (b->max.z - r->o.z) * id.z;
  63. tmin = fmaxf(tmin, fminf(t1.z, t2.z));
  64. tmax = fminf(tmax, fmaxf(t1.z, t2.z));
  65. if(tmax < tmin) return C3DLAS_DISJOINT;
  66. if(idist) *idist = tmin;
  67. if(ipoint) {
  68. ipoint->x = r->o.x + (r->d.x * tmin);
  69. ipoint->y = r->o.y + (r->d.y * tmin);
  70. ipoint->z = r->o.z + (r->d.z * tmin);
  71. }
  72. return C3DLAS_INTERSECT;
  73. }
  74. // this version gives the point of intersection as well as distance
  75. // algorithm explanation here. hopefully my extrapolation into 3 dimensions is correct.
  76. // http://tavianator.com/fast-branchless-raybounding-box-intersections/
  77. int intersectBoxLine3p(const AABB3* b, const Line3* l, Vector3* ipoint, float* idist) {
  78. Vector3 t1, t2, id;
  79. float tmin, tmax;
  80. Vector3 o = l->start;
  81. Vector3 d = vNorm3(vSub3(l->end, l->start));
  82. id = vInv3(d);
  83. t1.x = (b->min.x - o.x) * id.x;
  84. t2.x = (b->max.x - o.x) * id.x;
  85. tmin = fminf(t1.x, t2.x);
  86. tmax = fmaxf(t1.x, t2.x);
  87. t1.y = (b->min.y - o.y) * id.y;
  88. t2.y = (b->max.y - o.y) * id.y;
  89. tmin = fmaxf(tmin, fminf(t1.y, t2.y));
  90. tmax = fminf(tmax, fmaxf(t1.y, t2.y));
  91. t1.z = (b->min.z - o.z) * id.z;
  92. t2.z = (b->max.z - o.z) * id.z;
  93. tmin = fmaxf(tmin, fminf(t1.z, t2.z));
  94. tmax = fminf(tmax, fmaxf(t1.z, t2.z));
  95. if(tmax < tmin) return C3DLAS_DISJOINT;
  96. if(idist) *idist = tmin;
  97. if(ipoint) {
  98. ipoint->x = o.x + (d.x * tmin);
  99. ipoint->y = o.y + (d.y * tmin);
  100. ipoint->z = o.z + (d.z * tmin);
  101. }
  102. return C3DLAS_INTERSECT;
  103. }
  104. int intersectBoxLine3(AABB3 b, Line3 l, Vector3* ipoint, float* idist) {
  105. return intersectBoxLine3p(&b, &l, ipoint, idist);
  106. }
  107. bool boxContainsPoint3(AABB3 b, Vector3 p) {
  108. return b.min.x <= p.x && b.max.x >= p.x
  109. && b.min.y <= p.y && b.max.y >= p.y
  110. && b.min.z <= p.z && b.max.z >= p.z;
  111. }
  112. int boxClipRay(AABB3* b, Ray3 r, Line3* out) {
  113. vec3 norms[] = {
  114. {-1,0,0},
  115. {0,-1,0},
  116. {0,0,-1},
  117. {1,0,0},
  118. {0,1,0},
  119. {0,0,1},
  120. };
  121. f32 ds[] = {
  122. b->max.x,
  123. b->max.y,
  124. b->max.z,
  125. -b->min.x,
  126. -b->min.y,
  127. -b->min.z,
  128. };
  129. f32 mint = FLT_MAX;
  130. f32 maxt = 0;
  131. for(int i = 0; i < 6; i++) {
  132. float d = vDot3(norms[i], r.d);
  133. if(fabs(d) < FLT_CMP_EPSILON) continue; // parallel
  134. float t = (vDot3(norms[i], r.o) + ds[i]) / -d;
  135. vec3 pt = vAdd3(r.o, vScale3(r.d, t));
  136. switch(i) { // clamp to the other planes
  137. case 0:
  138. case 3:
  139. if(pt.y > b->max.y || pt.y < b->min.y) continue;
  140. if(pt.z > b->max.z || pt.z < b->min.z) continue;
  141. break;
  142. case 1:
  143. case 4:
  144. if(pt.x > b->max.x || pt.x < b->min.x) continue;
  145. if(pt.z > b->max.z || pt.z < b->min.z) continue;
  146. break;
  147. case 2:
  148. case 5:
  149. if(pt.x > b->max.x || pt.x < b->min.x) continue;
  150. if(pt.y > b->max.y || pt.y < b->min.y) continue;
  151. break;
  152. }
  153. mint = fminf(mint, t);
  154. maxt = fmaxf(maxt, t);
  155. }
  156. mint = fmaxf(0, mint); // clamp to ray origin
  157. if(maxt != 0) {
  158. out->a = vAdd3(r.o, vScale3(r.d, mint));
  159. out->b = vAdd3(r.o, vScale3(r.d, maxt));
  160. return C3DLAS_INTERSECT;
  161. }
  162. else {
  163. return C3DLAS_DISJOINT;
  164. }
  165. }
  166. float distPoint2Rect2(Vector2 a, Quad2 q) {
  167. // check the lines around the outside
  168. float d[4];
  169. for(int i = 0; i < 4; i++) {
  170. d[i] = vDistPointLine2(a, (Line2){q.v[i], q.v[(i + 1) % 4]});
  171. if(d[i] == 0) return 0;
  172. }
  173. // check if the line is entirely inside the rectangle,
  174. // if one point (and therefore both points) is inside the quad
  175. vec2 ab = vSub(q.v[1], q.v[0]);
  176. vec2 am = vSub(a, q.v[0]);
  177. vec2 bc = vSub(q.v[2], q.v[1]);
  178. vec2 bm = vSub(a, q.v[1]);
  179. float dabam = vDot(ab, am);
  180. if(dabam <= 0) {
  181. float dabab = vDot(ab, ab);
  182. if(dabam <= dabab) {
  183. float dbcbm = vDot(bc, bm);
  184. if(0 <= dbcbm) {
  185. float dbcbc = vDot(bc, bc);
  186. if(dbcbm <= dbcbc) return 0;
  187. }
  188. }
  189. }
  190. // the line is outside; one of the corners is closest, find which one
  191. return MIN(MIN(d[0], d[1]), MIN(d[2], d[3]));
  192. }
  193. int intersectPoint2Rect2(vec2 a, Quad2 q) {
  194. vec2 ab = vSub(q.v[1], q.v[0]);
  195. vec2 am = vSub(a, q.v[0]);
  196. vec2 bc = vSub(q.v[2], q.v[1]);
  197. vec2 bm = vSub(a, q.v[1]);
  198. float dabam = vDot(ab, am);
  199. if(dabam <= 0) {
  200. float dabab = vDot(ab, ab);
  201. if(dabam <= dabab) {
  202. float dbcbm = vDot(bc, bm);
  203. if(0 <= dbcbm) {
  204. float dbcbc = vDot(bc, bc);
  205. if(dbcbm <= dbcbc) return C3DLAS_INTERSECT;
  206. }
  207. }
  208. }
  209. return C3DLAS_DISJOINT;
  210. }
  211. int intersectRect2Rect2(Quad2 a, Quad2 b) {
  212. // early rejection test based on distance between centers
  213. vec2 ca = {0, 0};
  214. vec2 cb = {0, 0};
  215. for(int i = 0; i < 4; i++) {
  216. ca = vAdd(ca, a.v[i]);
  217. cb = vAdd(cb, b.v[i]);
  218. }
  219. ca = vScale(ca, .25f);
  220. cb = vScale(cb, .25f);
  221. float radSq = vDistSq(ca, a.v[0]) + vDistSq(cb, b.v[0]);
  222. if(radSq > vDistSq(ca, cb)) return C3DLAS_DISJOINT;
  223. // Check if any of the points are inside the other rectangle
  224. // This handles situations where one rect is fully contained in the other
  225. for(int i = 0; i < 4; i++) {
  226. if(C3DLAS_INTERSECT == intersectPoint2Rect2(a.v[i], b)) return C3DLAS_INTERSECT;
  227. if(C3DLAS_INTERSECT == intersectPoint2Rect2(b.v[i], a)) return C3DLAS_INTERSECT;
  228. }
  229. // check all the lines against all the other lines
  230. for(int i = 0; i < 4; i++)
  231. for(int j = 0; j < 4; j++) {
  232. if(intersectLine2Line2((Line2){a.v[i], a.v[(i + 1) % 4]}, (Line2){b.v[j], b.v[(j + 1) % 4]}) == C3DLAS_INTERSECT) return C3DLAS_INTERSECT;
  233. }
  234. return C3DLAS_DISJOINT;
  235. }