ray.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * Copyright (c), Recep Aslantas.
  3. *
  4. * MIT License (MIT), http://opensource.org/licenses/MIT
  5. * Full license can be found in the LICENSE file
  6. */
  7. /*
  8. Functions:
  9. CGLM_INLINE bool glm_ray_triangle(vec3 origin,
  10. vec3 direction,
  11. vec3 v0,
  12. vec3 v1,
  13. vec3 v2,
  14. float *d);
  15. CGLM_INLINE bool glm_ray_sphere(vec3 origin,
  16. vec3 dir,
  17. vec4 s,
  18. float * __restrict t1,
  19. float * __restrict t2)
  20. CGLM_INLINE void glm_ray_at(vec3 orig, vec3 dir, float t, vec3 point);
  21. */
  22. #ifndef cglm_ray_h
  23. #define cglm_ray_h
  24. #include "vec3.h"
  25. /*!
  26. * @brief Möller–Trumbore ray-triangle intersection algorithm
  27. *
  28. * @param[in] origin origin of ray
  29. * @param[in] direction direction of ray
  30. * @param[in] v0 first vertex of triangle
  31. * @param[in] v1 second vertex of triangle
  32. * @param[in] v2 third vertex of triangle
  33. * @param[in, out] d distance to intersection
  34. * @return whether there is intersection
  35. */
  36. CGLM_INLINE
  37. bool
  38. glm_ray_triangle(vec3 origin,
  39. vec3 direction,
  40. vec3 v0,
  41. vec3 v1,
  42. vec3 v2,
  43. float *d) {
  44. vec3 edge1, edge2, p, t, q;
  45. float det, inv_det, u, v, dist;
  46. const float epsilon = 0.000001f;
  47. glm_vec3_sub(v1, v0, edge1);
  48. glm_vec3_sub(v2, v0, edge2);
  49. glm_vec3_cross(direction, edge2, p);
  50. det = glm_vec3_dot(edge1, p);
  51. if (det > -epsilon && det < epsilon)
  52. return false;
  53. inv_det = 1.0f / det;
  54. glm_vec3_sub(origin, v0, t);
  55. u = inv_det * glm_vec3_dot(t, p);
  56. if (u < 0.0f || u > 1.0f)
  57. return false;
  58. glm_vec3_cross(t, edge1, q);
  59. v = inv_det * glm_vec3_dot(direction, q);
  60. if (v < 0.0f || u + v > 1.0f)
  61. return false;
  62. dist = inv_det * glm_vec3_dot(edge2, q);
  63. if (d)
  64. *d = dist;
  65. return dist > epsilon;
  66. }
  67. /*!
  68. * @brief ray sphere intersection
  69. *
  70. * returns false if there is no intersection if true:
  71. *
  72. * - t1 > 0, t2 > 0: ray intersects the sphere at t1 and t2 both ahead of the origin
  73. * - t1 < 0, t2 > 0: ray starts inside the sphere, exits at t2
  74. * - t1 < 0, t2 < 0: no intersection ahead of the ray ( returns false )
  75. * - the caller can check if the intersection points (t1 and t2) fall within a
  76. * specific range (for example, tmin < t1, t2 < tmax) to determine if the
  77. * intersections are within a desired segment of the ray
  78. *
  79. * @param[in] origin ray origin
  80. * @param[out] dir normalized ray direction
  81. * @param[in] s sphere [center.x, center.y, center.z, radii]
  82. * @param[in] t1 near point1 (closer to origin)
  83. * @param[in] t2 far point2 (farther from origin)
  84. *
  85. * @returns whether there is intersection
  86. */
  87. CGLM_INLINE
  88. bool
  89. glm_ray_sphere(vec3 origin,
  90. vec3 dir,
  91. vec4 s,
  92. float * __restrict t1,
  93. float * __restrict t2) {
  94. vec3 dp;
  95. float r2, ddp, dpp, dscr, q, tmp, _t1, _t2;
  96. glm_vec3_sub(s, origin, dp);
  97. ddp = glm_vec3_dot(dir, dp);
  98. dpp = glm_vec3_norm2(dp);
  99. /* compute the remedy term for numerical stability */
  100. glm_vec3_mulsubs(dir, ddp, dp); /* dp: remedy term */
  101. r2 = s[3] * s[3];
  102. dscr = r2 - glm_vec3_norm2(dp);
  103. if (dscr < 0.0f) {
  104. /* no intersection */
  105. return false;
  106. }
  107. dscr = sqrtf(dscr);
  108. q = (ddp >= 0.0f) ? (ddp + dscr) : (ddp - dscr);
  109. /*
  110. include Press, William H., Saul A. Teukolsky,
  111. William T. Vetterling, and Brian P. Flannery,
  112. "Numerical Recipes in C," Cambridge University Press, 1992.
  113. */
  114. _t1 = q;
  115. _t2 = (dpp - r2) / q;
  116. /* adjust t1 and t2 to ensure t1 is the closer intersection */
  117. if (_t1 > _t2) {
  118. tmp = _t1;
  119. _t1 = _t2;
  120. _t2 = tmp;
  121. }
  122. *t1 = _t1;
  123. *t2 = _t2;
  124. /* check if the closest intersection (t1) is behind the ray's origin */
  125. if (_t1 < 0.0f && _t2 < 0.0f) {
  126. /* both intersections are behind the ray, no visible intersection */
  127. return false;
  128. }
  129. return true;
  130. }
  131. /*!
  132. * @brief point using t by 𝐏(𝑡)=𝐀+𝑡𝐛
  133. *
  134. * @param[in] orig origin of ray
  135. * @param[in] dir direction of ray
  136. * @param[in] t parameter
  137. * @param[out] point point at t
  138. */
  139. CGLM_INLINE
  140. void
  141. glm_ray_at(vec3 orig, vec3 dir, float t, vec3 point) {
  142. vec3 dst;
  143. glm_vec3_scale(dir, t, dst);
  144. glm_vec3_add(orig, dst, point);
  145. }
  146. #endif