@woosh/meep-engine 3.59.0 → 3.60.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/package.json +1 -1
  2. package/src/shade/playground/probe_clipmap/index.html +12 -0
  3. package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
  4. package/src/shade/playground/probe_clipmap/main.js +5 -0
  5. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  6. package/src/shade/renderer/Renderer.js +4 -6
  7. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +63 -1
  8. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  9. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +228 -16
  10. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +27 -4
  11. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
  12. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +526 -23
  13. package/src/shade/renderer/geometry/sdf/cards/MeshCardCaptureMode.d.ts +11 -0
  14. package/src/shade/renderer/geometry/sdf/cards/MeshCardCaptureMode.d.ts.map +1 -0
  15. package/src/shade/renderer/geometry/sdf/cards/MeshCardCaptureMode.js +21 -0
  16. package/src/shade/renderer/geometry/sdf/cards/mesh_cards_raster_pass_descriptor.d.ts +65 -0
  17. package/src/shade/renderer/geometry/sdf/cards/mesh_cards_raster_pass_descriptor.d.ts.map +1 -0
  18. package/src/shade/renderer/geometry/sdf/cards/mesh_cards_raster_pass_descriptor.js +376 -0
  19. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_capture.d.ts +7 -3
  20. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_capture.d.ts.map +1 -1
  21. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_capture.js +70 -6
  22. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_args.d.ts +20 -0
  23. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_args.d.ts.map +1 -0
  24. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_args.js +80 -0
  25. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_scatter.d.ts +18 -0
  26. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_scatter.d.ts.map +1 -0
  27. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_raster_scatter.js +113 -0
  28. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts +47 -0
  29. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts.map +1 -0
  30. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.js +80 -0
  31. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts +91 -0
  32. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts.map +1 -0
  33. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.js +902 -0
  34. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts +16 -0
  35. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts.map +1 -0
  36. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.js +67 -0
  37. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts +17 -0
  38. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts.map +1 -0
  39. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.js +145 -0
  40. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts +12 -0
  41. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts.map +1 -0
  42. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.js +105 -0
  43. package/src/shade/renderer/global_illumination/probe/octahedral/shader_lpv_build_gbuffer.d.ts.map +1 -1
  44. package/src/shade/renderer/global_illumination/probe/octahedral/shader_lpv_build_gbuffer.js +2 -1
  45. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +3 -9
  46. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  47. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +13 -31
  48. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +764 -48
  49. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +410 -0
  50. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +3 -2
  51. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  52. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +4 -3
  53. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +41 -17
  54. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -1
  55. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +57 -33
  56. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.d.ts +11 -3
  57. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.d.ts.map +1 -1
  58. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.js +13 -4
  59. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts +9 -18
  60. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts.map +1 -1
  61. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.js +8 -10
  62. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap.d.ts +12 -0
  63. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap.d.ts.map +1 -1
  64. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap.js +28 -0
  65. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts +1 -29
  66. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts.map +1 -1
  67. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.js +1 -74
  68. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK.d.ts +161 -0
  69. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK.d.ts.map +1 -0
  70. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK.js +219 -0
  71. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK_INSTANCE_STRUCT.d.ts +1 -8
  72. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK_INSTANCE_STRUCT.d.ts.map +1 -1
  73. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK_INSTANCE_STRUCT.js +1 -9
  74. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MeshSDFBrickProvider.d.ts +40 -12
  75. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MeshSDFBrickProvider.d.ts.map +1 -1
  76. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MeshSDFBrickProvider.js +373 -31
  77. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +2 -1
  78. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts.map +1 -1
  79. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +2 -1
  80. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_texel.d.ts +15 -8
  81. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_texel.d.ts.map +1 -1
  82. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_texel.js +28 -14
  83. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_walk.d.ts +23 -0
  84. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_walk.d.ts.map +1 -0
  85. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_walk.js +66 -0
  86. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_batch.d.ts +29 -0
  87. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_batch.d.ts.map +1 -0
  88. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_batch.js +210 -0
  89. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_command.d.ts +29 -0
  90. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_command.d.ts.map +1 -0
  91. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_command.js +86 -0
  92. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_gather.d.ts +41 -0
  93. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_gather.d.ts.map +1 -0
  94. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_gather.js +439 -0
  95. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_resolve.d.ts +23 -0
  96. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_resolve.d.ts.map +1 -0
  97. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_resolve.js +135 -0
  98. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_free.d.ts +3 -1
  99. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_free.d.ts.map +1 -1
  100. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_free.js +12 -3
  101. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +21 -18
  102. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  103. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +254 -73
  104. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +149 -8
  105. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
  106. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +181 -13
  107. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +179 -7
  108. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
  109. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +412 -31
  110. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.js +4 -4
  111. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -1
  112. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +4 -3
  113. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +36 -10
  114. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts.map +1 -1
  115. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js +218 -29
  116. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.d.ts +5 -1
  117. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.d.ts.map +1 -1
  118. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.js +24 -14
  119. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts +15 -6
  120. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts.map +1 -1
  121. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.js +21 -22
  122. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_guide.d.ts +36 -0
  123. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_guide.d.ts.map +1 -0
  124. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_guide.js +257 -0
  125. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.d.ts +18 -7
  126. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.d.ts.map +1 -1
  127. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.js +157 -51
  128. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_order.d.ts +23 -0
  129. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_order.d.ts.map +1 -0
  130. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_order.js +110 -0
  131. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts +24 -2
  132. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts.map +1 -1
  133. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.js +90 -10
  134. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_ray_layout.d.ts +45 -0
  135. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_ray_layout.d.ts.map +1 -0
  136. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_ray_layout.js +205 -0
  137. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.js +1 -1
  138. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.d.ts +16 -3
  139. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.d.ts.map +1 -1
  140. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.js +55 -10
  141. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts +19 -4
  142. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts.map +1 -1
  143. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.js +60 -6
  144. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts +10 -9
  145. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  146. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +32 -39
  147. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts +21 -14
  148. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
  149. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +100 -30
  150. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace_command.d.ts +6 -2
  151. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace_command.d.ts.map +1 -1
  152. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace_command.js +26 -10
  153. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.d.ts +3 -2
  154. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.d.ts.map +1 -1
  155. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.js +12 -12
  156. package/src/shade/renderer/gpu_primitive/sort/SORT_DIGIT_SETTINGS_STRUCT.d.ts +10 -0
  157. package/src/shade/renderer/gpu_primitive/sort/SORT_DIGIT_SETTINGS_STRUCT.d.ts.map +1 -0
  158. package/src/shade/renderer/gpu_primitive/sort/SORT_DIGIT_SETTINGS_STRUCT.js +21 -0
  159. package/src/shade/renderer/gpu_primitive/sort/SORT_PASS_SETTINGS_STRUCT.d.ts +5 -2
  160. package/src/shade/renderer/gpu_primitive/sort/SORT_PASS_SETTINGS_STRUCT.d.ts.map +1 -1
  161. package/src/shade/renderer/gpu_primitive/sort/SORT_PASS_SETTINGS_STRUCT.js +31 -23
  162. package/src/shade/renderer/gpu_primitive/sort/SORT_SIZE_STRUCT.d.ts +10 -0
  163. package/src/shade/renderer/gpu_primitive/sort/SORT_SIZE_STRUCT.d.ts.map +1 -0
  164. package/src/shade/renderer/gpu_primitive/sort/SORT_SIZE_STRUCT.js +22 -0
  165. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_constants.d.ts +9 -0
  166. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_constants.d.ts.map +1 -0
  167. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_constants.js +18 -0
  168. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_digit.d.ts +8 -3
  169. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_digit.d.ts.map +1 -1
  170. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_digit.js +41 -32
  171. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_histogram_tile.d.ts +31 -0
  172. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_histogram_tile.d.ts.map +1 -0
  173. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_histogram_tile.js +71 -0
  174. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_scatter_tile.d.ts +47 -0
  175. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_scatter_tile.d.ts.map +1 -0
  176. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_scatter_tile.js +210 -0
  177. package/src/shade/renderer/gpu_primitive/sort/defs.d.ts +5 -4
  178. package/src/shade/renderer/gpu_primitive/sort/defs.d.ts.map +1 -1
  179. package/src/shade/renderer/gpu_primitive/sort/defs.js +5 -4
  180. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts +56 -15
  181. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -1
  182. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +410 -61
  183. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram.d.ts +4 -1
  184. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram.d.ts.map +1 -1
  185. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram.js +16 -42
  186. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram_indirect.d.ts +15 -0
  187. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram_indirect.d.ts.map +1 -0
  188. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_histogram_indirect.js +60 -0
  189. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_prepare.d.ts +25 -0
  190. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_prepare.d.ts.map +1 -0
  191. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_prepare.js +89 -0
  192. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter.d.ts +3 -8
  193. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter.d.ts.map +1 -1
  194. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter.js +28 -160
  195. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter_indirect.d.ts +12 -0
  196. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter_indirect.d.ts.map +1 -0
  197. package/src/shade/renderer/gpu_primitive/sort/shader_radix_sort_scatter_indirect.js +74 -0
  198. package/src/shade/renderer/gpu_primitive/sort/verify_radix_sort.d.ts +3 -1
  199. package/src/shade/renderer/gpu_primitive/sort/verify_radix_sort.d.ts.map +1 -1
  200. package/src/shade/renderer/gpu_primitive/sort/verify_radix_sort.js +387 -188
  201. package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_irradiance_flat.js +1 -1
  202. package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_sh.js +1 -1
  203. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  204. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +90 -72
  205. package/src/shade/renderer/material/resident/RESIDENT_MATERIAL_TEXTURE_LAYOUT.d.ts +5 -0
  206. package/src/shade/renderer/material/resident/RESIDENT_MATERIAL_TEXTURE_LAYOUT.d.ts.map +1 -1
  207. package/src/shade/renderer/material/resident/RESIDENT_MATERIAL_TEXTURE_LAYOUT.js +9 -0
  208. package/src/shade/renderer/path_tracer/shader/INDIRECT_TEXTURE_FILTER.d.ts +13 -0
  209. package/src/shade/renderer/path_tracer/shader/INDIRECT_TEXTURE_FILTER.d.ts.map +1 -0
  210. package/src/shade/renderer/path_tracer/shader/INDIRECT_TEXTURE_FILTER.js +14 -0
  211. package/src/shade/renderer/path_tracer/shader/IndirectTextureFilter.d.ts +10 -0
  212. package/src/shade/renderer/path_tracer/shader/IndirectTextureFilter.d.ts.map +1 -0
  213. package/src/shade/renderer/path_tracer/shader/IndirectTextureFilter.js +15 -0
  214. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_tangent_normal.d.ts +4 -3
  215. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_tangent_normal.d.ts.map +1 -1
  216. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_tangent_normal.js +6 -5
  217. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_texture.d.ts +17 -2
  218. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_texture.d.ts.map +1 -1
  219. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_texture.js +25 -57
  220. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_texture_exact.d.ts +13 -0
  221. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_texture_exact.d.ts.map +1 -0
  222. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_texture_exact.js +70 -0
  223. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_texture_stochastic.d.ts +10 -0
  224. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_texture_stochastic.d.ts.map +1 -0
  225. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_texture_stochastic.js +59 -0
  226. package/src/shade/renderer/path_tracer/shader/chunk_indirect_texture_load.d.ts +12 -0
  227. package/src/shade/renderer/path_tracer/shader/chunk_indirect_texture_load.d.ts.map +1 -0
  228. package/src/shade/renderer/path_tracer/shader/chunk_indirect_texture_load.js +49 -0
  229. package/src/shade/renderer/path_tracer/shader/chunk_ray_hit_to_opacity.d.ts.map +1 -1
  230. package/src/shade/renderer/path_tracer/shader/chunk_ray_hit_to_opacity.js +1 -0
  231. package/src/shade/renderer/path_tracer/shader/chunk_render_trace_path.d.ts.map +1 -1
  232. package/src/shade/renderer/path_tracer/shader/chunk_render_trace_path.js +1 -0
  233. package/src/shade/renderer/path_tracer/shader/chunk_sample_material.d.ts.map +1 -1
  234. package/src/shade/renderer/path_tracer/shader/chunk_sample_material.js +2 -1
  235. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts +7 -0
  236. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts.map +1 -1
  237. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.js +15 -6
  238. package/src/shade/renderer/scene/GPUSceneContext.d.ts +7 -1
  239. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  240. package/src/shade/renderer/scene/GPUSceneContext.js +26 -1
  241. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.d.ts +7 -7
  242. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.d.ts.map +1 -1
  243. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.js +262 -294
  244. package/src/shade/renderer/shader/chunk/filter/MULTISCALE_MEAN_STRUCT.d.ts +9 -0
  245. package/src/shade/renderer/shader/chunk/filter/MULTISCALE_MEAN_STRUCT.d.ts.map +1 -0
  246. package/src/shade/renderer/shader/chunk/filter/MULTISCALE_MEAN_STRUCT.js +21 -0
  247. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts +43 -0
  248. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts.map +1 -0
  249. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.js +87 -0
  250. package/src/shade/renderer/shader/chunk/noise/r/chunk_r2_canonical.d.ts +7 -1
  251. package/src/shade/renderer/shader/chunk/noise/r/chunk_r2_canonical.d.ts.map +1 -1
  252. package/src/shade/renderer/shader/chunk/noise/r/chunk_r2_canonical.js +1 -1
  253. package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_reserve_workgroup.d.ts +21 -0
  254. package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_reserve_workgroup.d.ts.map +1 -0
  255. package/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_reserve_workgroup.js +42 -0
  256. package/src/shade/renderer/wind/GPUSceneWind.d.ts +1 -1
  257. package/src/shade/wgsl/emulator/CPUBitmapData.d.ts +19 -0
  258. package/src/shade/wgsl/emulator/CPUBitmapData.d.ts.map +1 -1
  259. package/src/shade/wgsl/emulator/CPUBitmapData.js +27 -0
  260. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  261. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +65 -19
  262. package/src/view/elements/progress/segmented/GhostTrail.d.ts +116 -0
  263. package/src/view/elements/progress/segmented/GhostTrail.d.ts.map +1 -0
  264. package/src/view/elements/progress/segmented/GhostTrail.js +280 -0
  265. package/src/view/elements/progress/segmented/RESOURCE_BAR_SEGMENTS.d.ts +3 -1
  266. package/src/view/elements/progress/segmented/RESOURCE_BAR_SEGMENTS.d.ts.map +1 -1
  267. package/src/view/elements/progress/segmented/RESOURCE_BAR_SEGMENTS.js +3 -1
  268. package/src/view/elements/progress/segmented/SEGMENT_TIERS_DEFAULT.d.ts +11 -0
  269. package/src/view/elements/progress/segmented/SEGMENT_TIERS_DEFAULT.d.ts.map +1 -0
  270. package/src/view/elements/progress/segmented/SEGMENT_TIERS_DEFAULT.js +15 -0
  271. package/src/view/elements/progress/segmented/SegmentDefinition.d.ts +3 -0
  272. package/src/view/elements/progress/segmented/SegmentDefinition.d.ts.map +1 -1
  273. package/src/view/elements/progress/segmented/SegmentDefinition.js +3 -0
  274. package/src/view/elements/progress/segmented/SegmentTier.d.ts +38 -0
  275. package/src/view/elements/progress/segmented/SegmentTier.d.ts.map +1 -0
  276. package/src/view/elements/progress/segmented/SegmentTier.js +50 -0
  277. package/src/view/elements/progress/segmented/SegmentedResourceBarView.d.ts +163 -10
  278. package/src/view/elements/progress/segmented/SegmentedResourceBarView.d.ts.map +1 -1
  279. package/src/view/elements/progress/segmented/SegmentedResourceBarView.js +442 -101
  280. package/src/view/elements/progress/segmented/playground/index.html +78 -0
  281. package/src/view/elements/progress/segmented/playground/main.d.ts +2 -0
  282. package/src/view/elements/progress/segmented/playground/main.d.ts.map +1 -0
  283. package/src/view/elements/progress/segmented/playground/main.js +173 -0
  284. package/src/view/elements/progress/segmented/segment_cell_layout.d.ts +48 -0
  285. package/src/view/elements/progress/segmented/segment_cell_layout.d.ts.map +1 -0
  286. package/src/view/elements/progress/segmented/segment_cell_layout.js +75 -0
  287. package/src/view/elements/progress/segmented/segment_notch_place.d.ts +18 -0
  288. package/src/view/elements/progress/segmented/segment_notch_place.d.ts.map +1 -0
  289. package/src/view/elements/progress/segmented/segment_notch_place.js +28 -0
  290. package/src/view/elements/progress/segmented/segment_tick_positions.d.ts +32 -0
  291. package/src/view/elements/progress/segmented/segment_tick_positions.d.ts.map +1 -0
  292. package/src/view/elements/progress/segmented/segment_tick_positions.js +103 -0
  293. package/src/view/elements/progress/segmented/segmented-resource-bar.css +142 -0
  294. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_provider.d.ts +0 -35
  295. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_provider.d.ts.map +0 -1
  296. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_provider.js +0 -238
  297. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGEO_BRICK.d.ts +0 -99
  298. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGEO_BRICK.d.ts.map +0 -1
  299. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGEO_BRICK.js +0 -139
  300. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGeoBrickProvider.d.ts +0 -65
  301. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGeoBrickProvider.d.ts.map +0 -1
  302. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGeoBrickProvider.js +0 -393
  303. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_box.d.ts +0 -17
  304. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_box.d.ts.map +0 -1
  305. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_box.js +0 -36
  306. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_pair.d.ts +0 -29
  307. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_pair.d.ts.map +0 -1
  308. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_pair.js +0 -108
  309. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_texel.d.ts +0 -31
  310. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_texel.d.ts.map +0 -1
  311. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_texel.js +0 -113
  312. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_triangle.d.ts +0 -36
  313. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_triangle.d.ts.map +0 -1
  314. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_triangle.js +0 -85
  315. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_distance.d.ts +0 -23
  316. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_distance.d.ts.map +0 -1
  317. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_distance.js +0 -273
  318. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_gather.d.ts +0 -13
  319. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_gather.d.ts.map +0 -1
  320. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_gather.js +0 -151
  321. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_traverse.d.ts +0 -13
  322. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_traverse.d.ts.map +0 -1
  323. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_traverse.js +0 -133
  324. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_wait.d.ts +0 -22
  325. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_wait.d.ts.map +0 -1
  326. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_wait.js +0 -135
