intersection.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. * Copyright (c) 2012-2015 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/taylor001/crown/blob/master/LICENSE
  4. */
  5. #include "intersection.h"
  6. #include "aabb.h"
  7. #include "plane.h"
  8. #include "sphere.h"
  9. #include "vector3.h"
  10. namespace crown
  11. {
  12. float ray_plane_intersection(const Vector3& from, const Vector3& dir, const Plane& p)
  13. {
  14. const float num = dot(from, p.n);
  15. const float den = dot(dir, p.n);
  16. if (fequal(den, 0.0f))
  17. return -1.0f;
  18. return (-p.d - num) / den;
  19. }
  20. float ray_disc_intersection(const Vector3& from, const Vector3& dir, const Vector3& center, float radius, const Vector3& normal)
  21. {
  22. Plane p = plane::from_point_and_normal(center, normal);
  23. const float t = ray_plane_intersection(from, dir, p);
  24. if (t == -1.0)
  25. return -1.0;
  26. const Vector3 intersection_point = from + dir * t;
  27. if (distance(intersection_point, center) < radius)
  28. return t;
  29. return -1.0;
  30. }
  31. float ray_sphere_intersection(const Vector3& from, const Vector3& dir, const Sphere& s)
  32. {
  33. const Vector3 v = s.c - from;
  34. const float b = dot(v, dir);
  35. const float det = (s.r * s.r) - dot(v, v) + (b * b);
  36. if (det < 0.0 || b < s.r)
  37. return -1.0f;
  38. return b - sqrtf(det);
  39. }
  40. // http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/picking-with-custom-ray-obb-function/
  41. float ray_obb_intersection(const Vector3& from, const Vector3& dir, const Matrix4x4& tm, const Vector3& half_extents)
  42. {
  43. float tmin = 0.0f;
  44. float tmax = 100000.0f;
  45. Vector3 obb_pos = vector3(tm.t.x, tm.t.y, tm.t.z);
  46. Vector3 delta = obb_pos - from;
  47. {
  48. const Vector3 xaxis = vector3(tm.x.x, tm.x.y, tm.x.z);
  49. float e = dot(xaxis, delta);
  50. float f = dot(dir, xaxis);
  51. if (fabs(f) > 0.001f)
  52. {
  53. float t1 = (e-half_extents.x)/f;
  54. float t2 = (e+half_extents.x)/f;
  55. if (t1>t2){
  56. float w=t1;t1=t2;t2=w;
  57. }
  58. if (t2 < tmax)
  59. tmax = t2;
  60. if (t1 > tmin)
  61. tmin = t1;
  62. if (tmax < tmin)
  63. return -1.0f;
  64. }
  65. else
  66. {
  67. if(-e-half_extents.x > 0.0f || -e+half_extents.x < 0.0f)
  68. return -1.0f;
  69. }
  70. }
  71. {
  72. const Vector3 yaxis = vector3(tm.y.x, tm.y.y, tm.y.z);
  73. float e = dot(yaxis, delta);
  74. float f = dot(dir, yaxis);
  75. if (fabs(f) > 0.001f){
  76. float t1 = (e-half_extents.y)/f;
  77. float t2 = (e+half_extents.y)/f;
  78. if (t1>t2){float w=t1;t1=t2;t2=w;}
  79. if (t2 < tmax)
  80. tmax = t2;
  81. if (t1 > tmin)
  82. tmin = t1;
  83. if (tmin > tmax)
  84. return -1.0f;
  85. }
  86. else
  87. {
  88. if(-e-half_extents.y > 0.0f || -e+half_extents.y < 0.0f)
  89. return -1.0f;
  90. }
  91. }
  92. {
  93. const Vector3 zaxis = vector3(tm.z.x, tm.z.y, tm.z.z);
  94. float e = dot(zaxis, delta);
  95. float f = dot(dir, zaxis);
  96. if (fabs(f) > 0.001f){
  97. float t1 = (e-half_extents.z)/f;
  98. float t2 = (e+half_extents.z)/f;
  99. if (t1>t2){float w=t1;t1=t2;t2=w;}
  100. if (t2 < tmax)
  101. tmax = t2;
  102. if (t1 > tmin)
  103. tmin = t1;
  104. if (tmin > tmax)
  105. return -1.0f;
  106. }
  107. else
  108. {
  109. if(-e-half_extents.z > 0.0f || -e+half_extents.z < 0.0f)
  110. return -1.0f;
  111. }
  112. }
  113. return tmin;
  114. }
  115. bool plane_3_intersection(const Plane& p1, const Plane& p2, const Plane& p3, Vector3& ip)
  116. {
  117. const Vector3& n1 = p1.n;
  118. const Vector3& n2 = p2.n;
  119. const Vector3& n3 = p3.n;
  120. const float den = -dot(cross(n1, n2), n3);
  121. if (fequal(den, 0.0f))
  122. return false;
  123. const float inv_den = 1.0f / den;
  124. Vector3 res = p1.d * cross(n2, n3) + p2.d * cross(n3, n1) + p3.d * cross(n1, n2);
  125. ip = res * inv_den;
  126. return true;
  127. }
  128. bool frustum_sphere_intersection(const Frustum& f, const Sphere& s)
  129. {
  130. if (plane::distance_to_point(f.left, s.c) < -s.r ||
  131. plane::distance_to_point(f.right, s.c) < -s.r)
  132. {
  133. return false;
  134. }
  135. if (plane::distance_to_point(f.bottom, s.c) < -s.r ||
  136. plane::distance_to_point(f.top, s.c) < -s.r)
  137. {
  138. return false;
  139. }
  140. if (plane::distance_to_point(f.near, s.c) < -s.r ||
  141. plane::distance_to_point(f.far, s.c) < -s.r)
  142. {
  143. return false;
  144. }
  145. return true;
  146. }
  147. bool frustum_box_intersection(const Frustum& f, const AABB& b)
  148. {
  149. uint8_t out;
  150. out = 0;
  151. if (plane::distance_to_point(f.left, aabb::vertex(b, 0)) < 0.0) out++;
  152. if (plane::distance_to_point(f.left, aabb::vertex(b, 1)) < 0.0) out++;
  153. if (plane::distance_to_point(f.left, aabb::vertex(b, 2)) < 0.0) out++;
  154. if (plane::distance_to_point(f.left, aabb::vertex(b, 3)) < 0.0) out++;
  155. if (plane::distance_to_point(f.left, aabb::vertex(b, 4)) < 0.0) out++;
  156. if (plane::distance_to_point(f.left, aabb::vertex(b, 5)) < 0.0) out++;
  157. if (plane::distance_to_point(f.left, aabb::vertex(b, 6)) < 0.0) out++;
  158. if (plane::distance_to_point(f.left, aabb::vertex(b, 7)) < 0.0) out++;
  159. // If all vertices are outside one face, then the box doesn't intersect the frustum
  160. if (out == 8) return false;
  161. out = 0;
  162. if (plane::distance_to_point(f.right, aabb::vertex(b, 0)) < 0.0) out++;
  163. if (plane::distance_to_point(f.right, aabb::vertex(b, 1)) < 0.0) out++;
  164. if (plane::distance_to_point(f.right, aabb::vertex(b, 2)) < 0.0) out++;
  165. if (plane::distance_to_point(f.right, aabb::vertex(b, 3)) < 0.0) out++;
  166. if (plane::distance_to_point(f.right, aabb::vertex(b, 4)) < 0.0) out++;
  167. if (plane::distance_to_point(f.right, aabb::vertex(b, 5)) < 0.0) out++;
  168. if (plane::distance_to_point(f.right, aabb::vertex(b, 6)) < 0.0) out++;
  169. if (plane::distance_to_point(f.right, aabb::vertex(b, 7)) < 0.0) out++;
  170. if (out == 8) return false;
  171. out = 0;
  172. if (plane::distance_to_point(f.bottom, aabb::vertex(b, 0)) < 0.0) out++;
  173. if (plane::distance_to_point(f.bottom, aabb::vertex(b, 1)) < 0.0) out++;
  174. if (plane::distance_to_point(f.bottom, aabb::vertex(b, 2)) < 0.0) out++;
  175. if (plane::distance_to_point(f.bottom, aabb::vertex(b, 3)) < 0.0) out++;
  176. if (plane::distance_to_point(f.bottom, aabb::vertex(b, 4)) < 0.0) out++;
  177. if (plane::distance_to_point(f.bottom, aabb::vertex(b, 5)) < 0.0) out++;
  178. if (plane::distance_to_point(f.bottom, aabb::vertex(b, 6)) < 0.0) out++;
  179. if (plane::distance_to_point(f.bottom, aabb::vertex(b, 7)) < 0.0) out++;
  180. if (out == 8) return false;
  181. out = 0;
  182. if (plane::distance_to_point(f.top, aabb::vertex(b, 0)) < 0.0) out++;
  183. if (plane::distance_to_point(f.top, aabb::vertex(b, 1)) < 0.0) out++;
  184. if (plane::distance_to_point(f.top, aabb::vertex(b, 2)) < 0.0) out++;
  185. if (plane::distance_to_point(f.top, aabb::vertex(b, 3)) < 0.0) out++;
  186. if (plane::distance_to_point(f.top, aabb::vertex(b, 4)) < 0.0) out++;
  187. if (plane::distance_to_point(f.top, aabb::vertex(b, 5)) < 0.0) out++;
  188. if (plane::distance_to_point(f.top, aabb::vertex(b, 6)) < 0.0) out++;
  189. if (plane::distance_to_point(f.top, aabb::vertex(b, 7)) < 0.0) out++;
  190. if (out == 8) return false;
  191. out = 0;
  192. if (plane::distance_to_point(f.near, aabb::vertex(b, 0)) < 0.0) out++;
  193. if (plane::distance_to_point(f.near, aabb::vertex(b, 1)) < 0.0) out++;
  194. if (plane::distance_to_point(f.near, aabb::vertex(b, 2)) < 0.0) out++;
  195. if (plane::distance_to_point(f.near, aabb::vertex(b, 3)) < 0.0) out++;
  196. if (plane::distance_to_point(f.near, aabb::vertex(b, 4)) < 0.0) out++;
  197. if (plane::distance_to_point(f.near, aabb::vertex(b, 5)) < 0.0) out++;
  198. if (plane::distance_to_point(f.near, aabb::vertex(b, 6)) < 0.0) out++;
  199. if (plane::distance_to_point(f.near, aabb::vertex(b, 7)) < 0.0) out++;
  200. if (out == 8) return false;
  201. out = 0;
  202. if (plane::distance_to_point(f.far, aabb::vertex(b, 0)) < 0.0) out++;
  203. if (plane::distance_to_point(f.far, aabb::vertex(b, 1)) < 0.0) out++;
  204. if (plane::distance_to_point(f.far, aabb::vertex(b, 2)) < 0.0) out++;
  205. if (plane::distance_to_point(f.far, aabb::vertex(b, 3)) < 0.0) out++;
  206. if (plane::distance_to_point(f.far, aabb::vertex(b, 4)) < 0.0) out++;
  207. if (plane::distance_to_point(f.far, aabb::vertex(b, 5)) < 0.0) out++;
  208. if (plane::distance_to_point(f.far, aabb::vertex(b, 6)) < 0.0) out++;
  209. if (plane::distance_to_point(f.far, aabb::vertex(b, 7)) < 0.0) out++;
  210. if (out == 8) return false;
  211. // If we are here, it is because either the box intersects or it is contained in the frustum
  212. return true;
  213. }
  214. } // namespace crown