Octree.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. //This file is automatically rebuilt by the Cesium build process.
  2. export default "// These octree flags must be in sync with GpuOctreeFlag in VoxelTraversal.js\n\
  3. #define OCTREE_FLAG_INTERNAL 0\n\
  4. #define OCTREE_FLAG_LEAF 1\n\
  5. #define OCTREE_FLAG_PACKED_LEAF_FROM_PARENT 2\n\
  6. \n\
  7. #define OCTREE_MAX_LEVELS 32 // Harcoded value because GLSL doesn't like variable length loops\n\
  8. \n\
  9. uniform sampler2D u_octreeInternalNodeTexture;\n\
  10. uniform vec2 u_octreeInternalNodeTexelSizeUv;\n\
  11. uniform int u_octreeInternalNodeTilesPerRow;\n\
  12. #if (SAMPLE_COUNT > 1)\n\
  13. uniform sampler2D u_octreeLeafNodeTexture;\n\
  14. uniform vec2 u_octreeLeafNodeTexelSizeUv;\n\
  15. uniform int u_octreeLeafNodeTilesPerRow;\n\
  16. #endif\n\
  17. \n\
  18. struct OctreeNodeData {\n\
  19. int data;\n\
  20. int flag;\n\
  21. };\n\
  22. \n\
  23. struct TraversalData {\n\
  24. ivec4 octreeCoords;\n\
  25. int parentOctreeIndex;\n\
  26. };\n\
  27. \n\
  28. struct SampleData {\n\
  29. int megatextureIndex;\n\
  30. ivec4 tileCoords;\n\
  31. vec3 tileUv;\n\
  32. #if (SAMPLE_COUNT > 1)\n\
  33. float weight;\n\
  34. #endif\n\
  35. };\n\
  36. \n\
  37. // Integer mod: For WebGL1 only\n\
  38. int intMod(in int a, in int b) {\n\
  39. return a - (b * (a / b));\n\
  40. }\n\
  41. int normU8_toInt(in float value) {\n\
  42. return int(value * 255.0);\n\
  43. }\n\
  44. int normU8x2_toInt(in vec2 value) {\n\
  45. return int(value.x * 255.0) + 256 * int(value.y * 255.0);\n\
  46. }\n\
  47. float normU8x2_toFloat(in vec2 value) {\n\
  48. return float(normU8x2_toInt(value)) / 65535.0;\n\
  49. }\n\
  50. \n\
  51. OctreeNodeData getOctreeNodeData(in vec2 octreeUv) {\n\
  52. vec4 texData = texture(u_octreeInternalNodeTexture, octreeUv);\n\
  53. \n\
  54. OctreeNodeData data;\n\
  55. data.data = normU8x2_toInt(texData.xy);\n\
  56. data.flag = normU8x2_toInt(texData.zw);\n\
  57. return data;\n\
  58. }\n\
  59. \n\
  60. OctreeNodeData getOctreeChildData(in int parentOctreeIndex, in ivec3 childCoord) {\n\
  61. int childIndex = childCoord.z * 4 + childCoord.y * 2 + childCoord.x;\n\
  62. int octreeCoordX = intMod(parentOctreeIndex, u_octreeInternalNodeTilesPerRow) * 9 + 1 + childIndex;\n\
  63. int octreeCoordY = parentOctreeIndex / u_octreeInternalNodeTilesPerRow;\n\
  64. vec2 octreeUv = u_octreeInternalNodeTexelSizeUv * vec2(float(octreeCoordX) + 0.5, float(octreeCoordY) + 0.5);\n\
  65. return getOctreeNodeData(octreeUv);\n\
  66. }\n\
  67. \n\
  68. int getOctreeParentIndex(in int octreeIndex) {\n\
  69. int octreeCoordX = intMod(octreeIndex, u_octreeInternalNodeTilesPerRow) * 9;\n\
  70. int octreeCoordY = octreeIndex / u_octreeInternalNodeTilesPerRow;\n\
  71. vec2 octreeUv = u_octreeInternalNodeTexelSizeUv * vec2(float(octreeCoordX) + 0.5, float(octreeCoordY) + 0.5);\n\
  72. vec4 parentData = texture(u_octreeInternalNodeTexture, octreeUv);\n\
  73. int parentOctreeIndex = normU8x2_toInt(parentData.xy);\n\
  74. return parentOctreeIndex;\n\
  75. }\n\
  76. \n\
  77. /**\n\
  78. * Convert a position in the uv-space of the tileset bounding shape\n\
  79. * into the uv-space of a tile within the tileset\n\
  80. */\n\
  81. vec3 getTileUv(in vec3 shapePosition, in ivec4 octreeCoords) {\n\
  82. // PERFORMANCE_IDEA: use bit-shifting (only in WebGL2)\n\
  83. float dimAtLevel = pow(2.0, float(octreeCoords.w));\n\
  84. return shapePosition * dimAtLevel - vec3(octreeCoords.xyz);\n\
  85. }\n\
  86. \n\
  87. void getOctreeLeafSampleData(in OctreeNodeData data, in ivec4 octreeCoords, out SampleData sampleData) {\n\
  88. sampleData.megatextureIndex = data.data;\n\
  89. sampleData.tileCoords = (data.flag == OCTREE_FLAG_PACKED_LEAF_FROM_PARENT)\n\
  90. ? ivec4(octreeCoords.xyz / 2, octreeCoords.w - 1)\n\
  91. : octreeCoords;\n\
  92. }\n\
  93. \n\
  94. #if (SAMPLE_COUNT > 1)\n\
  95. void getOctreeLeafSampleDatas(in OctreeNodeData data, in ivec4 octreeCoords, out SampleData sampleDatas[SAMPLE_COUNT]) {\n\
  96. int leafIndex = data.data;\n\
  97. int leafNodeTexelCount = 2;\n\
  98. // Adding 0.5 moves to the center of the texel\n\
  99. float leafCoordXStart = float(intMod(leafIndex, u_octreeLeafNodeTilesPerRow) * leafNodeTexelCount) + 0.5;\n\
  100. float leafCoordY = float(leafIndex / u_octreeLeafNodeTilesPerRow) + 0.5;\n\
  101. \n\
  102. // Get an interpolation weight and a flag to determine whether to read the parent texture\n\
  103. vec2 leafUv0 = u_octreeLeafNodeTexelSizeUv * vec2(leafCoordXStart + 0.0, leafCoordY);\n\
  104. vec4 leafData0 = texture(u_octreeLeafNodeTexture, leafUv0);\n\
  105. float lerp = normU8x2_toFloat(leafData0.xy);\n\
  106. sampleDatas[0].weight = 1.0 - lerp;\n\
  107. sampleDatas[1].weight = lerp;\n\
  108. // TODO: this looks wrong? Should be comparing to OCTREE_FLAG_PACKED_LEAF_FROM_PARENT\n\
  109. sampleDatas[0].tileCoords = (normU8_toInt(leafData0.z) == 1)\n\
  110. ? ivec4(octreeCoords.xyz / 2, octreeCoords.w - 1)\n\
  111. : octreeCoords;\n\
  112. sampleDatas[1].tileCoords = (normU8_toInt(leafData0.w) == 1)\n\
  113. ? ivec4(octreeCoords.xyz / 2, octreeCoords.w - 1)\n\
  114. : octreeCoords;\n\
  115. \n\
  116. // Get megatexture indices for both samples\n\
  117. vec2 leafUv1 = u_octreeLeafNodeTexelSizeUv * vec2(leafCoordXStart + 1.0, leafCoordY);\n\
  118. vec4 leafData1 = texture(u_octreeLeafNodeTexture, leafUv1);\n\
  119. sampleDatas[0].megatextureIndex = normU8x2_toInt(leafData1.xy);\n\
  120. sampleDatas[1].megatextureIndex = normU8x2_toInt(leafData1.zw);\n\
  121. }\n\
  122. #endif\n\
  123. \n\
  124. OctreeNodeData traverseOctreeDownwards(in vec3 shapePosition, inout TraversalData traversalData) {\n\
  125. float sizeAtLevel = 1.0 / pow(2.0, float(traversalData.octreeCoords.w));\n\
  126. vec3 start = vec3(traversalData.octreeCoords.xyz) * sizeAtLevel;\n\
  127. vec3 end = start + vec3(sizeAtLevel);\n\
  128. OctreeNodeData childData;\n\
  129. \n\
  130. for (int i = 0; i < OCTREE_MAX_LEVELS; ++i) {\n\
  131. // Find out which octree child contains the position\n\
  132. // 0 if before center, 1 if after\n\
  133. vec3 center = 0.5 * (start + end);\n\
  134. vec3 childCoord = step(center, shapePosition);\n\
  135. \n\
  136. // Get octree coords for the next level down\n\
  137. ivec4 octreeCoords = traversalData.octreeCoords;\n\
  138. traversalData.octreeCoords = ivec4(octreeCoords.xyz * 2 + ivec3(childCoord), octreeCoords.w + 1);\n\
  139. \n\
  140. childData = getOctreeChildData(traversalData.parentOctreeIndex, ivec3(childCoord));\n\
  141. \n\
  142. if (childData.flag != OCTREE_FLAG_INTERNAL) {\n\
  143. // leaf tile - stop traversing\n\
  144. break;\n\
  145. }\n\
  146. \n\
  147. // interior tile - keep going deeper\n\
  148. start = mix(start, center, childCoord);\n\
  149. end = mix(center, end, childCoord);\n\
  150. traversalData.parentOctreeIndex = childData.data;\n\
  151. }\n\
  152. \n\
  153. return childData;\n\
  154. }\n\
  155. \n\
  156. /**\n\
  157. * Transform a given position to an octree tile coordinate and a position within that tile,\n\
  158. * and find the corresponding megatexture index and texture coordinates\n\
  159. */\n\
  160. void traverseOctreeFromBeginning(in vec3 shapePosition, out TraversalData traversalData, out SampleData sampleDatas[SAMPLE_COUNT]) {\n\
  161. traversalData.octreeCoords = ivec4(0);\n\
  162. traversalData.parentOctreeIndex = 0;\n\
  163. \n\
  164. OctreeNodeData nodeData = getOctreeNodeData(vec2(0.0));\n\
  165. if (nodeData.flag != OCTREE_FLAG_LEAF) {\n\
  166. nodeData = traverseOctreeDownwards(shapePosition, traversalData);\n\
  167. }\n\
  168. \n\
  169. #if (SAMPLE_COUNT == 1)\n\
  170. getOctreeLeafSampleData(nodeData, traversalData.octreeCoords, sampleDatas[0]);\n\
  171. sampleDatas[0].tileUv = getTileUv(shapePosition, sampleDatas[0].tileCoords);\n\
  172. #else\n\
  173. getOctreeLeafSampleDatas(nodeData, traversalData.octreeCoords, sampleDatas);\n\
  174. sampleDatas[0].tileUv = getTileUv(shapePosition, sampleDatas[0].tileCoords);\n\
  175. sampleDatas[1].tileUv = getTileUv(shapePosition, sampleDatas[1].tileCoords);\n\
  176. #endif\n\
  177. }\n\
  178. \n\
  179. bool inRange(in vec3 v, in vec3 minVal, in vec3 maxVal) {\n\
  180. return clamp(v, minVal, maxVal) == v;\n\
  181. }\n\
  182. \n\
  183. bool insideTile(in vec3 shapePosition, in ivec4 octreeCoords) {\n\
  184. vec3 tileUv = getTileUv(shapePosition, octreeCoords);\n\
  185. bool inside = inRange(tileUv, vec3(0.0), vec3(1.0));\n\
  186. // Assume (!) the position is always inside the root tile.\n\
  187. return inside || octreeCoords.w == 0;\n\
  188. }\n\
  189. \n\
  190. void traverseOctreeFromExisting(in vec3 shapePosition, inout TraversalData traversalData, inout SampleData sampleDatas[SAMPLE_COUNT]) {\n\
  191. if (insideTile(shapePosition, traversalData.octreeCoords)) {\n\
  192. for (int i = 0; i < SAMPLE_COUNT; i++) {\n\
  193. sampleDatas[0].tileUv = getTileUv(shapePosition, sampleDatas[0].tileCoords);\n\
  194. }\n\
  195. return;\n\
  196. }\n\
  197. \n\
  198. // Go up tree until we find a parent tile containing shapePosition\n\
  199. for (int i = 0; i < OCTREE_MAX_LEVELS; ++i) {\n\
  200. traversalData.octreeCoords.xyz /= 2;\n\
  201. traversalData.octreeCoords.w -= 1;\n\
  202. \n\
  203. if (insideTile(shapePosition, traversalData.octreeCoords)) {\n\
  204. break;\n\
  205. }\n\
  206. \n\
  207. traversalData.parentOctreeIndex = getOctreeParentIndex(traversalData.parentOctreeIndex);\n\
  208. }\n\
  209. \n\
  210. // Go down tree\n\
  211. OctreeNodeData nodeData = traverseOctreeDownwards(shapePosition, traversalData);\n\
  212. \n\
  213. #if (SAMPLE_COUNT == 1)\n\
  214. getOctreeLeafSampleData(nodeData, traversalData.octreeCoords, sampleDatas[0]);\n\
  215. sampleDatas[0].tileUv = getTileUv(shapePosition, sampleDatas[0].tileCoords);\n\
  216. #else\n\
  217. getOctreeLeafSampleDatas(nodeData, traversalData.octreeCoords, sampleDatas);\n\
  218. sampleDatas[0].tileUv = getTileUv(shapePosition, sampleDatas[0].tileCoords);\n\
  219. sampleDatas[1].tileUv = getTileUv(shapePosition, sampleDatas[1].tileCoords);\n\
  220. #endif\n\
  221. }\n\
  222. ";