@@ -0,0 +1,410 @@
1
+ # Probe rays: a variable count per probe, sorted for coherence — scope
2
+
3
+ 2026-10-30. Scoped against master at `309823e49`. Since built: stage 1 (`0ec7a5fc3`), stage 2
4
+ (`b825bd46c`, its as-built note in the proposal's §8.6) and the sort's generalisation (`053a1c8ba`).
5
+ The sorted rays were built, measured on both GPUs on Sponza and Emerald Square, and not shipped
6
+ ("Measured" under §2). Nor were the local sorts that followed (chunks, bins, a hash control, within
7
+ each probe, position bits); the trace list in the probes' Morton order ships instead ("Local sorts,
8
+ measured" under §2).
9
+
10
+ ## What was asked
11
+
12
+ 1. **A variable number of rays per probe update, as Enshrouded does it.**
13
+ - A probe whose short-term mean dominates (it is changing) takes more rays.
14
+ - A converged probe sips rays, except at the regular uniform updates that keep its depth and its
15
+ estimator fed.
16
+ - A DEAD probe shoots the minimum.
17
+ 2. **Rays sorted (binned) for coherence** by one key: a short Morton code of the origin together
18
+ with the octahedral direction.
19
+
20
+ Enshrouded, as §2.1 records it from the talk's captions:
21
+ - a new probe asks for 512 rays and decays fast to 16, rising again when it sees change;
22
+ - requests are scaled down to the frame's budget, and rays are batched by a probe-index scan;
23
+ - rays are sorted by position and direction, and hits by kind;
24
+ - DEAD probes still trace 16 rays a frame.
25
+
26
+ Sorting hits by kind was not asked for and stays out.
27
+
28
+ ## Where the fixed R lives today
29
+
30
+ Every pass that touches rays assumes R rays for each listed probe, at offset `k·R`.
31
+
32
+ | Where | What assumes R |
33
+ |---|---|
34
+ | schedule, due | `U = ⌊ray_budget / R⌋` probes a frame; `T = ⌈P_w / U⌉` |
35
+ | `shader_probe_clipmap_trace_command` | the ray dispatch is `traced × R` |
36
+ | trace, light, shade, want_hits | ray thread → probe `ray / R`, its ray `ray % R` |
37
+ | accumulate | `first_ray = k·R`; uniform rounds `R / n_r²`; guided runs inside `[0, R)` |
38
+ | guide (weights, starts) | the hold `(64 − 2 − R/n_r²)/R`; the starts walk `R` rays |
39
+ | `chunk_probe_clipmap_ray_texel` | the uniform ray↔texel map: powers of two, `R ∈ [n_r²/4, 4·n_r²]` |
40
+ | project | classification's "was this update guided" test takes R |
41
+ | `probe_rays` | sized `U·R` = the budget |
42
+
43
+ The per-probe passes (relocate, the guide's three, accumulate, project, publish) cost by listed
44
+ probe, not by ray. Accumulate was 0.43–0.68 ms on the iGPU at 512 probes. U keeps bounding them.
45
+
46
+ ## 1. A variable ray count
47
+
48
+ ### The update kinds and their rays
49
+
50
+ | Update | Rays | Why |
51
+ |---|---|---|
52
+ | a probe's first (NEW) | `R_new` (Enshrouded 512, two a texel at n_r = 16), uniform | a new probe sees its whole sphere at once |
53
+ | uniform: every 5th, every DEAD one | `R_u = n_r²`, one a texel, as today | keeps depth, classification and every texel's estimator fed |
54
+ | guided | the probe's request, in `[R_min, R_max]` | change takes rays, a converged probe sips |
55
+ | DEAD | `R_min`, uniform | see fork F4 |
56
+
57
+ ### The request: from the probe, not the texel (measured)
58
+
59
+ The estimator's per-texel inconsistency is the natural reading of "short-term mean dominates", but it
60
+ cannot carry the request. Measured on the emulator through the shipped accumulate pass, eight streams,
61
+ short blend 0.18:
62
+ - a steady one-ray texel (σ = μ) reads 0.27 on average, 0.41 at p90;
63
+ - after a ×2 step it reads 0.35 over updates 10–40, and after +30% it reads 0.29, both inside its
64
+ own noise;
65
+ - a texel lit by one ray in five reads 0.29 steady and 0.35–0.37 after either step;
66
+ - at the blend of a texel the guide passes over (0.63) it reads 0.87 whatever happens.
67
+
68
+ **Recommended signal: the same gap test, over the whole probe.** Take Σ over the probe's texels of
69
+ (sample − long mean), luminance-weighted, against that sum's own noise, √Σ deviation².
70
+ - Over 256 texels its noise is 16× smaller. A probe-wide +30% shift on one-ray texels is about
71
+ 0.3·√256 ≈ 4.8 noise units in one update. That figure is derived, not measured; stage 0 measures it.
72
+ - The accumulate thread already holds the sample, the mean and the deviation.
73
+ - Projection's rows pass and probe pass already reduce per probe; they would carry the sum into the
74
+ probe.
75
+ - A NEW probe's request decays with its texels' count, Enshrouded's "decays fast".
76
+ - The constants come from the measured distributions of this signal (steady against changed), not
77
+ from round numbers.
78
+
79
+ Changing probes then take more rays, so their samples' deviation shrinks as 1/√rays. That is what
80
+ the estimator's own catch-up needs to engage sooner on the post-load shift measured on 2026-10-30. It
81
+ only helps if the request sees the change, which per-texel inconsistency does not.
82
+
83
+ ### The budget, the offsets, the dispatch
84
+
85
+ - **U stays `⌊budget / R_u⌋`**, so a frame of all-uniform updates fits exactly as it does today, and
86
+ the period `T = ⌈P_w/U⌉` is unchanged.
87
+ - **Guided requests fill what's left, scaled down when over budget** (Enshrouded's "requests scaled to
88
+ the budget"). The scale comes from the previous frame's demand, so one scan suffices.
89
+ - **Offsets come from one exclusive scan** of the listed probes' ray counts (Enshrouded's
90
+ "probe-index scan"):
91
+ - `graph_prefix_scan_csdldf`, ≤ U elements, indirect over the list's count;
92
+ - it gives each probe's first ray and the frame's total;
93
+ - the ray dispatch is built from the total, the way the mesh expansion does it with
94
+ `shader_prefix_sum_to_command`.
95
+ - **A ray finds its probe by `lower_bound_branchless` over the offsets**: the mesh expansion's chunk,
96
+ at most log₂U + 1 steps.
97
+ - **The request's storage:** the record is full (64 B; `sh` takes bytes 32–63), and `screen` is a u32
98
+ holding one bit. The request packs into its upper bits (fork F6).
99
+ - **In a converged scene, guided updates run at R_min**, so the frame traces fewer rays than the
100
+ budget. The saving is trace time: 6.8–7.6 ms on the iGPU and 0.34–0.47 ms on the 4090 at Sponza
101
+ today (guiding's paired numbers).
102
+
103
+ ### Forks
104
+
105
+ - **F1. Schedule: keep the period, vary rays per update (recommended)**, rather than Enshrouded's
106
+ every probe every frame. The per-probe passes scale with listed probes. Accumulate at 512 probes on
107
+ the iGPU is 0.43–0.68 ms, so all 4,600 of Sponza's probes every frame would be about 4–6 ms
108
+ (derived).
109
+ - **F2. Over budget: scale the guided requests (recommended)**, rather than stretching T. Scaling
110
+ keeps every probe's cadence, including the changing ones'.
111
+ - **F3. Weigh a sample by its rays in the estimator (recommended, same stage).** Measured in the
112
+ review: one one-ray uniform sample every 5th update, mixed into a 16-ray guided stream, raised the
113
+ long mean's error 4.1 → 7.3% at β 0.18. Variable rays widen the spread from 0 to 64 rays a texel.
114
+ The reference estimator has no weights, so this is measured on the emulator before it lands.
115
+ - **F4. DEAD: every period at R_min (recommended)**, against today's every 8 periods at R.
116
+ - It reacts 8× sooner for fewer rays.
117
+ - R_min comes from the classification's tolerance. The back-face share's binomial deviation at the
118
+ 25% threshold is ±11% at 16 rays, ±6% at 48 and ±5% at 64.
119
+ - Below n_r²/4 rays the uniform map's assertion lifts; the spread map already covers every texel
120
+ over n_r²/R updates.
121
+ - **F5. R_max:** bounded by the 64-a-texel gather (`PROBE_TEXEL_RAYS`), by the depth limit
122
+ `R ≤ 64·n_d²`, and by the budget. Its value comes from stage 2's measurement.
123
+ - **F6. The request's storage:** pack it into `screen` (recommended), or grow the record to 80 B.
124
+
125
+ ## 2. Sorted rays
126
+
127
+ ### Design
128
+
129
+ - **Key, one u32:**
130
+ - origin: the Morton code of the probe's lattice coordinate inside its cascade's window (32³:
131
+ 15 bits) plus its cascade (5 cascades: 3 bits);
132
+ - direction: the ray's octahedral texel, coarsened to 8×8 bins (6 bits, UE's count);
133
+ - 24 bits in all.
134
+ - **Key pass:** a thread a ray over the frame's live total. The probe comes from `lower_bound` over
135
+ the offsets, and the texel from the update's map (the uniform map, or the guide's search the trace
136
+ already does). The value is the ray's index.
137
+ - **Sort: `graph_radix_sort`, generalised, not copied.** It is the engine's sort, and the LBVH
138
+ build is its one caller. Two changes:
139
+ - it dispatches over a host element count today, which here would be the budget's capacity; it
140
+ must follow the live total, indirect (the rule that GPU work follows the live count);
141
+ - it always runs four 8-bit digit passes, 12 dispatches; a key-width option makes a 24-bit key
142
+ three passes, 9 dispatches.
143
+ - The batch pass's bitonic sort (≤ 64 rows in workgroup memory, inside a dispatch that runs anyway)
144
+ is a different scale and is not a candidate.
145
+ - **Consumers:** trace, light and shade take `ray = order[thread]`. Their outputs stay at the ray's
146
+ index, so want_hits, accumulate and projection do not change.
147
+ - **Layout fork, measured in stage 0:**
148
+ - direction-major: UE's `SortProbeTraceTilesCS` bins 64 directions, with Morton position a todo;
149
+ - origin-major: today's grouping by probe, with directions ordered within it;
150
+ - interleaved.
151
+
152
+ ### Not known; stage 0 measures it
153
+
154
+ - The sort's cost at the budget, 131,072 keys, on both GPUs. No measurement is recorded.
155
+ - Trace, light and shade time in sorted order against today's. Today a 64-lane wave is one probe's
156
+ origin over four octahedral rows (uniform) or a run of the walk (guided).
157
+ - The scattered writes: sorted threads write 28-B records at the ray's index.
158
+ - Context: S3f's incoherent rays cost about 18× a coherent screen ray on the 4090 and about 5× on the
159
+ iGPU. That benchmark predates the probe ray layout.
160
+
161
+ ### Key layouts to measure (Alex, 2026-10-30)
162
+
163
+ Four keys, plus today's unsorted order as the baseline. Each is timed as its whole cost: key pass,
164
+ sort, trace, light and shade. Both GPUs, paired in one process (the key pass swapped by pipeline),
165
+ Sponza with the caches resident. The direction bin is fixed at 8×8 octahedral bins (6 bits) for all
166
+ four.
167
+
168
+ **Two origin encodings:**
169
+ - **O1, per cascade:** the Morton code of the probe's lattice coordinate inside its own cascade's
170
+ window, 5 bits an axis at 32³ (15 bits), with the cascade's 3 bits above it. 18 bits.
171
+ - **O2, one domain:** the Morton code of the probe's position inside the coarsest cascade's window,
172
+ with no cascade bits.
173
+ - That window spans 2^(C−1)·32 cascade-0 spacings: 512 at C = 5.
174
+ - Telling cascade-0 probes apart takes 9 bits an axis (27). Beside 6 direction bits that is 33, so
175
+ O2 takes 8 bits an axis (24): a cell of two cascade-0 spacings, where a pair of cascade-0 probes
176
+ can share a code.
177
+
178
+ **Two direction placements:**
179
+ - **D-high, `[direction | origin]`:** rays bucket by direction across probes, as UE's 64 bins do.
180
+ - **D-low, `[origin | direction]`:** rays bucket by probe position, in direction order within each.
181
+
182
+ | Key | Bits | Radix passes |
183
+ |---|---|---|
184
+ | O1 D-high | 24 | 3 |
185
+ | O1 D-low | 24 | 3 |
186
+ | O2 D-high | 30 | 4 |
187
+ | O2 D-low | 30 | 4 |
188
+
189
+ The pass counts differ, so the sort's own cost is part of each key's comparison.
190
+
191
+ ### Measured (2026-10-30): no key beats unsorted, so none ships
192
+
193
+ Built as stage 3 lays it out, on top of stage 2's variable rays:
194
+ - a key pass, a thread of the rays' launch, which finds each ray's texel as the trace does;
195
+ - `graph_radix_sort` over the launch's threads, counted on the device (the ray command writes them),
196
+ with the threads past the last ray keyed past every ray, so that they sort to the end in their own
197
+ order;
198
+ - trace, shade and light take `ray = order[thread]`.
199
+
200
+ **How it was measured.** Sponza, and NVIDIA's Emerald Square (day, 2.69M triangles, 230 m a side;
201
+ textures held to 1024² on the iGPU). The caches were resident, the clock at 60 Hz, and the camera and
202
+ the light still. Emerald was measured from two views: down an avenue at 1.7 m, and from 29 m over the
203
+ square. Each round ran every arm once in a seeded shuffled order: 8 frames unmeasured, then 24
204
+ measured. There were 8 rounds on the 4090 and 4 on the iGPU. Two of the arms are unsorted, and their
205
+ agreement is the noise. "Unsorted" runs the key pass as an identity, writing each thread's own index.
206
+
207
+ The figures are the GPU's busy time from relocation's start to the light pass's end, a frame, in µs,
208
+ as means. A frame's rays swing with the schedule's turn, between about 30k and 105k on Emerald. A
209
+ median taken category by category picks a different kind of frame for each category, and this
210
+ section's first tables, medians, read a 3× faster trace beside a 13× slower sort. The sorted arms are
211
+ given against the mean of the two unsorted runs.
212
+
213
+ **At the rays variable rays leave** (a still scene, most probes sipping):
214
+
215
+ | Scene, GPU | Rays a frame | Unsorted (two runs) | O1 D-high | O1 D-low | O2 D-high | O2 D-low |
216
+ |---|---|---|---|---|---|---|
217
+ | Emerald avenue, 4090 | ~33k | 588.6 / 600.3 | +76 | +75 | +103 | +112 |
218
+ | Emerald overview, 4090 | ~29k | 412.0 / 407.7 | +91 | +79 | +96 | +101 |
219
+ | Sponza, 4090 | ~51k | 834.1 / 880.7 | +90 | +130 | +205 | +190 |
220
+ | Emerald avenue, iGPU | ~32k | 6,848 / 6,110 | +1,830 | +1,049 | +1,821 | +1,232 |
221
+ | Sponza, iGPU | ~59k | 5,651 / 5,653 | +2,466 | +624 | +2,607 | +547 |
222
+
223
+ **At about 120k rays a frame**, every update asked for at least 256 rays (one a texel at n_r = 16; a
224
+ measurement-only floor), the budget's 131,072 scaling the rest:
225
+
226
+ | Scene, GPU | Rays a frame | Unsorted (two runs) | O1 D-high | O1 D-low | O2 D-high | O2 D-low |
227
+ |---|---|---|---|---|---|---|
228
+ | Emerald avenue, 4090 | ~127k | 767.7 / 772.1 | +15 | +16 | +65 | +84 |
229
+ | Emerald overview, 4090 | ~117k | 943.3 / 919.4 | +189 | +161 | +298 | +743 |
230
+ | Sponza, 4090 | ~120k | 1,507 / 1,426 | +340 | +324 | +40 | +342 |
231
+ | Emerald avenue, iGPU | ~125k | 15,317 / 15,358 | +2,877 | +429 | +4,101 | +1,521 |
232
+ | Sponza, iGPU | ~123k | 11,603 / 11,546 | +4,485 | +1,248 | +4,401 | +1,803 |
233
+
234
+ - **No key beats unsorted, on either GPU, in any scene or view, at either count.**
235
+ - **The trace does gain at the higher count, on Emerald's avenue.** On the 4090 it drops 11% with O1
236
+ D-high (618.5 → 549.5 µs; the unsorted runs agree within 0.5 µs). On the iGPU it drops 6% with O1
237
+ D-low, and shade 11% (−763 and −232 µs).
238
+ - Keying and sorting cost more than that: about 75 µs on the 4090 (13 dispatches, latency-bound), and
239
+ on the iGPU 1.49 ms (the key pass 328 µs past the identity's, the sort 1.13 ms).
240
+ - At the lower count the trace does not move on either GPU.
241
+ - **Direction-major keys (D-high) slow shade and light on both GPUs**: on the iGPU by 20–70% across
242
+ trace, shade and light. A ray's record, 28 bytes when measured (`PROBE_RAY_STRUCT`; 24 since its light became one RGB9E5
243
+ word), stays at the ray's own index.
244
+ - Sorted threads read and write those records out of order, about twice the 32-byte sectors a
245
+ record.
246
+ - A wave of one direction also reads the origins and records of many probes, and the light pass's
247
+ probe taps around many hits.
248
+ - **The 4090's overview and Sponza read high at 120k for every key:** their shade, sort and scans
249
+ measure 2–4× the avenue's at the same count, with 30–170 µs of idle gaps inside the stretch. The
250
+ direction of the result holds in every case; those cases' size is uncertain.
251
+ - **A lead, since shipped** (below). Origin-major order's gain could be had without sorting rays: order the trace
252
+ list, at most U probes, by the probes' Morton codes, and the rays' layout follows it.
253
+ - Its measured upper bound is O1 D-low's change to trace, shade and light. On Emerald's avenue at
254
+ 125k rays that is −1.0 ms of the iGPU's 15.3 ms, and −49 µs on the 4090. At the lower count, and
255
+ on Sponza, it is about none.
256
+ - **Not shipped.** The wiring is reverted. It is kept, with the measurement-only floor, as
257
+ `stage3b_sorted_rays_v2.patch` and `stage3b_shader_probe_clipmap_ray_keys.js` in the session's
258
+ scratchpad. The harness is `device/sortab.js` there. The sort's generalisation landed first
259
+ (`053a1c8ba`: `key_bits` and the device count). The BVH build is its only caller, and that caller
260
+ uses neither.
261
+
262
+ ### Local sorts, measured (2026-10-30): every one loses; the probes' order ships
263
+
264
+ After the global keys, cheaper orders were tried: sorting the rays inside a chunk of the launch, one
265
+ workgroup a chunk, and sorting the trace list instead of the rays. All were measured the same way as
266
+ above, at the 256-ray floor (131,072 rays a frame, every frame, so the arms compare like for like), 96
267
+ to 120 measured frames an arm, as means against the mean of two unsorted runs. Unless a table says
268
+ otherwise, the figures are the busy time from relocation to the light pass's end.
269
+
270
+ **The local sort.** A workgroup takes a chunk of the launch's threads, packs each ray's key above its
271
+ place in the chunk, and sorts them with the radix scatter's stable binary split, a bit a round. The
272
+ rays move only within their chunk. Keyed by the ray's direction bin, as the trace finds its texel:
273
+ 8×8 bins of the octahedral map (6 bits, the bins of UE's `SortProbeTraceTilesCS`) or 4×4 (4 bits).
274
+ "Probe order, then" runs the trace-list sort below first. iGPU, Emerald avenue / Sponza:
275
+
276
+ | Order | 2048-ray chunks | 1024 | 512 |
277
+ |---|---|---|---|
278
+ | 8×8 bins | +19.0% / +21.1% | +14.9% / +16.3% | +9.9% / +13.8% |
279
+ | 4×4 bins | +14.4% / +12.6% | +11.8% / +12.9% | +9.2% / +10.8% |
280
+ | Probe order, then 8×8 | +9.9% / +12.9% | +7.8% / +9.4% | +8.0% / +5.6% |
281
+ | Probe order, then 4×4 | +7.0% / +9.4% | +7.7% / +6.5% | +4.9% / +5.0% |
282
+
283
+ Unsorted: 13,324 / 12,095 µs, its two runs 0.3% / 1.6% apart. The probes' order alone: −1.9% / −4.0%.
284
+ - **Coarser bins and smaller chunks help, step by step, and none reaches unsorted.**
285
+ - What the order costs, before the trace sees it: on the iGPU, the key pass takes 280–330 µs (each ray's
286
+ texel found a second time; 15–34 µs as an identity), and the sort 114–123 µs at 6 bits and 86–92 at
287
+ 4, rising to 179 and 130 at 512-ray chunks. On the 4090 the sort takes 7–10 µs, less at smaller chunks.
288
+ - **The 4090 does not care.** Every arm is within ±60 µs of its 618–630 µs, both scenes.
289
+
290
+ **The control: a hash key.** The same local sort keyed by a hash of the ray (PCG), as many bits as the
291
+ bins: the same scatter of records and the same mixing of probes in a wave, and no grouping by
292
+ direction. The trace on the iGPU, Emerald / Sponza, against unsorted's 11,473 / 8,581 µs:
293
+
294
+ | Chunk and bins | Direction key | Hash key |
295
+ |---|---|---|
296
+ | 8×8, 2048 | +15% / +20% | +52% / +57% |
297
+ | 4×4, 512 | +8% / +8% | +34% / +36% |
298
+ | Probe order, then 4×4, 512 | +1% / +3% | +29% / +30% |
299
+
300
+ - **Direction coherence is worth 2.3–4.2 ms of the iGPU's trace here.** What loses is mixing several
301
+ probes' rays in one wave, which every chunk of more than one probe does.
302
+ - Under the hash, shade and light slow too (shade +0.7 to +1.2 ms, Sponza's light up to +1.9 ms): their
303
+ records and hits scatter with the rays. On the 4090 hash and direction are within ±60 µs of each
304
+ other.
305
+
306
+ **Within each probe.** Keyed by the probe's place in the list (4 bits) above the bin, in 512-ray chunks,
307
+ so that each probe's rays sort by direction and no wave mixes probes. The trace on the iGPU moved
308
+ −0.6% to +1.4% at 131k rays, and +1.0% on Sponza's own schedule (57k rays): noise. The key and sort
309
+ passes cost 470–680 µs on top. **The rays of one probe already share their waves, walking the map's
310
+ texels in rows** (a uniform update `ray % texels`, a guided one the guide's walk), so a ray sort has
311
+ nothing left to gain.
312
+
313
+ **Position bits above the bin (Alex).** Probe order first, then a local sort in 2048-ray chunks keyed by
314
+ 12 bits of the probe's Morton code past its low b bits, above the 8×8 bin: the probes of one 2^b-point
315
+ block of the lattice mix and sort by direction together, and no others. Measured on `f12f7858c`
316
+ (hits shadowed by traced rays). iGPU, Sponza / Emerald, busy (trace):
317
+
318
+ | Mixing | Busy | Trace |
319
+ |---|---|---|
320
+ | b = 0, no probes mix | +4.1% / +3.4% | −0.6% / −1.7% |
321
+ | b = 3, 2×2×2 blocks | +5.6% / +4.3% | +1.0% / −0.8% |
322
+ | b = 6, 4×4×4 blocks | +9.6% / +8.4% | +4.9% / +3.4% |
323
+ | Direction only | +13.0% / +11.2% | +10.1% / +7.9% |
324
+ | Probe order alone | −1.9% / −1.4% | −1.5% / −1.4% |
325
+
326
+ The trace follows the mixing and tops out at the probes' order's own; the key pass (about 300 µs) and the
327
+ 18-bit sort (about 325 µs) come on top. 4090: every arm −1.7% to +7.1%.
328
+
329
+ **With traced hit shadows** (`f12f7858c`: a sun ray and a local light's ray from every hit), the local
330
+ sorts were measured again: iGPU Sponza / Emerald, 8×8 in 2048s +22.1% / +18.4%, probe order then 4×4 in
331
+ 512s +5.9% / +6.3%, within each probe +5.2% / +4.1%, probe order alone −2.2% / −1.0%; 4090 +1% to +7%,
332
+ probe order −0.4% to −1.8%. Unchanged: the secondary rays gain nothing from grouping the primaries.
333
+
334
+ **The probes' order ships** (`shader_probe_clipmap_order.js`). After the due passes list the frame's
335
+ updates, a workgroup a run of 1,024 listed probes sorts its run in place by the cascade and the Morton
336
+ code of the probe's lattice point in the cascade's window (the bitonic workgroup sort,
337
+ `chunk_sort_bitonic_workgroup`), dispatched through `PROBE_DISPATCH_ORDER`, which the update's command
338
+ writes over the live count. Every pass after it reads the sorted list, the rays' layout among them, so
339
+ neighbouring probes' rays run in neighbouring waves: the same blocks of the bricks and caches, a wave
340
+ apart. Past one run the list is ordered within each run, not across them. The ray budget scales the
341
+ requests in proportion, so the order changes no probe's rays.
342
+
343
+ What it measured before shipping, iGPU at 131k rays, across five batches: Emerald −249, −510, −311,
344
+ −130, −181 µs (1.0–3.6%); Sponza −479, −340, −267, −226 µs, and one batch +475. On the schedule's own
345
+ counts, Sponza −109 and −171 µs. On the 4090, −58 to +37 µs: level. Its cost, a one-workgroup split sort
346
+ in the measurement, was 14–18 µs.
347
+
348
+ **As shipped, on the schedule's own counts** (no floor; 6 rounds, 144 frames an arm; the pass dispatched
349
+ or skipped, each twice; the busy stretch, mean of each pair):
350
+
351
+ | Scene, GPU | Rays a frame | Skipped | Ordered | Change | Pairs apart (skipped / ordered) |
352
+ |---|---|---|---|---|---|
353
+ | Sponza, iGPU | ~54k | 5,618 | 5,438 | −180 µs (−3.2%), trace −2.4% | 47 / 35 |
354
+ | Emerald avenue, iGPU | 40–59k | 5,485 | 5,510 | +25 µs, noise | 390 / 150 |
355
+ | Emerald avenue, 4090 | ~51k | 495 | 479 | −16 µs (−3.2%) | 19 / 19 |
356
+ | Sponza, 4090 | ~55k | 500 | 508 | +7 µs, noise | 4 / 46 |
357
+
358
+ - The pass takes 10.4–12.7 µs on both GPUs.
359
+ - Read back on both GPUs after a frame, every run is in its keys' order and a permutation of the list
360
+ (512 of 512 distinct).
361
+ - Emerald's rays swing with the schedule's turn (40–59k between its blocks), which is why its
362
+ floor-free pairs sit hundreds of µs apart.
363
+
364
+ The measurement wiring is kept in the session's scratchpad, not the tree: `stage3e_local_sort_control_within.patch`
365
+ (chunks, bins, the hash control, within-probe; for `c4d54e2cb`), `stage3f_sorts_on_f12f7858c.patch` and
366
+ `stage3g_morton_bits_on_f12f7858c.patch` (the same and the position bits, for `f12f7858c`); the harness is
367
+ `device/sortab.js`, and `device/orderab.js` A/Bs the shipped pass by skipping its dispatch.
368
+
369
+ ## Stages
370
+
371
+ 0. **Measure.** Scratchpad one-offs, both GPUs:
372
+ - (a) the radix sort at 131,072 keys, 24 against 32 bits;
373
+ - (b) the key pass, sort and permuted trace/light/shade, for the four keys of "Key layouts to
374
+ measure" against today's order;
375
+ - (c) the probe-level signal on the emulator: steady against +30% and ×2, one-ray and
376
+ one-in-five texels.
377
+
378
+ Decides whether sorting goes ahead, its layout, and the request's constants.
379
+ 1. **Plumbing, with no behaviour change.**
380
+ - A per-probe ray count and offset through every pass in the table above, and the ray dispatch
381
+ over the live total.
382
+ - Every request at R: bytes identical to master on the device.
383
+ - The specs move to per-probe counts.
384
+ 2. **Requests.**
385
+ - NEW, uniform, guided and DEAD counts; the probe-level signal; budget scaling; the estimator's
386
+ weighting by rays.
387
+ - On the device: the post-residency dark spell (`timeline.mjs`), steady noise, and rays and
388
+ trace time a frame.
389
+ 3. **Sorting, if stage 0 says go.**
390
+ - The radix sort's generalisation (indirect count, key width), pinned in its specs.
391
+ - The key pass, and the permuted trace, light and shade.
392
+ - A device A/B of the four keys against unsorted; the fastest key ships, and only if it beats
393
+ unsorted on both GPUs.
394
+
395
+ ## Reuse map
396
+
397
+ | Need | Reused | Change |
398
+ |---|---|---|
399
+ | ray offsets and the frame's total | `graph_prefix_scan_csdldf` (out of place, indirect) | none |
400
+ | the ray dispatch from the total | the mesh expansion's `shader_prefix_sum_to_command` pattern, `chunk_folded_dispatch` | none |
401
+ | ray → probe | `chunk_lower_bound_branchless` | none |
402
+ | the sort | `graph_radix_sort` | generalised: indirect count, key width |
403
+ | origin Morton | `chunk_v3_morton_encode` | none |
404
+ | direction bin | the probe's own octahedral texel | none |
405
+ | the per-probe signal | projection's rows pass and probe pass | one more sum |
406
+ | the request's storage | the record's `screen` word | packed |
407
+ | the guided walk at R_k | the guide's three passes | R per probe |
408
+
409
+ Duplication found along the way: the trace's `probe_trace_guided_position` is a binary search the
410
+ lower-bound chunk could serve.
@@ -8,8 +8,9 @@
8
8
  * - the row → card set table readers find a row's card set in: the pair's once it is resident,
9
9
  * `GPU_DATABASE_NULL` until then and for a row out of the SDF world.
10
10
  *
11
- * A row is in the SDF world when its `flags` carry `MESH_FLAG_SDF_WORLD`; a virtual geometry is absent,
12
- * served by its own provider. A skinned row draws a clone: the hold and the pair are its source's,
11
+ * A row is in the SDF world when its `flags` carry `MESH_FLAG_SDF_WORLD`, whatever its geometry: a
12
+ * virtual geometry's cache is held as a mesh's is, and comes from its own source (`VGeoSDFProxies`).
13
+ * A skinned row draws a clone: the hold and the pair are its source's,
13
14
  * whose unskinned field and cards the clone's header is aliased to (§6.3). A row written again moves
14
15
  * its hold and its pair, the new ones taken before the old ones go, so a cache or card set a row keeps
15
16
  * drawing is never let go in between.
@@ -1 +1 @@
1
- {"version":3,"file":"ProbeClipmapSceneHolds.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js"],"names":[],"mappings":"AAwDA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH;IAwEI;;;OAGG;IACH,mBAHW,eAAe,YACf,eAAe,EASzB;IAED;;OAEG;IACH,sEAEC;IAED;;;OAGG;IACH,yBAEC;IAED;;;OAGG;IACH,yBAEC;IAED;;;OAGG;IACH,mCAEC;IAED;;;OAGG;IACH,qCAEC;IAED,0BAEC;IAED;;;;;;OAMG;IACH,oBAJW,mBAAmB,YACnB,aAAa,GACX,MAAM,GAAC,SAAS,CAI5B;IAED;;;;OAIG;IACH,6BAIC;IAED,eAiBC;IAED,eAuCC;IAED;;OAEG;IACH,cAiBC;;CA4TJ;8BAzmBY,OAAO,gCAAgC,EAAE,eAAe;8BACxD,OAAO,mCAAmC,EAAE,eAAe;kCAC3D,OAAO,uCAAuC,EAAE,mBAAmB;4BACnE,OAAO,iCAAiC,EAAE,aAAa;yCACvD,OAAO,uDAAuD,EAAE,0BAA0B;8BAC1F,OAAO,0BAA0B,EAAE,eAAe"}
1
+ {"version":3,"file":"ProbeClipmapSceneHolds.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js"],"names":[],"mappings":"AAwDA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH;IAwEI;;;OAGG;IACH,mBAHW,eAAe,YACf,eAAe,EASzB;IAED;;OAEG;IACH,sEAEC;IAED;;;OAGG;IACH,yBAEC;IAED;;;OAGG;IACH,yBAEC;IAED;;;OAGG;IACH,mCAEC;IAED;;;OAGG;IACH,qCAEC;IAED,0BAEC;IAED;;;;;;OAMG;IACH,oBAJW,mBAAmB,YACnB,aAAa,GACX,MAAM,GAAC,SAAS,CAI5B;IAED;;;;OAIG;IACH,6BAIC;IAED,eAiBC;IAED,eAuCC;IAED;;OAEG;IACH,cAiBC;;CA4TJ;8BA1mBY,OAAO,gCAAgC,EAAE,eAAe;8BACxD,OAAO,mCAAmC,EAAE,eAAe;kCAC3D,OAAO,uCAAuC,EAAE,mBAAmB;4BACnE,OAAO,iCAAiC,EAAE,aAAa;yCACvD,OAAO,uDAAuD,EAAE,0BAA0B;8BAC1F,OAAO,0BAA0B,EAAE,eAAe"}
@@ -64,8 +64,9 @@ class Pair {
64
64
  * - the row → card set table readers find a row's card set in: the pair's once it is resident,
65
65
  * `GPU_DATABASE_NULL` until then and for a row out of the SDF world.
66
66
  *
67
- * A row is in the SDF world when its `flags` carry `MESH_FLAG_SDF_WORLD`; a virtual geometry is absent,
68
- * served by its own provider. A skinned row draws a clone: the hold and the pair are its source's,
67
+ * A row is in the SDF world when its `flags` carry `MESH_FLAG_SDF_WORLD`, whatever its geometry: a
68
+ * virtual geometry's cache is held as a mesh's is, and comes from its own source (`VGeoSDFProxies`).
69
+ * A skinned row draws a clone: the hold and the pair are its source's,
69
70
  * whose unskinned field and cards the clone's header is aliased to (§6.3). A row written again moves
70
71
  * its hold and its pair, the new ones taken before the old ones go, so a cache or card set a row keeps
71
72
  * drawing is never let go in between.
@@ -325,7 +326,7 @@ export class ProbeClipmapSceneHolds {
325
326
  let record;
326
327
  let pair;
327
328
 
328
- if ((flags & MESH_FLAG_SDF_WORLD) !== 0 && geometry.isVirtualGeometry !== true) {
329
+ if ((flags & MESH_FLAG_SDF_WORLD) !== 0) {
329
330
  record = geometries.get_metadata(geometry);
330
331
  }
331
332
 
@@ -151,11 +151,42 @@ export class ProbeClipmapSettings {
151
151
  * GPU with another load of 40–73%, which is in the medians: the least loaded frames cost 0.11 ms at
152
152
  * 16,384. At the default Sponza's cards are captured in 10 frames.
153
153
  *
154
- * On the AMD iGPU (RDNA2) a page costs 0.78 µs: 16,384 pages cost 33.5 ms at the median, and
155
- * about 1,290 fit 1 ms (1,024 cost 0.80 ms).
154
+ * Re-derived once the material reads became trilinear at a texel's footprint (2026-10-30), which
155
+ * costs 1.30× at the median, timed on the same pages in the same frame: 16,384 pages cost 0.54 and
156
+ * 0.55 ms at the median in two runs (the old capture 0.54 ms beside them), 32,768 cost 1.48 and
157
+ * 1.52 ms, and the least loaded frames 0.15 ms at 16,384.
158
+ *
159
+ * On the AMD iGPU (RDNA2), measured before that, a page costs 0.78 µs: 16,384 pages cost 33.5 ms at
160
+ * the median, and about 1,290 fit 1 ms (1,024 cost 0.80 ms).
161
+ *
162
+ * Derived for {@link MeshCardCaptureMode.Trace}. A rastered card set is taken whole, the frame's
163
+ * last past the budget, and a frame also stops at what its scratch holds: at the largest budget
164
+ * Sponza's recapture took 13 frames on the iGPU, 2.5 ms of capture a frame on average.
156
165
  * @returns {number}
157
166
  */
158
167
  get card_capture_budget(): number;
168
+ /**
169
+ * @param {MeshCardCaptureMode} v
170
+ */
171
+ set card_capture_mode(v: number);
172
+ /**
173
+ * How card pages are captured: each card drawn through its material's own template and textures,
174
+ * or a ray a texel against the geometry's BLAS with the path tracer's material sampling. A change
175
+ * captures every card set again.
176
+ *
177
+ * Raster is the default. The trace took one level-0 tap of the material's 64² resident copy a
178
+ * texel and kept it, which aliased: on Sponza's outer wall the brick texture's dark band, every
179
+ * 12.8 card texels, landed on a row of texels once and between rows at its other repeats, a seam
180
+ * across the wall. The raster samples the texture's mips at the card texel's footprint, as UE's
181
+ * card capture does, and since 2026-10-30 the trace reads the resident copy's mips there too,
182
+ * trilinearly, at 1.30× its cost (see {@link card_capture_budget}). Against the one-tap trace, the
183
+ * cards' colours agreed with the raster's to 3 codes on average over Sponza's wall, floor, ceiling
184
+ * and banners, and recapturing all of Sponza (154,138 pages) at the largest budget, the two
185
+ * interleaved in one process, cost the trace 9.1–12.7 ms and the raster 0.6 ms on the RTX 4090,
186
+ * and 335 ms against 33 ms on the AMD iGPU (RDNA2).
187
+ * @returns {MeshCardCaptureMode}
188
+ */
189
+ get card_capture_mode(): number;
159
190
  /**
160
191
  * @param {number} v integer, 1 to {@link PROBE_CLIPMAP_CASCADE_COUNT_MAX}
161
192
  */
@@ -231,25 +262,18 @@ export class ProbeClipmapSettings {
231
262
  */
232
263
  get ray_budget(): number;
233
264
  /**
234
- * @param {number} v seconds, positive and finite
235
- */
236
- set response_time(v: number);
237
- /**
238
- * Seconds of the exponential blend a probe's radiance follows a change by: an update blends by
239
- * `1 − e^(−Δt / response_time)`. DDGI's hysteresis of 0.97 a frame at 60 fps is 0.55 s.
240
- * @returns {number}
241
- */
242
- get response_time(): number;
243
- /**
244
- * @param {number} v seconds, positive and finite
265
+ * @param {number} v frames, positive and finite
245
266
  */
246
- set retention_time(v: number);
267
+ set response_frames(v: number);
247
268
  /**
248
- * Seconds a probe no pixel wants keeps its slot before it is freed, so a probe that leaves the screen
249
- * and comes back within it keeps its history.
269
+ * Frames of the short mean a probe's radiance follows a change by, in its multi-scale mean: an update
270
+ * blends the short mean by `1 − e^(−Δt / response_frames)`, Δt the frames since the probe's last update,
271
+ * and the mean catches up with it once the two disagree past the texel's noise. The depth's moments
272
+ * blend by the same. Frames, not seconds: an update happens in a frame, and the records count them.
273
+ * 30 is half a second at 60 fps; DDGI's hysteresis of 0.97 a frame is 33.
250
274
  * @returns {number}
251
275
  */
252
- get retention_time(): number;
276
+ get response_frames(): number;
253
277
  /**
254
278
  * @param {ProbeClipmapDebugView} v
255
279
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ProbeClipmapSettings.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js"],"names":[],"mappings":"AAMA;;;GAGG;AACH,8CAFU,MAAM,CAEiC;AAEjD;;;GAGG;AACH,gDAFU,cAAc,MAAM,CAAC,CAE8C;AAE7E;;;GAGG;AACH,sDAFU,MAAM,CAEyC;AAEzD;;GAEG;AACH,sDAFU,MAAM,CAE0C;AAE1D;;;GAGG;AACH,mDAFU,MAAM,CAEuC;AAEvD;;;;;GAKG;AACH,sDAFU,MAAM,CAE0C;AAE1D;;;;;;;;;;;;;;;;GAgBG;AACH;IAaI;;OAEG;IACH,mCAKC;IAjBD;;;;OAIG;IACH,kCAEC;IAsBD;;OAEG;IACH,wCAIC;IAfD;;;OAGG;IACH,uCAEC;IAuBD;;OAEG;IACH,gCAKC;IAlBD;;;;;OAKG;IACH,+BAEC;IAuBD;;OAEG;IACH,kCAKC;IAjBD;;;;OAIG;IACH,iCAEC;IAwBD;;OAEG;IACH,mCAKC;IAlBD;;;;;OAKG;IACH,kCAEC;IAyBD;;;OAGG;IACH,mCAOC;IAtBD;;;;;;OAMG;IACH,kCAEC;IAqCD;;;OAGG;IACH,oCAKC;IA7BD;;;;;;;;;;;;;;;OAeG;IACH,mCAEC;IAoCD;;;OAGG;IACH,mCAKC;IA9BD;;;;;;;;;;;;;;;;OAgBG;IACH,kCAEC;IAwBD;;OAEG;IACH,mCAKC;IAjBD;;;;OAIG;IACH,kCAEC;IAsBD;;OAEG;IACH,wCAIC;IAfD;;;OAGG;IACH,uCAEC;IAuBD;;OAEG;IACH,6BAKC;IAlBD;;;;;OAKG;IACH,4BAEC;IAuBD;;;OAGG;IACH,mCAOC;IApBD;;;;OAIG;IACH,kCAEC;IA0BD;;;OAGG;IACH,gCAOC;IApBD;;;;OAIG;IACH,+BAEC;IA0BD;;;OAGG;IACH,8BAKC;IAlBD;;;;OAIG;IACH,6BAEC;IAyBD;;OAEG;IACH,0BAIC;IAjBD;;;;;OAKG;IACH,yBAEC;IAsBD;;OAEG;IACH,6BAKC;IAjBD;;;;OAIG;IACH,4BAEC;IAuBD;;OAEG;IACH,8BAKC;IAjBD;;;;OAIG;IACH,6BAEC;IAuBD;;OAEG;IACH,0BAIC;IAhBD;;;;OAIG;IACH,yBAEC;;CAUJ"}
1
+ {"version":3,"file":"ProbeClipmapSettings.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js"],"names":[],"mappings":"AAOA;;;GAGG;AACH,8CAFU,MAAM,CAEiC;AAEjD;;;GAGG;AACH,gDAFU,cAAc,MAAM,CAAC,CAE8C;AAE7E;;;GAGG;AACH,sDAFU,MAAM,CAEyC;AAEzD;;GAEG;AACH,sDAFU,MAAM,CAE0C;AAE1D;;;GAGG;AACH,mDAFU,MAAM,CAEuC;AAEvD;;;;;GAKG;AACH,sDAFU,MAAM,CAE0C;AAE1D;;;;;;;;;;;;;;;;GAgBG;AACH;IAaI;;OAEG;IACH,mCAKC;IAjBD;;;;OAIG;IACH,kCAEC;IAsBD;;OAEG;IACH,wCAIC;IAfD;;;OAGG;IACH,uCAEC;IAuBD;;OAEG;IACH,gCAKC;IAlBD;;;;;OAKG;IACH,+BAEC;IAuBD;;OAEG;IACH,kCAKC;IAjBD;;;;OAIG;IACH,iCAEC;IAwBD;;OAEG;IACH,mCAKC;IAlBD;;;;;OAKG;IACH,kCAEC;IAyBD;;;OAGG;IACH,mCAOC;IAtBD;;;;;;OAMG;IACH,kCAEC;IAqCD;;;OAGG;IACH,oCAKC;IA7BD;;;;;;;;;;;;;;;OAeG;IACH,mCAEC;IA6CD;;;OAGG;IACH,mCAKC;IAvCD;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,kCAEC;IAoCD;;OAEG;IACH,iCAIC;IA5BD;;;;;;;;;;;;;;;;OAgBG;IACH,gCAEC;IAsBD;;OAEG;IACH,mCAKC;IAjBD;;;;OAIG;IACH,kCAEC;IAsBD;;OAEG;IACH,wCAIC;IAfD;;;OAGG;IACH,uCAEC;IAuBD;;OAEG;IACH,6BAKC;IAlBD;;;;;OAKG;IACH,4BAEC;IAuBD;;;OAGG;IACH,mCAOC;IApBD;;;;OAIG;IACH,kCAEC;IA0BD;;;OAGG;IACH,gCAOC;IApBD;;;;OAIG;IACH,+BAEC;IA0BD;;;OAGG;IACH,8BAKC;IAlBD;;;;OAIG;IACH,6BAEC;IAyBD;;OAEG;IACH,0BAIC;IAjBD;;;;;OAKG;IACH,yBAEC;IAyBD;;OAEG;IACH,+BAKC;IApBD;;;;;;;OAOG;IACH,8BAEC;IAuBD;;OAEG;IACH,0BAIC;IAhBD;;;;OAIG;IACH,yBAEC;;CAUJ"}