Cry_GeoIntersect.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. // Description : Common intersection-tests
  9. #pragma once
  10. #include <Cry_Geo.h>
  11. namespace Intersect {
  12. inline bool Ray_Plane(const Ray& ray, const Plane_tpl<f32>& plane, Vec3& output, bool bSingleSidePlane = true)
  13. {
  14. float cosine = plane.n | ray.direction;
  15. //REJECTION 1: if "line-direction" is perpendicular to "plane-normal", an intersection is not possible! That means ray is parallel
  16. // to the plane
  17. //REJECTION 2: if bSingleSidePlane == true we deal with single-sided planes. That means
  18. // if "line-direction" is pointing in the same direction as "the plane-normal",
  19. // an intersection is not possible!
  20. if ((cosine == 0.0f) || // normal is orthogonal to vector, cant intersect
  21. (bSingleSidePlane && (cosine > 0.0f))) // we are trying to find an intersection in the same direction as the plane normal
  22. {
  23. return false;
  24. }
  25. float numer = plane.DistFromPlane(ray.origin);
  26. float fLength = -numer / cosine;
  27. output = ray.origin + (ray.direction * fLength);
  28. //skip, if cutting-point is "behind" ray.origin
  29. if (fLength < 0.0f)
  30. {
  31. return false;
  32. }
  33. return true; //intersection occurred
  34. }
  35. /*
  36. * calculates intersection between a ray and a triangle.
  37. * IMPORTANT: this is a single-sided intersection test. That means its not sufficient
  38. * that the triangle and rayt overlap, its also important that the triangle
  39. * is "visible" when you from the origin along the ray-direction.
  40. *
  41. * If you need a double-sided test, you'll have to call this function twice with
  42. * reversed order of triangle vertices.
  43. *
  44. * return values
  45. * if there is an intertection the functions return "true" and stores the
  46. * 3d-intersection point in "output". if the function returns "false" the value in
  47. * "output" is undefined
  48. */
  49. inline bool Ray_Triangle(const Ray& ray, const Vec3& v0, const Vec3& v1, const Vec3& v2, Vec3& output)
  50. {
  51. const float Epsilon = 0.0000001f;
  52. Vec3 edgeA = v1 - v0;
  53. Vec3 edgeB = v2 - v0;
  54. Vec3 dir = ray.direction;
  55. Vec3 p = dir.Cross(edgeA);
  56. Vec3 t = ray.origin - v0;
  57. Vec3 q = t.Cross(edgeB);
  58. float dot = edgeB.Dot(p);
  59. float u = t.Dot(p);
  60. float v = dir.Dot(q);
  61. float DotGreaterThanEpsilon = dot - Epsilon;
  62. float VGreaterEqualThanZero = v;
  63. float UGreaterEqualThanZero = u;
  64. float UVLessThanDot = dot - (u + v);
  65. float ULessThanDot = dot - u;
  66. float UVGreaterEqualThanZero = (float)fsel(VGreaterEqualThanZero, UGreaterEqualThanZero, VGreaterEqualThanZero);
  67. float UUVLessThanDot = (float)fsel(UVLessThanDot, ULessThanDot, UVLessThanDot);
  68. float BothGood = (float)fsel(UVGreaterEqualThanZero, UUVLessThanDot, UVGreaterEqualThanZero);
  69. float AllGood = (float)fsel(DotGreaterThanEpsilon, BothGood, DotGreaterThanEpsilon);
  70. if (AllGood < 0.0f)
  71. {
  72. return false;
  73. }
  74. float dt = edgeA.Dot(q) / dot;
  75. Vec3 result = (dir * dt) + ray.origin;
  76. output = result;
  77. float AfterStart = (result - ray.origin).Dot(dir);
  78. return AfterStart >= 0.0f;
  79. }
  80. //----------------------------------------------------------------------------------
  81. // Ray_AABB
  82. //
  83. // just ONE intersection point is calculated, and thats the entry point -
  84. // Lineseg and AABB are assumed to be in the same space
  85. //
  86. //--- 0x00 = no intersection (output undefined) --------------------------
  87. //--- 0x01 = intersection (intersection point in output) --------------
  88. //--- 0x02 = start of Lineseg is inside the AABB (ls.start is output)
  89. //----------------------------------------------------------------------------------
  90. inline uint8 Ray_AABB(const Ray& ray, const AABB& aabb, Vec3& output1)
  91. {
  92. uint8 cflags;
  93. float cosine;
  94. Vec3 cut;
  95. //--------------------------------------------------------------------------------------
  96. //---- check if "ray.origin" is inside of AABB ---------------------------
  97. //--------------------------------------------------------------------------------------
  98. cflags = (ray.origin.x >= aabb.min.x) << 0;
  99. cflags |= (ray.origin.x <= aabb.max.x) << 1;
  100. cflags |= (ray.origin.y >= aabb.min.y) << 2;
  101. cflags |= (ray.origin.y <= aabb.max.y) << 3;
  102. cflags |= (ray.origin.z >= aabb.min.z) << 4;
  103. cflags |= (ray.origin.z <= aabb.max.z) << 5;
  104. if (cflags == 0x3f)
  105. {
  106. output1 = ray.origin;
  107. return 0x02;
  108. }
  109. //--------------------------------------------------------------------------------------
  110. //---- check intersection with planes ------------------------------
  111. //--------------------------------------------------------------------------------------
  112. for (int i = 0; i < 3; i++)
  113. {
  114. if ((ray.direction[i] > 0) && (ray.origin[i] < aabb.min[i]))
  115. {
  116. cosine = (-ray.origin[i] + aabb.min[i]) / ray.direction[i];
  117. cut[i] = aabb.min[i];
  118. cut[incm3(i)] = ray.origin[incm3(i)] + (ray.direction[incm3(i)] * cosine);
  119. cut[decm3(i)] = ray.origin[decm3(i)] + (ray.direction[decm3(i)] * cosine);
  120. if ((cut[incm3(i)] > aabb.min[incm3(i)]) && (cut[incm3(i)] < aabb.max[incm3(i)]) && (cut[decm3(i)] > aabb.min[decm3(i)]) && (cut[decm3(i)] < aabb.max[decm3(i)]))
  121. {
  122. output1 = cut;
  123. return 0x01;
  124. }
  125. }
  126. if ((ray.direction[i] < 0) && (ray.origin[i] > aabb.max[i]))
  127. {
  128. cosine = (+ray.origin[i] - aabb.max[i]) / ray.direction[i];
  129. cut[i] = aabb.max[i];
  130. cut[incm3(i)] = ray.origin[incm3(i)] - (ray.direction[incm3(i)] * cosine);
  131. cut[decm3(i)] = ray.origin[decm3(i)] - (ray.direction[decm3(i)] * cosine);
  132. if ((cut[incm3(i)] > aabb.min[incm3(i)]) && (cut[incm3(i)] < aabb.max[incm3(i)]) && (cut[decm3(i)] > aabb.min[decm3(i)]) && (cut[decm3(i)] < aabb.max[decm3(i)]))
  133. {
  134. output1 = cut;
  135. return 0x01;
  136. }
  137. }
  138. }
  139. return 0x00;//no intersection
  140. }
  141. //----------------------------------------------------------------------------------
  142. //--- 0x00 = no intersection --------------------------
  143. //--- 0x01 = not possible --
  144. //--- 0x02 = one intersection, lineseg has just an EXIT point but no ENTRY point (ls.start is inside the sphere) --
  145. //--- 0x03 = two intersection, lineseg has ENTRY and EXIT point --
  146. //----------------------------------------------------------------------------------
  147. inline unsigned char Ray_Sphere(const Ray& ray, const ::Sphere& s, Vec3& i0, Vec3& i1)
  148. {
  149. Vec3 end = ray.origin + ray.direction;
  150. float a = ray.direction | ray.direction;
  151. float b = (ray.direction | (ray.origin - s.center)) * 2.0f;
  152. float c = ((ray.origin - s.center) | (ray.origin - s.center)) - (s.radius * s.radius);
  153. float desc = (b * b) - (4 * a * c);
  154. unsigned char intersection = 0;
  155. if (desc >= 0.0f)
  156. {
  157. float lamba0 = (-b - sqrt_tpl(desc)) / (2.0f * a);
  158. // _stprintf(d3dApp.token,"lamba0: %20.12f",lamba0);
  159. // d3dApp.m_pFont->DrawText( 2, d3dApp.PrintY, D3DCOLOR_ARGB(255,255,255,0), d3dApp.token ); d3dApp.PrintY+=20;
  160. if (lamba0 > 0.0f)
  161. {
  162. i0 = ray.origin + ((end - ray.origin) * lamba0);
  163. intersection = 1;
  164. }
  165. float lamba1 = (-b + sqrt_tpl(desc)) / (2.0f * a);
  166. // _stprintf(d3dApp.token,"lamba1: %20.12f",lamba1);
  167. // d3dApp.m_pFont->DrawText( 2, d3dApp.PrintY, D3DCOLOR_ARGB(255,255,255,0), d3dApp.token ); d3dApp.PrintY+=20;
  168. if (lamba1 > 0.0f)
  169. {
  170. i1 = ray.origin + ((end - ray.origin) * lamba1);
  171. intersection |= 2;
  172. }
  173. }
  174. return intersection;
  175. }
  176. inline bool Ray_SphereFirst(const Ray& ray, const ::Sphere& s, Vec3& intPoint)
  177. {
  178. Vec3 p2;
  179. unsigned char res = Ray_Sphere(ray, s, intPoint, p2);
  180. if (res == 2)
  181. {
  182. intPoint = p2;
  183. }
  184. if (res > 1)
  185. {
  186. return true;
  187. }
  188. return false;
  189. }
  190. } //Intersect