RayTriangle.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. JPH_NAMESPACE_BEGIN
  6. /// Intersect ray with triangle, returns closest point or FLT_MAX if no hit (branch less version)
  7. /// Adapted from: http://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
  8. JPH_INLINE float RayTriangle(Vec3Arg inOrigin, Vec3Arg inDirection, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
  9. {
  10. // Epsilon
  11. Vec3 epsilon = Vec3::sReplicate(1.0e-12f);
  12. // Zero & one
  13. Vec3 zero = Vec3::sZero();
  14. Vec3 one = Vec3::sReplicate(1.0f);
  15. // Find vectors for two edges sharing inV0
  16. Vec3 e1 = inV1 - inV0;
  17. Vec3 e2 = inV2 - inV0;
  18. // Begin calculating determinant - also used to calculate u parameter
  19. Vec3 p = inDirection.Cross(e2);
  20. // if determinant is near zero, ray lies in plane of triangle
  21. Vec3 det = Vec3::sReplicate(e1.Dot(p));
  22. // Check if determinant is near zero
  23. UVec4 det_near_zero = Vec3::sLess(det.Abs(), epsilon);
  24. // When the determinant is near zero, set it to one to avoid dividing by zero
  25. det = Vec3::sSelect(det, Vec3::sReplicate(1.0f), det_near_zero);
  26. // Calculate distance from inV0 to ray origin
  27. Vec3 s = inOrigin - inV0;
  28. // Calculate u parameter
  29. Vec3 u = Vec3::sReplicate(s.Dot(p)) / det;
  30. // Prepare to test v parameter
  31. Vec3 q = s.Cross(e1);
  32. // Calculate v parameter
  33. Vec3 v = Vec3::sReplicate(inDirection.Dot(q)) / det;
  34. // Get intersection point
  35. Vec3 t = Vec3::sReplicate(e2.Dot(q)) / det;
  36. // Check if there is an intersection
  37. UVec4 no_intersection =
  38. UVec4::sOr
  39. (
  40. UVec4::sOr
  41. (
  42. UVec4::sOr
  43. (
  44. det_near_zero,
  45. Vec3::sLess(u, zero)
  46. ),
  47. UVec4::sOr
  48. (
  49. Vec3::sLess(v, zero),
  50. Vec3::sGreater(u + v, one)
  51. )
  52. ),
  53. Vec3::sLess(t, zero)
  54. );
  55. // Select intersection point or FLT_MAX based on if there is an intersection or not
  56. return Vec3::sSelect(t, Vec3::sReplicate(FLT_MAX), no_intersection).GetX();
  57. }
  58. /// Intersect ray with 4 triangles in SOA format, returns 4 vector of closest points or FLT_MAX if no hit (uses bit tricks to do less divisions)
  59. JPH_INLINE Vec4 RayTriangle4(Vec3Arg inOrigin, Vec3Arg inDirection, Vec4Arg inV0X, Vec4Arg inV0Y, Vec4Arg inV0Z, Vec4Arg inV1X, Vec4Arg inV1Y, Vec4Arg inV1Z, Vec4Arg inV2X, Vec4Arg inV2Y, Vec4Arg inV2Z)
  60. {
  61. // Epsilon
  62. Vec4 epsilon = Vec4::sReplicate(1.0e-12f);
  63. // Zero
  64. Vec4 zero = Vec4::sZero();
  65. // Find vectors for two edges sharing inV0
  66. Vec4 e1x = inV1X - inV0X;
  67. Vec4 e1y = inV1Y - inV0Y;
  68. Vec4 e1z = inV1Z - inV0Z;
  69. Vec4 e2x = inV2X - inV0X;
  70. Vec4 e2y = inV2Y - inV0Y;
  71. Vec4 e2z = inV2Z - inV0Z;
  72. // Get direction vector components
  73. Vec4 dx = inDirection.SplatX();
  74. Vec4 dy = inDirection.SplatY();
  75. Vec4 dz = inDirection.SplatZ();
  76. // Begin calculating determinant - also used to calculate u parameter
  77. Vec4 px = dy * e2z - dz * e2y;
  78. Vec4 py = dz * e2x - dx * e2z;
  79. Vec4 pz = dx * e2y - dy * e2x;
  80. // if determinant is near zero, ray lies in plane of triangle
  81. Vec4 det = e1x * px + e1y * py + e1z * pz;
  82. // Get sign bit for determinant and make positive
  83. Vec4 det_sign = Vec4::sAnd(det, UVec4::sReplicate(0x80000000).ReinterpretAsFloat());
  84. det = Vec4::sXor(det, det_sign);
  85. // Check which determinants are near zero
  86. UVec4 det_near_zero = Vec4::sLess(det, epsilon);
  87. // Set components of the determinant to 1 that are near zero to avoid dividing by zero
  88. det = Vec4::sSelect(det, Vec4::sReplicate(1.0f), det_near_zero);
  89. // Calculate distance from inV0 to ray origin
  90. Vec4 sx = inOrigin.SplatX() - inV0X;
  91. Vec4 sy = inOrigin.SplatY() - inV0Y;
  92. Vec4 sz = inOrigin.SplatZ() - inV0Z;
  93. // Calculate u parameter and flip sign if determinant was negative
  94. Vec4 u = Vec4::sXor(sx * px + sy * py + sz * pz, det_sign);
  95. // Prepare to test v parameter
  96. Vec4 qx = sy * e1z - sz * e1y;
  97. Vec4 qy = sz * e1x - sx * e1z;
  98. Vec4 qz = sx * e1y - sy * e1x;
  99. // Calculate v parameter and flip sign if determinant was negative
  100. Vec4 v = Vec4::sXor(dx * qx + dy * qy + dz * qz, det_sign);
  101. // Get intersection point and flip sign if determinant was negative
  102. Vec4 t = Vec4::sXor(e2x * qx + e2y * qy + e2z * qz, det_sign);
  103. // Check if there is an intersection
  104. UVec4 no_intersection =
  105. UVec4::sOr
  106. (
  107. UVec4::sOr
  108. (
  109. UVec4::sOr
  110. (
  111. det_near_zero,
  112. Vec4::sLess(u, zero)
  113. ),
  114. UVec4::sOr
  115. (
  116. Vec4::sLess(v, zero),
  117. Vec4::sGreater(u + v, det)
  118. )
  119. ),
  120. Vec4::sLess(t, zero)
  121. );
  122. // Select intersection point or FLT_MAX based on if there is an intersection or not
  123. return Vec4::sSelect(t / det, Vec4::sReplicate(FLT_MAX), no_intersection);
  124. }
  125. JPH_NAMESPACE_END