IntrRay3Sphere3.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/IntrIntervals.h>
  9. #include <Mathematics/IntrLine3Sphere3.h>
  10. #include <Mathematics/Ray.h>
  11. namespace WwiseGTE
  12. {
  13. template <typename Real>
  14. class TIQuery<Real, Ray3<Real>, Sphere3<Real>>
  15. {
  16. public:
  17. struct Result
  18. {
  19. bool intersect;
  20. };
  21. Result operator()(Ray3<Real> const& ray, Sphere3<Real> const& sphere)
  22. {
  23. // The sphere is (X-C)^T*(X-C)-1 = 0 and the line is X = P+t*D.
  24. // Substitute the line equation into the sphere equation to
  25. // obtain a quadratic equation Q(t) = t^2 + 2*a1*t + a0 = 0, where
  26. // a1 = D^T*(P-C) and a0 = (P-C)^T*(P-C)-1.
  27. Result result;
  28. Vector3<Real> diff = ray.origin - sphere.center;
  29. Real a0 = Dot(diff, diff) - sphere.radius * sphere.radius;
  30. if (a0 <= (Real)0)
  31. {
  32. // P is inside the sphere.
  33. result.intersect = true;
  34. return result;
  35. }
  36. // else: P is outside the sphere
  37. Real a1 = Dot(ray.direction, diff);
  38. if (a1 >= (Real)0)
  39. {
  40. result.intersect = false;
  41. return result;
  42. }
  43. // Intersection occurs when Q(t) has real roots.
  44. Real discr = a1 * a1 - a0;
  45. result.intersect = (discr >= (Real)0);
  46. return result;
  47. }
  48. };
  49. template <typename Real>
  50. class FIQuery<Real, Ray3<Real>, Sphere3<Real>>
  51. :
  52. public FIQuery<Real, Line3<Real>, Sphere3<Real>>
  53. {
  54. public:
  55. struct Result
  56. :
  57. public FIQuery<Real, Line3<Real>, Sphere3<Real>>::Result
  58. {
  59. // No additional information to compute.
  60. };
  61. Result operator()(Ray3<Real> const& ray, Sphere3<Real> const& sphere)
  62. {
  63. Result result;
  64. DoQuery(ray.origin, ray.direction, sphere, result);
  65. for (int i = 0; i < result.numIntersections; ++i)
  66. {
  67. result.point[i] = ray.origin + result.parameter[i] * ray.direction;
  68. }
  69. return result;
  70. }
  71. protected:
  72. void DoQuery(Vector3<Real> const& rayOrigin,
  73. Vector3<Real> const& rayDirection, Sphere3<Real> const& sphere,
  74. Result& result)
  75. {
  76. FIQuery<Real, Line3<Real>, Sphere3<Real>>::DoQuery(rayOrigin,
  77. rayDirection, sphere, result);
  78. if (result.intersect)
  79. {
  80. // The line containing the ray intersects the sphere; the
  81. // t-interval is [t0,t1]. The ray intersects the sphere as
  82. // long as [t0,t1] overlaps the ray t-interval [0,+infinity).
  83. std::array<Real, 2> rayInterval = { (Real)0, std::numeric_limits<Real>::max() };
  84. FIQuery<Real, std::array<Real, 2>, std::array<Real, 2>> iiQuery;
  85. auto iiResult = iiQuery(result.parameter, rayInterval);
  86. if (iiResult.intersect)
  87. {
  88. result.numIntersections = iiResult.numIntersections;
  89. result.parameter = iiResult.overlap;
  90. }
  91. else
  92. {
  93. result.intersect = false;
  94. result.numIntersections = 0;
  95. }
  96. }
  97. }
  98. };
  99. }