IntersectionUtils.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. //This file is automatically rebuilt by the Cesium build process.
  2. export default "/* Intersection defines\n\
  3. #define INTERSECTION_COUNT ###\n\
  4. */\n\
  5. \n\
  6. #define NO_HIT (-czm_infinity)\n\
  7. #define INF_HIT (czm_infinity * 0.5)\n\
  8. #define RAY_SHIFT (0.000003163)\n\
  9. #define RAY_SCALE (1.003163)\n\
  10. \n\
  11. struct Ray {\n\
  12. vec3 pos;\n\
  13. vec3 dir;\n\
  14. #if defined(SHAPE_BOX)\n\
  15. vec3 dInv;\n\
  16. #endif\n\
  17. };\n\
  18. \n\
  19. struct RayShapeIntersection {\n\
  20. vec4 entry;\n\
  21. vec4 exit;\n\
  22. };\n\
  23. \n\
  24. struct Intersections {\n\
  25. // Don't access these member variables directly - call the functions instead.\n\
  26. \n\
  27. // Store an array of ray-surface intersections. Each intersection is composed of:\n\
  28. // .xyz for the surface normal at the intersection point\n\
  29. // .w for the T value\n\
  30. // The scale of the normal encodes the shape intersection type:\n\
  31. // length(intersection.xyz) = 1: positive shape entry\n\
  32. // length(intersection.xyz) = 2: positive shape exit\n\
  33. // length(intersection.xyz) = 3: negative shape entry\n\
  34. // length(intersection.xyz) = 4: negative shape exit\n\
  35. // INTERSECTION_COUNT is the number of ray-*shape* (volume) intersections,\n\
  36. // so we need twice as many to track ray-*surface* intersections\n\
  37. vec4 intersections[INTERSECTION_COUNT * 2];\n\
  38. \n\
  39. #if (INTERSECTION_COUNT > 1)\n\
  40. // Maintain state for future nextIntersection calls\n\
  41. int index;\n\
  42. int surroundCount;\n\
  43. bool surroundIsPositive;\n\
  44. #endif\n\
  45. };\n\
  46. \n\
  47. RayShapeIntersection getFirstIntersection(in Intersections ix) \n\
  48. {\n\
  49. return RayShapeIntersection(ix.intersections[0], ix.intersections[1]);\n\
  50. }\n\
  51. \n\
  52. vec4 encodeIntersectionType(vec4 intersection, int index, bool entry)\n\
  53. {\n\
  54. float scale = float(index > 0) * 2.0 + float(!entry) + 1.0;\n\
  55. return vec4(intersection.xyz * scale, intersection.w);\n\
  56. }\n\
  57. \n\
  58. // Use defines instead of real functions because WebGL1 cannot access array with non-constant index.\n\
  59. #define setIntersection(/*inout Intersections*/ ix, /*int*/ index, /*float*/ t, /*bool*/ positive, /*bool*/ enter) (ix).intersections[(index)] = vec4(0.0, float(!positive) * 2.0 + float(!enter) + 1.0, 0.0, (t))\n\
  60. #define setIntersectionPair(/*inout Intersections*/ ix, /*int*/ index, /*vec2*/ entryExit) (ix).intersections[(index) * 2 + 0] = vec4(0.0, float((index) > 0) * 2.0 + 1.0, 0.0, (entryExit).x); (ix).intersections[(index) * 2 + 1] = vec4(0.0, float((index) > 0) * 2.0 + 2.0, 0.0, (entryExit).y)\n\
  61. #define setSurfaceIntersection(/*inout Intersections*/ ix, /*int*/ index, /*vec4*/ intersection) (ix).intersections[(index)] = intersection;\n\
  62. #define setShapeIntersection(/*inout Intersections*/ ix, /*int*/ index, /*RayShapeIntersection*/ intersection) (ix).intersections[(index) * 2 + 0] = encodeIntersectionType((intersection).entry, (index), true); (ix).intersections[(index) * 2 + 1] = encodeIntersectionType((intersection).exit, (index), false)\n\
  63. \n\
  64. #if (INTERSECTION_COUNT > 1)\n\
  65. void initializeIntersections(inout Intersections ix) {\n\
  66. // Sort the intersections from min T to max T with bubble sort.\n\
  67. // Note: If this sorting function changes, some of the intersection test may\n\
  68. // need to be updated. Search for \"bubble sort\" to find those areas.\n\
  69. const int sortPasses = INTERSECTION_COUNT * 2 - 1;\n\
  70. for (int n = sortPasses; n > 0; --n) {\n\
  71. for (int i = 0; i < sortPasses; ++i) {\n\
  72. // The loop should be: for (i = 0; i < n; ++i) {...} but WebGL1 cannot\n\
  73. // loop with non-constant condition, so it has to break early instead\n\
  74. if (i >= n) { break; }\n\
  75. \n\
  76. vec4 intersect0 = ix.intersections[i + 0];\n\
  77. vec4 intersect1 = ix.intersections[i + 1];\n\
  78. \n\
  79. bool inOrder = intersect0.w <= intersect1.w;\n\
  80. \n\
  81. ix.intersections[i + 0] = inOrder ? intersect0 : intersect1;\n\
  82. ix.intersections[i + 1] = inOrder ? intersect1 : intersect0;\n\
  83. }\n\
  84. }\n\
  85. \n\
  86. // Prepare initial state for nextIntersection\n\
  87. ix.index = 0;\n\
  88. ix.surroundCount = 0;\n\
  89. ix.surroundIsPositive = false;\n\
  90. }\n\
  91. #endif\n\
  92. \n\
  93. #if (INTERSECTION_COUNT > 1)\n\
  94. RayShapeIntersection nextIntersection(inout Intersections ix) {\n\
  95. vec4 surfaceIntersection = vec4(0.0, 0.0, 0.0, NO_HIT);\n\
  96. RayShapeIntersection shapeIntersection = RayShapeIntersection(surfaceIntersection, surfaceIntersection);\n\
  97. \n\
  98. const int passCount = INTERSECTION_COUNT * 2;\n\
  99. \n\
  100. if (ix.index == passCount) {\n\
  101. return shapeIntersection;\n\
  102. }\n\
  103. \n\
  104. for (int i = 0; i < passCount; ++i) {\n\
  105. // The loop should be: for (i = ix.index; i < passCount; ++i) {...} but WebGL1 cannot\n\
  106. // loop with non-constant condition, so it has to continue instead.\n\
  107. if (i < ix.index) {\n\
  108. continue;\n\
  109. }\n\
  110. \n\
  111. ix.index = i + 1;\n\
  112. \n\
  113. surfaceIntersection = ix.intersections[i];\n\
  114. int intersectionType = int(length(surfaceIntersection.xyz) - 0.5);\n\
  115. bool currShapeIsPositive = intersectionType < 2;\n\
  116. bool enter = intMod(intersectionType, 2) == 0;\n\
  117. \n\
  118. ix.surroundCount += enter ? +1 : -1;\n\
  119. ix.surroundIsPositive = currShapeIsPositive ? enter : ix.surroundIsPositive;\n\
  120. \n\
  121. // entering positive or exiting negative\n\
  122. if (ix.surroundCount == 1 && ix.surroundIsPositive && enter == currShapeIsPositive) {\n\
  123. shapeIntersection.entry = surfaceIntersection;\n\
  124. }\n\
  125. \n\
  126. // exiting positive or entering negative after being inside positive\n\
  127. bool exitPositive = !enter && currShapeIsPositive && ix.surroundCount == 0;\n\
  128. bool enterNegativeFromPositive = enter && !currShapeIsPositive && ix.surroundCount == 2 && ix.surroundIsPositive;\n\
  129. if (exitPositive || enterNegativeFromPositive) {\n\
  130. shapeIntersection.exit = surfaceIntersection;\n\
  131. \n\
  132. // entry and exit have been found, so the loop can stop\n\
  133. if (exitPositive) {\n\
  134. // After exiting positive shape there is nothing left to intersect, so jump to the end index.\n\
  135. ix.index = passCount;\n\
  136. }\n\
  137. break;\n\
  138. }\n\
  139. }\n\
  140. \n\
  141. return shapeIntersection;\n\
  142. }\n\
  143. #endif\n\
  144. \n\
  145. // NOTE: initializeIntersections, nextIntersection aren't even declared unless INTERSECTION_COUNT > 1\n\
  146. ";