Ray.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #include "../Precompiled.h"
  4. #include "../Math/BoundingBox.h"
  5. #include "../Math/Frustum.h"
  6. #include "../Math/Ray.h"
  7. #include "../DebugNew.h"
  8. namespace Urho3D
  9. {
  10. Vector3 Ray::ClosestPoint(const Ray& ray) const
  11. {
  12. // Algorithm based on http://paulbourke.net/geometry/lineline3d/
  13. Vector3 p13 = origin_ - ray.origin_;
  14. Vector3 p43 = ray.direction_;
  15. Vector3 p21 = direction_;
  16. float d1343 = p13.DotProduct(p43);
  17. float d4321 = p43.DotProduct(p21);
  18. float d1321 = p13.DotProduct(p21);
  19. float d4343 = p43.DotProduct(p43);
  20. float d2121 = p21.DotProduct(p21);
  21. float d = d2121 * d4343 - d4321 * d4321;
  22. if (Abs(d) < M_EPSILON)
  23. return origin_;
  24. float n = d1343 * d4321 - d1321 * d4343;
  25. float a = n / d;
  26. return origin_ + a * direction_;
  27. }
  28. float Ray::HitDistance(const Plane& plane) const
  29. {
  30. float d = plane.normal_.DotProduct(direction_);
  31. if (Abs(d) >= M_EPSILON)
  32. {
  33. float t = -(plane.normal_.DotProduct(origin_) + plane.d_) / d;
  34. if (t >= 0.0f)
  35. return t;
  36. else
  37. return M_INFINITY;
  38. }
  39. else
  40. return M_INFINITY;
  41. }
  42. float Ray::HitDistance(const BoundingBox& box) const
  43. {
  44. // If undefined, no hit (infinite distance)
  45. if (!box.Defined())
  46. return M_INFINITY;
  47. // Check for ray origin being inside the box
  48. if (box.IsInside(origin_))
  49. return 0.0f;
  50. float dist = M_INFINITY;
  51. // Check for intersecting in the X-direction
  52. if (origin_.x_ < box.min_.x_ && direction_.x_ > 0.0f)
  53. {
  54. float x = (box.min_.x_ - origin_.x_) / direction_.x_;
  55. if (x < dist)
  56. {
  57. Vector3 point = origin_ + x * direction_;
  58. if (point.y_ >= box.min_.y_ && point.y_ <= box.max_.y_ && point.z_ >= box.min_.z_ && point.z_ <= box.max_.z_)
  59. dist = x;
  60. }
  61. }
  62. if (origin_.x_ > box.max_.x_ && direction_.x_ < 0.0f)
  63. {
  64. float x = (box.max_.x_ - origin_.x_) / direction_.x_;
  65. if (x < dist)
  66. {
  67. Vector3 point = origin_ + x * direction_;
  68. if (point.y_ >= box.min_.y_ && point.y_ <= box.max_.y_ && point.z_ >= box.min_.z_ && point.z_ <= box.max_.z_)
  69. dist = x;
  70. }
  71. }
  72. // Check for intersecting in the Y-direction
  73. if (origin_.y_ < box.min_.y_ && direction_.y_ > 0.0f)
  74. {
  75. float x = (box.min_.y_ - origin_.y_) / direction_.y_;
  76. if (x < dist)
  77. {
  78. Vector3 point = origin_ + x * direction_;
  79. if (point.x_ >= box.min_.x_ && point.x_ <= box.max_.x_ && point.z_ >= box.min_.z_ && point.z_ <= box.max_.z_)
  80. dist = x;
  81. }
  82. }
  83. if (origin_.y_ > box.max_.y_ && direction_.y_ < 0.0f)
  84. {
  85. float x = (box.max_.y_ - origin_.y_) / direction_.y_;
  86. if (x < dist)
  87. {
  88. Vector3 point = origin_ + x * direction_;
  89. if (point.x_ >= box.min_.x_ && point.x_ <= box.max_.x_ && point.z_ >= box.min_.z_ && point.z_ <= box.max_.z_)
  90. dist = x;
  91. }
  92. }
  93. // Check for intersecting in the Z-direction
  94. if (origin_.z_ < box.min_.z_ && direction_.z_ > 0.0f)
  95. {
  96. float x = (box.min_.z_ - origin_.z_) / direction_.z_;
  97. if (x < dist)
  98. {
  99. Vector3 point = origin_ + x * direction_;
  100. if (point.x_ >= box.min_.x_ && point.x_ <= box.max_.x_ && point.y_ >= box.min_.y_ && point.y_ <= box.max_.y_)
  101. dist = x;
  102. }
  103. }
  104. if (origin_.z_ > box.max_.z_ && direction_.z_ < 0.0f)
  105. {
  106. float x = (box.max_.z_ - origin_.z_) / direction_.z_;
  107. if (x < dist)
  108. {
  109. Vector3 point = origin_ + x * direction_;
  110. if (point.x_ >= box.min_.x_ && point.x_ <= box.max_.x_ && point.y_ >= box.min_.y_ && point.y_ <= box.max_.y_)
  111. dist = x;
  112. }
  113. }
  114. return dist;
  115. }
  116. float Ray::HitDistance(const Frustum& frustum, bool solidInside) const
  117. {
  118. float maxOutside = 0.0f;
  119. float minInside = M_INFINITY;
  120. bool allInside = true;
  121. for (const auto& plane : frustum.planes_)
  122. {
  123. float distance = HitDistance(plane);
  124. if (plane.Distance(origin_) < 0.0f)
  125. {
  126. maxOutside = Max(maxOutside, distance);
  127. allInside = false;
  128. }
  129. else
  130. minInside = Min(minInside, distance);
  131. }
  132. if (allInside)
  133. return solidInside ? 0.0f : minInside;
  134. else if (maxOutside <= minInside)
  135. return maxOutside;
  136. else
  137. return M_INFINITY;
  138. }
  139. float Ray::HitDistance(const Sphere& sphere) const
  140. {
  141. Vector3 centeredOrigin = origin_ - sphere.center_;
  142. float squaredRadius = sphere.radius_ * sphere.radius_;
  143. // Check if ray originates inside the sphere
  144. if (centeredOrigin.LengthSquared() <= squaredRadius)
  145. return 0.0f;
  146. // Calculate intersection by quadratic equation
  147. float a = direction_.DotProduct(direction_);
  148. float b = 2.0f * centeredOrigin.DotProduct(direction_);
  149. float c = centeredOrigin.DotProduct(centeredOrigin) - squaredRadius;
  150. float d = b * b - 4.0f * a * c;
  151. // No solution
  152. if (d < 0.0f)
  153. return M_INFINITY;
  154. // Get the nearer solution
  155. float dSqrt = sqrtf(d);
  156. float dist = (-b - dSqrt) / (2.0f * a);
  157. if (dist >= 0.0f)
  158. return dist;
  159. else
  160. return (-b + dSqrt) / (2.0f * a);
  161. }
  162. float Ray::HitDistance(const Vector3& v0, const Vector3& v1, const Vector3& v2, Vector3* outNormal, Vector3* outBary) const
  163. {
  164. // Based on Fast, Minimum Storage Ray/Triangle Intersection by Möller & Trumbore
  165. // http://www.graphics.cornell.edu/pubs/1997/MT97.pdf
  166. // Calculate edge vectors
  167. Vector3 edge1(v1 - v0);
  168. Vector3 edge2(v2 - v0);
  169. // Calculate determinant & check backfacing
  170. Vector3 p(direction_.CrossProduct(edge2));
  171. float det = edge1.DotProduct(p);
  172. if (det >= M_EPSILON)
  173. {
  174. // Calculate u & v parameters and test
  175. Vector3 t(origin_ - v0);
  176. float u = t.DotProduct(p);
  177. if (u >= 0.0f && u <= det)
  178. {
  179. Vector3 q(t.CrossProduct(edge1));
  180. float v = direction_.DotProduct(q);
  181. if (v >= 0.0f && u + v <= det)
  182. {
  183. float distance = edge2.DotProduct(q) / det;
  184. // Discard hits behind the ray
  185. if (distance >= 0.0f)
  186. {
  187. // There is an intersection, so calculate distance & optional normal
  188. if (outNormal)
  189. *outNormal = edge1.CrossProduct(edge2);
  190. if (outBary)
  191. *outBary = Vector3(1 - (u / det) - (v / det), u / det, v / det);
  192. return distance;
  193. }
  194. }
  195. }
  196. }
  197. return M_INFINITY;
  198. }
  199. float Ray::HitDistance(const void* vertexData, i32 vertexStride, i32 vertexStart, i32 vertexCount,
  200. Vector3* outNormal, Vector2* outUV, i32 uvOffset) const
  201. {
  202. assert(vertexStride >= 0);
  203. assert(vertexStart >= 0);
  204. assert(vertexCount >= 0);
  205. assert(uvOffset >= 0 || (uvOffset == NINDEX && !outUV));
  206. float nearest = M_INFINITY;
  207. const u8* vertices = ((const u8*)vertexData) + vertexStart * vertexStride;
  208. i32 index = 0, nearestIdx = NINDEX;
  209. Vector3 tempNormal;
  210. Vector3* tempNormalPtr = outNormal ? &tempNormal : nullptr;
  211. Vector3 barycentric;
  212. Vector3 tempBarycentric;
  213. Vector3* tempBarycentricPtr = outUV ? &tempBarycentric : nullptr;
  214. while (index + 2 < vertexCount)
  215. {
  216. const Vector3& v0 = *((const Vector3*)(&vertices[index * vertexStride]));
  217. const Vector3& v1 = *((const Vector3*)(&vertices[(index + 1) * vertexStride]));
  218. const Vector3& v2 = *((const Vector3*)(&vertices[(index + 2) * vertexStride]));
  219. float distance = HitDistance(v0, v1, v2, tempNormalPtr, tempBarycentricPtr);
  220. if (distance < nearest)
  221. {
  222. nearestIdx = index;
  223. nearest = distance;
  224. if (outNormal)
  225. *outNormal = tempNormal;
  226. if (outUV)
  227. barycentric = tempBarycentric;
  228. }
  229. index += 3;
  230. }
  231. if (outUV)
  232. {
  233. if (nearestIdx == NINDEX)
  234. *outUV = Vector2::ZERO;
  235. else
  236. {
  237. // Interpolate the UV coordinate using barycentric coordinate
  238. const Vector2& uv0 = *((const Vector2*)(&vertices[uvOffset + nearestIdx * vertexStride]));
  239. const Vector2& uv1 = *((const Vector2*)(&vertices[uvOffset + (nearestIdx + 1) * vertexStride]));
  240. const Vector2& uv2 = *((const Vector2*)(&vertices[uvOffset + (nearestIdx + 2) * vertexStride]));
  241. *outUV = Vector2(uv0.x_ * barycentric.x_ + uv1.x_ * barycentric.y_ + uv2.x_ * barycentric.z_,
  242. uv0.y_ * barycentric.x_ + uv1.y_ * barycentric.y_ + uv2.y_ * barycentric.z_);
  243. }
  244. }
  245. return nearest;
  246. }
  247. float Ray::HitDistance(const void* vertexData, i32 vertexStride, const void* indexData, i32 indexSize,
  248. i32 indexStart, i32 indexCount, Vector3* outNormal, Vector2* outUV, i32 uvOffset) const
  249. {
  250. assert(vertexStride >= 0);
  251. assert(indexSize >= 0);
  252. assert(indexStart >= 0);
  253. assert(indexCount >= 0);
  254. assert(uvOffset >= 0 || (uvOffset == NINDEX && !outUV));
  255. float nearest = M_INFINITY;
  256. const u8* vertices = (const u8*)vertexData;
  257. Vector3 tempNormal;
  258. Vector3* tempNormalPtr = outNormal ? &tempNormal : nullptr;
  259. Vector3 barycentric;
  260. Vector3 tempBarycentric;
  261. Vector3* tempBarycentricPtr = outUV ? &tempBarycentric : nullptr;
  262. // 16-bit indices
  263. if (indexSize == sizeof(unsigned short))
  264. {
  265. const unsigned short* indices = ((const unsigned short*)indexData) + indexStart;
  266. const unsigned short* indicesEnd = indices + indexCount;
  267. const unsigned short* nearestIndices = nullptr;
  268. while (indices < indicesEnd)
  269. {
  270. const Vector3& v0 = *((const Vector3*)(&vertices[indices[0] * vertexStride]));
  271. const Vector3& v1 = *((const Vector3*)(&vertices[indices[1] * vertexStride]));
  272. const Vector3& v2 = *((const Vector3*)(&vertices[indices[2] * vertexStride]));
  273. float distance = HitDistance(v0, v1, v2, tempNormalPtr, tempBarycentricPtr);
  274. if (distance < nearest)
  275. {
  276. nearestIndices = indices;
  277. nearest = distance;
  278. if (outNormal)
  279. *outNormal = tempNormal;
  280. if (outUV)
  281. barycentric = tempBarycentric;
  282. }
  283. indices += 3;
  284. }
  285. if (outUV)
  286. {
  287. if (nearestIndices == nullptr)
  288. *outUV = Vector2::ZERO;
  289. else
  290. {
  291. // Interpolate the UV coordinate using barycentric coordinate
  292. const Vector2& uv0 = *((const Vector2*)(&vertices[uvOffset + nearestIndices[0] * vertexStride]));
  293. const Vector2& uv1 = *((const Vector2*)(&vertices[uvOffset + nearestIndices[1] * vertexStride]));
  294. const Vector2& uv2 = *((const Vector2*)(&vertices[uvOffset + nearestIndices[2] * vertexStride]));
  295. *outUV = Vector2(uv0.x_ * barycentric.x_ + uv1.x_ * barycentric.y_ + uv2.x_ * barycentric.z_,
  296. uv0.y_ * barycentric.x_ + uv1.y_ * barycentric.y_ + uv2.y_ * barycentric.z_);
  297. }
  298. }
  299. }
  300. // 32-bit indices
  301. else
  302. {
  303. const unsigned* indices = ((const unsigned*)indexData) + indexStart;
  304. const unsigned* indicesEnd = indices + indexCount;
  305. const unsigned* nearestIndices = nullptr;
  306. while (indices < indicesEnd)
  307. {
  308. const Vector3& v0 = *((const Vector3*)(&vertices[indices[0] * vertexStride]));
  309. const Vector3& v1 = *((const Vector3*)(&vertices[indices[1] * vertexStride]));
  310. const Vector3& v2 = *((const Vector3*)(&vertices[indices[2] * vertexStride]));
  311. float distance = HitDistance(v0, v1, v2, tempNormalPtr, tempBarycentricPtr);
  312. if (distance < nearest)
  313. {
  314. nearestIndices = indices;
  315. nearest = distance;
  316. if (outNormal)
  317. *outNormal = tempNormal;
  318. if (outUV)
  319. barycentric = tempBarycentric;
  320. }
  321. indices += 3;
  322. }
  323. if (outUV)
  324. {
  325. if (nearestIndices == nullptr)
  326. *outUV = Vector2::ZERO;
  327. else
  328. {
  329. // Interpolate the UV coordinate using barycentric coordinate
  330. const Vector2& uv0 = *((const Vector2*)(&vertices[uvOffset + nearestIndices[0] * vertexStride]));
  331. const Vector2& uv1 = *((const Vector2*)(&vertices[uvOffset + nearestIndices[1] * vertexStride]));
  332. const Vector2& uv2 = *((const Vector2*)(&vertices[uvOffset + nearestIndices[2] * vertexStride]));
  333. *outUV = Vector2(uv0.x_ * barycentric.x_ + uv1.x_ * barycentric.y_ + uv2.x_ * barycentric.z_,
  334. uv0.y_ * barycentric.x_ + uv1.y_ * barycentric.y_ + uv2.y_ * barycentric.z_);
  335. }
  336. }
  337. }
  338. return nearest;
  339. }
  340. bool Ray::InsideGeometry(const void* vertexData, i32 vertexSize, i32 vertexStart, i32 vertexCount) const
  341. {
  342. assert(vertexSize >= 0);
  343. assert(vertexStart >= 0);
  344. assert(vertexCount >= 0);
  345. float currentFrontFace = M_INFINITY;
  346. float currentBackFace = M_INFINITY;
  347. const u8* vertices = ((const u8*)vertexData) + vertexStart * vertexSize;
  348. i32 index = 0;
  349. while (index + 2 < vertexCount)
  350. {
  351. const Vector3& v0 = *((const Vector3*)(&vertices[index * vertexSize]));
  352. const Vector3& v1 = *((const Vector3*)(&vertices[(index + 1) * vertexSize]));
  353. const Vector3& v2 = *((const Vector3*)(&vertices[(index + 2) * vertexSize]));
  354. float frontFaceDistance = HitDistance(v0, v1, v2);
  355. float backFaceDistance = HitDistance(v2, v1, v0);
  356. currentFrontFace = Min(frontFaceDistance > 0.0f ? frontFaceDistance : M_INFINITY, currentFrontFace);
  357. // A backwards face is just a regular one, with the vertices in the opposite order. This essentially checks backfaces by
  358. // checking reversed frontfaces
  359. currentBackFace = Min(backFaceDistance > 0.0f ? backFaceDistance : M_INFINITY, currentBackFace);
  360. index += 3;
  361. }
  362. // If the closest face is a backface, that means that the ray originates from the inside of the geometry
  363. // NOTE: there may be cases where both are equal, as in, no collision to either. This is prevented in the most likely case
  364. // (ray doesn't hit either) by this conditional
  365. if (currentFrontFace != M_INFINITY || currentBackFace != M_INFINITY)
  366. return currentBackFace < currentFrontFace;
  367. // It is still possible for two triangles to be equally distant from the triangle, however, this is extremely unlikely.
  368. // As such, it is safe to assume they are not
  369. return false;
  370. }
  371. bool Ray::InsideGeometry(const void* vertexData, i32 vertexSize, const void* indexData, i32 indexSize,
  372. i32 indexStart, i32 indexCount) const
  373. {
  374. assert(vertexSize >= 0);
  375. assert(indexSize >= 0);
  376. assert(indexStart >= 0);
  377. assert(indexCount >= 0);
  378. float currentFrontFace = M_INFINITY;
  379. float currentBackFace = M_INFINITY;
  380. const u8* vertices = (const u8*)vertexData;
  381. // 16-bit indices
  382. if (indexSize == sizeof(unsigned short))
  383. {
  384. const unsigned short* indices = ((const unsigned short*)indexData) + indexStart;
  385. const unsigned short* indicesEnd = indices + indexCount;
  386. while (indices < indicesEnd)
  387. {
  388. const Vector3& v0 = *((const Vector3*)(&vertices[indices[0] * vertexSize]));
  389. const Vector3& v1 = *((const Vector3*)(&vertices[indices[1] * vertexSize]));
  390. const Vector3& v2 = *((const Vector3*)(&vertices[indices[2] * vertexSize]));
  391. float frontFaceDistance = HitDistance(v0, v1, v2);
  392. float backFaceDistance = HitDistance(v2, v1, v0);
  393. currentFrontFace = Min(frontFaceDistance > 0.0f ? frontFaceDistance : M_INFINITY, currentFrontFace);
  394. // A backwards face is just a regular one, with the vertices in the opposite order. This essentially checks backfaces by
  395. // checking reversed frontfaces
  396. currentBackFace = Min(backFaceDistance > 0.0f ? backFaceDistance : M_INFINITY, currentBackFace);
  397. indices += 3;
  398. }
  399. }
  400. // 32-bit indices
  401. else
  402. {
  403. const unsigned* indices = ((const unsigned*)indexData) + indexStart;
  404. const unsigned* indicesEnd = indices + indexCount;
  405. while (indices < indicesEnd)
  406. {
  407. const Vector3& v0 = *((const Vector3*)(&vertices[indices[0] * vertexSize]));
  408. const Vector3& v1 = *((const Vector3*)(&vertices[indices[1] * vertexSize]));
  409. const Vector3& v2 = *((const Vector3*)(&vertices[indices[2] * vertexSize]));
  410. float frontFaceDistance = HitDistance(v0, v1, v2);
  411. float backFaceDistance = HitDistance(v2, v1, v0);
  412. currentFrontFace = Min(frontFaceDistance > 0.0f ? frontFaceDistance : M_INFINITY, currentFrontFace);
  413. // A backwards face is just a regular one, with the vertices in the opposite order. This essentially checks backfaces by
  414. // checking reversed frontfaces
  415. currentBackFace = Min(backFaceDistance > 0.0f ? backFaceDistance : M_INFINITY, currentBackFace);
  416. indices += 3;
  417. }
  418. }
  419. // If the closest face is a backface, that means that the ray originates from the inside of the geometry
  420. // NOTE: there may be cases where both are equal, as in, no collision to either. This is prevented in the most likely case
  421. // (ray doesn't hit either) by this conditional
  422. if (currentFrontFace != M_INFINITY || currentBackFace != M_INFINITY)
  423. return currentBackFace < currentFrontFace;
  424. // It is still possible for two triangles to be equally distant from the triangle, however, this is extremely unlikely.
  425. // As such, it is safe to assume they are not
  426. return false;
  427. }
  428. Ray Ray::Transformed(const Matrix3x4& transform) const
  429. {
  430. Ray ret;
  431. ret.origin_ = transform * origin_;
  432. ret.direction_ = transform * Vector4(direction_, 0.0f);
  433. return ret;
  434. }
  435. }