IntersectCylinder.glsl 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. // See IntersectionUtils.glsl for the definitions of Ray, setIntersection,
  2. // setIntersectionPair
  3. /* Cylinder defines (set in Scene/VoxelCylinderShape.js)
  4. #define CYLINDER_HAS_RENDER_BOUNDS_RADIUS_MIN
  5. #define CYLINDER_HAS_RENDER_BOUNDS_RADIUS_MAX
  6. #define CYLINDER_HAS_RENDER_BOUNDS_RADIUS_FLAT
  7. #define CYLINDER_HAS_RENDER_BOUNDS_HEIGHT
  8. #define CYLINDER_HAS_RENDER_BOUNDS_HEIGHT_FLAT
  9. #define CYLINDER_HAS_RENDER_BOUNDS_ANGLE
  10. #define CYLINDER_HAS_RENDER_BOUNDS_ANGLE_RANGE_UNDER_HALF
  11. #define CYLINDER_HAS_RENDER_BOUNDS_ANGLE_RANGE_OVER_HALF
  12. #define CYLINDER_HAS_RENDER_BOUNDS_ANGLE_RANGE_EQUAL_HALF
  13. #define CYLINDER_HAS_RENDER_BOUNDS_ANGLE_RANGE_EQUAL_ZERO
  14. #define CYLINDER_HAS_SHAPE_BOUNDS_RADIUS
  15. #define CYLINDER_HAS_SHAPE_BOUNDS_RADIUS_FLAT
  16. #define CYLINDER_HAS_SHAPE_BOUNDS_HEIGHT
  17. #define CYLINDER_HAS_SHAPE_BOUNDS_HEIGHT_FLAT
  18. #define CYLINDER_HAS_SHAPE_BOUNDS_ANGLE
  19. #define CYLINDER_HAS_SHAPE_BOUNDS_ANGLE_RANGE_EQUAL_ZERO
  20. #define CYLINDER_HAS_SHAPE_BOUNDS_ANGLE_MIN_DISCONTINUITY
  21. #define CYLINDER_HAS_SHAPE_BOUNDS_ANGLE_MAX_DISCONTINUITY
  22. #define CYLINDER_HAS_SHAPE_BOUNDS_ANGLE_MIN_MAX_REVERSED
  23. #define CYLINDER_INTERSECTION_INDEX_RADIUS_MAX
  24. #define CYLINDER_INTERSECTION_INDEX_RADIUS_MIN
  25. #define CYLINDER_INTERSECTION_INDEX_ANGLE
  26. */
  27. // Cylinder uniforms
  28. #if defined(CYLINDER_HAS_RENDER_BOUNDS_RADIUS_MAX) || defined(CYLINDER_HAS_RENDER_BOUNDS_HEIGHT)
  29. uniform vec3 u_cylinderUvToRenderBoundsScale;
  30. uniform vec3 u_cylinderUvToRenderBoundsTranslate;
  31. #endif
  32. #if defined(CYLINDER_HAS_RENDER_BOUNDS_RADIUS_MIN) && !defined(CYLINDER_HAS_RENDER_BOUNDS_RADIUS_FLAT)
  33. uniform float u_cylinderUvToRenderRadiusMin;
  34. #endif
  35. #if defined(CYLINDER_HAS_RENDER_BOUNDS_ANGLE)
  36. uniform vec2 u_cylinderRenderAngleMinMax;
  37. #endif
  38. vec4 intersectHalfPlane(Ray ray, float angle) {
  39. vec2 o = ray.pos.xy;
  40. vec2 d = ray.dir.xy;
  41. vec2 planeDirection = vec2(cos(angle), sin(angle));
  42. vec2 planeNormal = vec2(planeDirection.y, -planeDirection.x);
  43. float a = dot(o, planeNormal);
  44. float b = dot(d, planeNormal);
  45. float t = -a / b;
  46. vec2 p = o + t * d;
  47. bool outside = dot(p, planeDirection) < 0.0;
  48. if (outside) return vec4(-INF_HIT, +INF_HIT, NO_HIT, NO_HIT);
  49. return vec4(-INF_HIT, t, t, +INF_HIT);
  50. }
  51. #define POSITIVE_HIT vec2(t, +INF_HIT);
  52. #define NEGATIVE_HIT vec2(-INF_HIT, t);
  53. vec2 intersectHalfSpace(Ray ray, float angle)
  54. {
  55. vec2 o = ray.pos.xy;
  56. vec2 d = ray.dir.xy;
  57. vec2 n = vec2(sin(angle), -cos(angle));
  58. float a = dot(o, n);
  59. float b = dot(d, n);
  60. float t = -a / b;
  61. float s = sign(a);
  62. // Half space cuts right through the camera, pick the side to intersect
  63. if (a == 0.0) {
  64. if (b >= 0.0) {
  65. return POSITIVE_HIT;
  66. } else {
  67. return NEGATIVE_HIT;
  68. }
  69. }
  70. if (t >= 0.0 != s >= 0.0) {
  71. return POSITIVE_HIT;
  72. } else {
  73. return NEGATIVE_HIT;
  74. }
  75. }
  76. vec2 intersectRegularWedge(Ray ray, float minAngle, float maxAngle)
  77. {
  78. vec2 o = ray.pos.xy;
  79. vec2 d = ray.dir.xy;
  80. vec2 n1 = vec2(sin(minAngle), -cos(minAngle));
  81. vec2 n2 = vec2(-sin(maxAngle), cos(maxAngle));
  82. float a1 = dot(o, n1);
  83. float a2 = dot(o, n2);
  84. float b1 = dot(d, n1);
  85. float b2 = dot(d, n2);
  86. float t1 = -a1 / b1;
  87. float t2 = -a2 / b2;
  88. float s1 = sign(a1);
  89. float s2 = sign(a2);
  90. float tmin = min(t1, t2);
  91. float tmax = max(t1, t2);
  92. float smin = tmin == t1 ? s1 : s2;
  93. float smax = tmin == t1 ? s2 : s1;
  94. bool e = tmin >= 0.0;
  95. bool f = tmax >= 0.0;
  96. bool g = smin >= 0.0;
  97. bool h = smax >= 0.0;
  98. if (e != g && f == h) return vec2(tmin, tmax);
  99. else if (e == g && f == h) return vec2(-INF_HIT, tmin);
  100. else if (e != g && f != h) return vec2(tmax, +INF_HIT);
  101. else return vec2(NO_HIT);
  102. }
  103. vec4 intersectFlippedWedge(Ray ray, float minAngle, float maxAngle)
  104. {
  105. vec2 planeIntersectMin = intersectHalfSpace(ray, minAngle);
  106. vec2 planeIntersectMax = intersectHalfSpace(ray, maxAngle + czm_pi);
  107. return vec4(planeIntersectMin, planeIntersectMax);
  108. }
  109. vec2 intersectUnitCylinder(Ray ray)
  110. {
  111. vec3 o = ray.pos;
  112. vec3 d = ray.dir;
  113. float a = dot(d.xy, d.xy);
  114. float b = dot(o.xy, d.xy);
  115. float c = dot(o.xy, o.xy) - 1.0;
  116. float det = b * b - a * c;
  117. if (det < 0.0) {
  118. return vec2(NO_HIT);
  119. }
  120. det = sqrt(det);
  121. float ta = (-b - det) / a;
  122. float tb = (-b + det) / a;
  123. float t1 = min(ta, tb);
  124. float t2 = max(ta, tb);
  125. float z1 = o.z + t1 * d.z;
  126. float z2 = o.z + t2 * d.z;
  127. if (abs(z1) >= 1.0)
  128. {
  129. float tCap = (sign(z1) - o.z) / d.z;
  130. t1 = abs(b + a * tCap) < det ? tCap : NO_HIT;
  131. }
  132. if (abs(z2) >= 1.0)
  133. {
  134. float tCap = (sign(z2) - o.z) / d.z;
  135. t2 = abs(b + a * tCap) < det ? tCap : NO_HIT;
  136. }
  137. return vec2(t1, t2);
  138. }
  139. vec2 intersectUnitCircle(Ray ray) {
  140. vec3 o = ray.pos;
  141. vec3 d = ray.dir;
  142. float t = -o.z / d.z;
  143. vec2 zPlanePos = o.xy + d.xy * t;
  144. float distSqr = dot(zPlanePos, zPlanePos);
  145. if (distSqr > 1.0) {
  146. return vec2(NO_HIT);
  147. }
  148. return vec2(t, t);
  149. }
  150. vec2 intersectInfiniteUnitCylinder(Ray ray)
  151. {
  152. vec3 o = ray.pos;
  153. vec3 d = ray.dir;
  154. float a = dot(d.xy, d.xy);
  155. float b = dot(o.xy, d.xy);
  156. float c = dot(o.xy, o.xy) - 1.0;
  157. float det = b * b - a * c;
  158. if (det < 0.0) {
  159. return vec2(NO_HIT);
  160. }
  161. det = sqrt(det);
  162. float t1 = (-b - det) / a;
  163. float t2 = (-b + det) / a;
  164. float tmin = min(t1, t2);
  165. float tmax = max(t1, t2);
  166. return vec2(tmin, tmax);
  167. }
  168. void intersectShape(Ray ray, inout Intersections ix)
  169. {
  170. #if defined(CYLINDER_HAS_RENDER_BOUNDS_RADIUS_MAX) || defined(CYLINDER_HAS_RENDER_BOUNDS_HEIGHT)
  171. ray.pos = ray.pos * u_cylinderUvToRenderBoundsScale + u_cylinderUvToRenderBoundsTranslate;
  172. ray.dir *= u_cylinderUvToRenderBoundsScale;
  173. #else
  174. // Position is converted from [0,1] to [-1,+1] because shape intersections assume unit space is [-1,+1].
  175. // Direction is scaled as well to be in sync with position.
  176. ray.pos = ray.pos * 2.0 - 1.0;
  177. ray.dir *= 2.0;
  178. #endif
  179. #if defined(CYLINDER_HAS_RENDER_BOUNDS_HEIGHT_FLAT)
  180. vec2 outerIntersect = intersectUnitCircle(ray);
  181. #else
  182. vec2 outerIntersect = intersectUnitCylinder(ray);
  183. #endif
  184. setIntersectionPair(ix, CYLINDER_INTERSECTION_INDEX_RADIUS_MAX, outerIntersect);
  185. if (outerIntersect.x == NO_HIT) {
  186. return;
  187. }
  188. #if defined(CYLINDER_HAS_RENDER_BOUNDS_RADIUS_FLAT)
  189. // When the cylinder is perfectly thin it's necessary to sandwich the
  190. // inner cylinder intersection inside the outer cylinder intersection.
  191. // Without this special case,
  192. // [outerMin, outerMax, innerMin, innerMax] will bubble sort to
  193. // [outerMin, innerMin, outerMax, innerMax] which will cause the back
  194. // side of the cylinder to be invisible because it will think the ray
  195. // is still inside the inner (negative) cylinder after exiting the
  196. // outer (positive) cylinder.
  197. // With this special case,
  198. // [outerMin, innerMin, innerMax, outerMax] will bubble sort to
  199. // [outerMin, innerMin, innerMax, outerMax] which will work correctly.
  200. // Note: If initializeIntersections() changes its sorting function
  201. // from bubble sort to something else, this code may need to change.
  202. vec2 innerIntersect = intersectInfiniteUnitCylinder(ray);
  203. setIntersection(ix, 0, outerIntersect.x, true, true); // positive, enter
  204. setIntersection(ix, 1, innerIntersect.x, false, true); // negative, enter
  205. setIntersection(ix, 2, innerIntersect.y, false, false); // negative, exit
  206. setIntersection(ix, 3, outerIntersect.y, true, false); // positive, exit
  207. #elif defined(CYLINDER_HAS_RENDER_BOUNDS_RADIUS_MIN)
  208. Ray innerRay = Ray(ray.pos * u_cylinderUvToRenderRadiusMin, ray.dir * u_cylinderUvToRenderRadiusMin);
  209. vec2 innerIntersect = intersectInfiniteUnitCylinder(innerRay);
  210. setIntersectionPair(ix, CYLINDER_INTERSECTION_INDEX_RADIUS_MIN, innerIntersect);
  211. #endif
  212. #if defined(CYLINDER_HAS_RENDER_BOUNDS_ANGLE_RANGE_UNDER_HALF)
  213. vec2 wedgeIntersect = intersectRegularWedge(ray, u_cylinderRenderAngleMinMax.x, u_cylinderRenderAngleMinMax.y);
  214. setIntersectionPair(ix, CYLINDER_INTERSECTION_INDEX_ANGLE, wedgeIntersect);
  215. #elif defined(CYLINDER_HAS_RENDER_BOUNDS_ANGLE_RANGE_OVER_HALF)
  216. vec4 wedgeIntersect = intersectFlippedWedge(ray, u_cylinderRenderAngleMinMax.x, u_cylinderRenderAngleMinMax.y);
  217. setIntersectionPair(ix, CYLINDER_INTERSECTION_INDEX_ANGLE + 0, wedgeIntersect.xy);
  218. setIntersectionPair(ix, CYLINDER_INTERSECTION_INDEX_ANGLE + 1, wedgeIntersect.zw);
  219. #elif defined(CYLINDER_HAS_RENDER_BOUNDS_ANGLE_RANGE_EQUAL_HALF)
  220. vec2 wedgeIntersect = intersectHalfSpace(ray, u_cylinderRenderAngleMinMax.x);
  221. setIntersectionPair(ix, CYLINDER_INTERSECTION_INDEX_ANGLE, wedgeIntersect);
  222. #elif defined(CYLINDER_HAS_RENDER_BOUNDS_ANGLE_RANGE_EQUAL_ZERO)
  223. vec4 wedgeIntersect = intersectHalfPlane(ray, u_cylinderRenderAngleMinMax.x);
  224. setIntersectionPair(ix, CYLINDER_INTERSECTION_INDEX_ANGLE + 0, wedgeIntersect.xy);
  225. setIntersectionPair(ix, CYLINDER_INTERSECTION_INDEX_ANGLE + 1, wedgeIntersect.zw);
  226. #endif
  227. }