GeometricTools.hlsl 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #ifndef UNITY_GEOMETRICTOOLS_INCLUDED
  2. #define UNITY_GEOMETRICTOOLS_INCLUDED
  3. //-----------------------------------------------------------------------------
  4. // Intersection functions
  5. //-----------------------------------------------------------------------------
  6. // return furthest near intersection in x and closest far intersection in y
  7. // if (intersections.y > intersections.x) the ray hit the box, else it miss it
  8. // Assume dir is normalize
  9. float2 BoxRayIntersect(float3 start, float3 dir, float3 boxMin, float3 boxMax)
  10. {
  11. float3 invDir = 1.0 / dir;
  12. // Find the ray intersection with box plane
  13. float3 firstPlaneIntersect = (boxMin - start) * invDir;
  14. float3 secondPlaneIntersect = (boxMax - start) * invDir;
  15. // Get the closest/furthest of these intersections along the ray (Ok because x/0 give +inf and -x/0 give -inf )
  16. float3 closestPlane = min(firstPlaneIntersect, secondPlaneIntersect);
  17. float3 furthestPlane = max(firstPlaneIntersect, secondPlaneIntersect);
  18. float2 intersections;
  19. // Find the furthest near intersection
  20. intersections.x = max(closestPlane.x, max(closestPlane.y, closestPlane.z));
  21. // Find the closest far intersection
  22. intersections.y = min(min(furthestPlane.x, furthestPlane.y), furthestPlane.z);
  23. return intersections;
  24. }
  25. // This simplified version assume that we care about the result only when we are inside the box
  26. // Assume dir is normalize
  27. float BoxRayIntersectSimple(float3 start, float3 dir, float3 boxMin, float3 boxMax)
  28. {
  29. float3 invDir = 1.0 / dir;
  30. // Find the ray intersection with box plane
  31. float3 rbmin = (boxMin - start) * invDir;
  32. float3 rbmax = (boxMax - start) * invDir;
  33. float3 rbminmax = (dir > 0.0) ? rbmax : rbmin;
  34. return min(min(rbminmax.x, rbminmax.y), rbminmax.z);
  35. }
  36. // Assume Sphere is at the origin (i.e start = position - spherePosition)
  37. float2 SphereRayIntersect(float3 start, float3 dir, float radius, out bool intersect)
  38. {
  39. float a = dot(dir, dir);
  40. float b = dot(dir, start) * 2.0;
  41. float c = dot(start, start) - radius * radius;
  42. float discriminant = b * b - 4.0 * a * c;
  43. float2 intersections = float2(0.0, 0.0);
  44. intersect = false;
  45. if (discriminant < 0.0 || a == 0.0)
  46. {
  47. intersections.x = 0.0;
  48. intersections.y = 0.0;
  49. }
  50. else
  51. {
  52. float sqrtDiscriminant = sqrt(discriminant);
  53. intersections.x = (-b - sqrtDiscriminant) / (2.0 * a);
  54. intersections.y = (-b + sqrtDiscriminant) / (2.0 * a);
  55. intersect = true;
  56. }
  57. return intersections;
  58. }
  59. // This simplified version assume that we care about the result only when we are inside the sphere
  60. // Assume Sphere is at the origin (i.e start = position - spherePosition) and dir is normalized
  61. // Ref: http://http.developer.nvidia.com/GPUGems/gpugems_ch19.html
  62. float SphereRayIntersectSimple(float3 start, float3 dir, float radius)
  63. {
  64. float b = dot(dir, start) * 2.0;
  65. float c = dot(start, start) - radius * radius;
  66. float discriminant = b * b - 4.0 * c;
  67. return abs(sqrt(discriminant) - b) * 0.5;
  68. }
  69. float3 RayPlaneIntersect(in float3 rayOrigin, in float3 rayDirection, in float3 planeOrigin, in float3 planeNormal)
  70. {
  71. float dist = dot(planeNormal, planeOrigin - rayOrigin) / dot(planeNormal, rayDirection);
  72. return rayOrigin + rayDirection * dist;
  73. }
  74. //-----------------------------------------------------------------------------
  75. // Miscellaneous functions
  76. //-----------------------------------------------------------------------------
  77. // Box is AABB
  78. float DistancePointBox(float3 position, float3 boxMin, float3 boxMax)
  79. {
  80. return length(max(max(position - boxMax, boxMin - position), float3(0.0, 0.0, 0.0)));
  81. }
  82. float3 ProjectPointOnPlane(float3 position, float3 planePosition, float3 planeNormal)
  83. {
  84. return position - (dot(position - planePosition, planeNormal) * planeNormal);
  85. }
  86. // Plane equation: {(a, b, c) = N, d = -dot(N, P)}.
  87. // Returns the distance from the plane to the point 'p' along the normal.
  88. // Positive -> in front (above), negative -> behind (below).
  89. float DistanceFromPlane(float3 p, float4 plane)
  90. {
  91. return dot(float4(p, 1.0), plane);
  92. }
  93. // Returns 'true' if the triangle is outside of the frustum.
  94. // 'epsilon' is the (negative) distance to (outside of) the frustum below which we cull the triangle.
  95. bool CullTriangleFrustum(float3 p0, float3 p1, float3 p2, float epsilon, float4 frustumPlanes[6], int numPlanes)
  96. {
  97. bool outside = false;
  98. for (int i = 0; i < numPlanes; i++)
  99. {
  100. // If all 3 points are behind any of the planes, we cull.
  101. outside = outside || Max3(DistanceFromPlane(p0, frustumPlanes[i]),
  102. DistanceFromPlane(p1, frustumPlanes[i]),
  103. DistanceFromPlane(p2, frustumPlanes[i])) < epsilon;
  104. }
  105. return outside;
  106. }
  107. // Returns 'true' if the edge of the triangle is outside of the frustum.
  108. // The edges are defined s.t. they are on the opposite side of the point with the given index.
  109. // 'epsilon' is the (negative) distance to (outside of) the frustum below which we cull the triangle.
  110. bool3 CullTriangleEdgesFrustum(float3 p0, float3 p1, float3 p2, float epsilon, float4 frustumPlanes[6], int numPlanes)
  111. {
  112. bool3 edgesOutside = false;
  113. for (int i = 0; i < numPlanes; i++)
  114. {
  115. bool3 pointsOutside = bool3(DistanceFromPlane(p0, frustumPlanes[i]) < epsilon,
  116. DistanceFromPlane(p1, frustumPlanes[i]) < epsilon,
  117. DistanceFromPlane(p2, frustumPlanes[i]) < epsilon);
  118. // If both points of the edge are behind any of the planes, we cull.
  119. edgesOutside.x = edgesOutside.x || (pointsOutside.y && pointsOutside.z);
  120. edgesOutside.y = edgesOutside.y || (pointsOutside.x && pointsOutside.z);
  121. edgesOutside.z = edgesOutside.z || (pointsOutside.x && pointsOutside.y);
  122. }
  123. return edgesOutside;
  124. }
  125. // Returns 'true' if a triangle defined by 3 vertices is back-facing.
  126. // 'epsilon' is the (negative) value of dot(N, V) below which we cull the triangle.
  127. // 'winding' can be used to change the order: pass 1 for (p0 -> p1 -> p2), or -1 for (p0 -> p2 -> p1).
  128. bool CullTriangleBackFace(float3 p0, float3 p1, float3 p2, float epsilon, float3 viewPos, float winding)
  129. {
  130. float3 edge1 = p1 - p0;
  131. float3 edge2 = p2 - p0;
  132. float3 N = cross(edge1, edge2);
  133. float3 V = viewPos - p0;
  134. float NdotV = dot(N, V) * winding;
  135. // Optimize:
  136. // NdotV / (length(N) * length(V)) < Epsilon
  137. // NdotV < Epsilon * length(N) * length(V)
  138. // NdotV < Epsilon * sqrt(dot(N, N)) * sqrt(dot(V, V))
  139. // NdotV < Epsilon * sqrt(dot(N, N) * dot(V, V))
  140. return NdotV < epsilon * sqrt(dot(N, N) * dot(V, V));
  141. }
  142. #endif // UNITY_GEOMETRICTOOLS_INCLUDED