@woosh/meep-engine 3.60.4 → 3.60.6

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 (419) hide show
  1. package/CHANGELOG.md +2621 -0
  2. package/CONTRIBUTING.md +7 -0
  3. package/MIGRATION_2_TO_3.md +136 -0
  4. package/SECURITY.md +4 -0
  5. package/editor/EditorCameraNavigation.d.ts +2 -1
  6. package/editor/EditorCameraNavigation.d.ts.map +1 -1
  7. package/editor/EditorCameraNavigation.js +51 -57
  8. package/package.json +6 -2
  9. package/src/engine/EngineHarness.d.ts +3 -9
  10. package/src/engine/EngineHarness.d.ts.map +1 -1
  11. package/src/engine/EngineHarness.js +6 -8
  12. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts +9 -6
  13. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts.map +1 -1
  14. package/src/engine/graphics/camera/makeOrbitalCameraController.js +44 -71
  15. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts +64 -0
  16. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts.map +1 -0
  17. package/src/engine/graphics/camera/orbital/MomentumAxis.js +187 -0
  18. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts +86 -0
  19. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts.map +1 -0
  20. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.js +319 -0
  21. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts +34 -10
  22. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
  23. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +116 -30
  24. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts +1 -7
  25. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
  26. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +1 -37
  27. package/src/engine/graphics/ecs/water/Water.d.ts +8 -0
  28. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  29. package/src/engine/graphics/ecs/water/Water.js +8 -0
  30. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  31. package/src/engine/graphics3/WaterSystem.js +731 -734
  32. package/src/engine/graphics3/decal/DecalTileShader.d.ts +61 -0
  33. package/src/engine/graphics3/decal/DecalTileShader.d.ts.map +1 -0
  34. package/src/engine/graphics3/decal/DecalTileShader.js +138 -0
  35. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts +10 -4
  36. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
  37. package/src/engine/graphics3/decal/GPUDecalRenderer.js +149 -44
  38. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts +25 -0
  39. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts.map +1 -0
  40. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.js +55 -0
  41. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts +22 -0
  42. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts.map +1 -0
  43. package/src/engine/graphics3/decal/graph_gather_decal_tiles.js +70 -0
  44. package/src/engine/graphics3/decal/shader_decal_composite.d.ts +7 -5
  45. package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
  46. package/src/engine/graphics3/decal/shader_decal_composite.js +48 -44
  47. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts +12 -0
  48. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts.map +1 -0
  49. package/src/engine/graphics3/decal/shader_decal_tile_copy.js +78 -0
  50. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts +11 -0
  51. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts.map +1 -0
  52. package/src/engine/graphics3/decal/shader_gather_decal_tiles.js +80 -0
  53. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts +13 -0
  54. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts.map +1 -0
  55. package/src/engine/input/devices/mouse/MouseEventButtons.js +23 -0
  56. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts +4 -0
  57. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts.map +1 -1
  58. package/src/engine/input/ecs/controllers/KeyboardCameraController.js +9 -45
  59. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  60. package/src/shade/playground/water_refraction/README.md +5 -6
  61. package/src/shade/playground/water_refraction/index.html +1 -1
  62. package/src/shade/renderer/Renderer.d.ts +11 -0
  63. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  64. package/src/shade/renderer/Renderer.js +50 -6
  65. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +40 -80
  66. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
  67. package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +197 -147
  68. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  69. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  70. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  71. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  72. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  73. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +28 -45
  74. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  75. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +111 -119
  76. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +22 -3
  77. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
  78. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +84 -3
  79. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts +19 -0
  80. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts.map +1 -0
  81. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.js +25 -0
  82. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts +31 -0
  83. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts.map +1 -0
  84. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js +343 -0
  85. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +15 -0
  86. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -1
  87. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +38 -0
  88. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts +17 -0
  89. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts.map +1 -0
  90. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.js +29 -0
  91. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -1
  92. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +7 -13
  93. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts +28 -59
  94. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts.map +1 -1
  95. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.js +84 -789
  96. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  97. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -8
  98. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +7 -6
  99. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  100. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +12 -11
  101. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +2 -2
  102. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +2 -2
  103. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +1 -4
  104. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  105. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +1 -10
  106. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +5 -15
  107. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -1
  108. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +6 -34
  109. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  110. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -7
  111. package/src/shade/renderer/hiz/HZBFootprint.d.ts +14 -0
  112. package/src/shade/renderer/hiz/HZBFootprint.d.ts.map +1 -0
  113. package/src/shade/renderer/hiz/HZBFootprint.js +16 -0
  114. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts +10 -0
  115. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts.map +1 -0
  116. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.js +11 -0
  117. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts +10 -0
  118. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts.map +1 -0
  119. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.js +11 -0
  120. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +0 -7
  121. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  122. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +405 -350
  123. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts +12 -0
  124. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts.map +1 -0
  125. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.js +27 -0
  126. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts +12 -0
  127. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts.map +1 -0
  128. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.js +27 -0
  129. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts +14 -0
  130. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts.map +1 -0
  131. package/src/shade/renderer/hiz/hzb_footprint_texels.js +34 -0
  132. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +0 -5
  133. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
  134. package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +37 -57
  135. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts +11 -0
  136. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts.map +1 -0
  137. package/src/shade/renderer/hiz/{shader_hzb_reduce_mip0_clip.js → shader_hzb_reduce_mip0.js} +120 -111
  138. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  139. package/src/shade/renderer/material/GPUMaterialManager.d.ts +11 -1
  140. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  141. package/src/shade/renderer/material/GPUMaterialManager.js +16 -8
  142. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +12 -12
  143. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  144. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +17 -118
  145. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +7 -3
  146. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
  147. package/src/shade/renderer/postprocess/gtao/GTAO.js +26 -13
  148. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts +14 -0
  149. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  150. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +196 -68
  151. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
  152. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +42 -28
  153. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
  154. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +429 -414
  155. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts +16 -0
  156. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts.map +1 -0
  157. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.js +156 -0
  158. package/src/shade/renderer/scene/GPUSceneContext.d.ts +2 -2
  159. package/src/shade/renderer/scene/GPUSceneContext.js +5 -5
  160. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  161. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +7 -2
  162. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +0 -6
  163. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  164. package/src/shade/renderer/water/GPUWaterRenderer.js +12 -17
  165. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts +35 -0
  166. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts.map +1 -0
  167. package/src/shade/renderer/water/medium/graph_water_meshlets.js +89 -0
  168. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  169. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  170. package/src/shade/renderer/water/shader_water.js +22 -13
  171. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
  172. package/src/shade/renderer/water/shader_water_avboit.js +7 -7
  173. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +1 -1
  174. package/src/shade/renderer/water/surface/graph_water_tessellation.js +1 -1
  175. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +9 -1
  176. package/editor/REWORK_PLAN_2026_08.md +0 -692
  177. package/src/CODEC_LAYOUT_VERIFICATION.md +0 -419
  178. package/src/CORRECTNESS_HUNT_2026_07_24.md +0 -142
  179. package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +0 -738
  180. package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +0 -79
  181. package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +0 -93
  182. package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +0 -80
  183. package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +0 -164
  184. package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +0 -69
  185. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +0 -110
  186. package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +0 -129
  187. package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +0 -72
  188. package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +0 -74
  189. package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +0 -169
  190. package/src/DUPLICATION_AUDIT_2026_08_07.md +0 -254
  191. package/src/DUPLICATION_AUDIT_REMEDIATION.md +0 -250
  192. package/src/DUPLICATION_REVIEW_2026_10_24.md +0 -1072
  193. package/src/REVIEW_2026_08_06/adv-core.md +0 -511
  194. package/src/REVIEW_2026_08_06/adv-gfx.md +0 -480
  195. package/src/REVIEW_2026_08_06/adv-view.md +0 -446
  196. package/src/REVIEW_2026_08_06/api-core.md +0 -296
  197. package/src/REVIEW_2026_08_06/api-engine.md +0 -195
  198. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +0 -507
  199. package/src/REVIEW_2026_08_06/core-binary.md +0 -348
  200. package/src/REVIEW_2026_08_06/core-collection.md +0 -376
  201. package/src/REVIEW_2026_08_06/core-math.md +0 -221
  202. package/src/REVIEW_2026_08_06/core-process.md +0 -266
  203. package/src/REVIEW_2026_08_06/core-science.md +0 -223
  204. package/src/REVIEW_2026_08_06/engine-ai-nav.md +0 -279
  205. package/src/REVIEW_2026_08_06/engine-animation.md +0 -167
  206. package/src/REVIEW_2026_08_06/engine-asset.md +0 -166
  207. package/src/REVIEW_2026_08_06/engine-ecs.md +0 -920
  208. package/src/REVIEW_2026_08_06/engine-input.md +0 -197
  209. package/src/REVIEW_2026_08_06/engine-misc.md +0 -248
  210. package/src/REVIEW_2026_08_06/engine-terrain.md +0 -52
  211. package/src/REVIEW_2026_08_06/generation.md +0 -176
  212. package/src/REVIEW_2026_08_06/geom-2d.md +0 -434
  213. package/src/REVIEW_2026_08_06/geom-3d.md +0 -117
  214. package/src/REVIEW_2026_08_06/gfx-gi.md +0 -143
  215. package/src/REVIEW_2026_08_06/gfx-render.md +0 -740
  216. package/src/REVIEW_2026_08_06/gfx-texture.md +0 -690
  217. package/src/REVIEW_2026_08_06/prior-criticals.md +0 -49
  218. package/src/REVIEW_2026_08_06/prior-highs.md +0 -138
  219. package/src/REVIEW_2026_08_06/test-gaps.md +0 -364
  220. package/src/REVIEW_2026_08_06/view.md +0 -667
  221. package/src/REVIEW_2026_08_06.md +0 -610
  222. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +0 -542
  223. package/src/core/bvh2/bvh3/NOTES.md +0 -2
  224. package/src/core/bvh8/NOTES.md +0 -63
  225. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +0 -243
  226. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +0 -417
  227. package/src/core/color/COLOR_REVIEW_2026_08_28.md +0 -779
  228. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +0 -433
  229. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +0 -486
  230. package/src/core/geom/3d/atlas/BFF_PLAN.md +0 -174
  231. package/src/core/geom/3d/atlas/REVIEW_02.md +0 -392
  232. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +0 -146
  233. package/src/core/geom/3d/gjk/NOTES.md +0 -8
  234. package/src/core/geom/3d/topology/TOPO_MESH_RETIREMENT_PLAN.md +0 -135
  235. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +0 -381
  236. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +0 -684
  237. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +0 -554
  238. package/src/core/model/reactive/evaluation/PREDICATE_APPLICABILITY_PROPOSAL.md +0 -446
  239. package/src/engine/REVIEW_2026_07_03.md +0 -211
  240. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +0 -815
  241. package/src/engine/control/first-person/DESIGN.md +0 -658
  242. package/src/engine/control/first-person/DESIGN_COLLISION.md +0 -382
  243. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +0 -563
  244. package/src/engine/control/first-person/TODO.md +0 -160
  245. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +0 -531
  246. package/src/engine/ecs/HIERARCHY_REVIEW.md +0 -717
  247. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +0 -262
  248. package/src/engine/ecs/ik/PLAN.md +0 -179
  249. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +0 -272
  250. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +0 -199
  251. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +0 -521
  252. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +0 -463
  253. package/src/engine/graphics/ecs/camera/pp/NOTES.md +0 -48
  254. package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +0 -659
  255. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +0 -235
  256. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +0 -490
  257. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +0 -466
  258. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +0 -717
  259. package/src/engine/input/ecs/ism/ISM_DESIGN.md +0 -1523
  260. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +0 -627
  261. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +0 -661
  262. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +0 -229
  263. package/src/engine/network/CONGESTION_CONTROL.md +0 -87
  264. package/src/engine/network/MESSAGE_TRANSPORT.md +0 -364
  265. package/src/engine/network/SMOOTHNESS_DESIGN.md +0 -400
  266. package/src/engine/physics/cloth/MEASUREMENTS.md +0 -5304
  267. package/src/engine/physics/cloth/PLAN.md +0 -3056
  268. package/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md +0 -1382
  269. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +0 -243
  270. package/src/engine/physics/fluid/solver/NOTES.md +0 -46
  271. package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +0 -536
  272. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +0 -432
  273. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +0 -250
  274. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +0 -322
  275. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +0 -261
  276. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +0 -121
  277. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +0 -999
  278. package/src/format/image/avif/DECISIONS.md +0 -545
  279. package/src/format/image/jpeg/NOTES.md +0 -3
  280. package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +0 -814
  281. package/src/generation/COORDINATES.md +0 -54
  282. package/src/generation/REVIEW_01_ACTION_PLAN.md +0 -628
  283. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +0 -220
  284. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +0 -172
  285. package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +0 -86
  286. package/src/generation/foliage/FOLIAGE_DESIGN.md +0 -547
  287. package/src/generation/foliage/FOLIAGE_PLAN.md +0 -198
  288. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +0 -158
  289. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +0 -521
  290. package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +0 -86
  291. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +0 -347
  292. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +0 -248
  293. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +0 -694
  294. package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +0 -552
  295. package/src/shade/RENDERER_CONTRACT.md +0 -697
  296. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +0 -263
  297. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +0 -569
  298. package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +0 -755
  299. package/src/shade/device/mock/EXTENSION_PROPOSAL_2026_08_22.md +0 -458
  300. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +0 -255
  301. package/src/shade/device/mock/REVIEW_2026_08_22.md +0 -527
  302. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +0 -894
  303. package/src/shade/device/timing/profile/SGPT_FORMAT.md +0 -345
  304. package/src/shade/renderer/NOTES.md +0 -78
  305. package/src/shade/renderer/PLAN.md +0 -8
  306. package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +0 -145
  307. package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +0 -357
  308. package/src/shade/renderer/atmosphere/NOTES.md +0 -6
  309. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts +0 -76
  310. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts.map +0 -1
  311. package/src/shade/renderer/camera/orbital/MomentumAxis.js +0 -164
  312. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts +0 -45
  313. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts.map +0 -1
  314. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.js +0 -66
  315. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +0 -98
  316. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +0 -1
  317. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +0 -184
  318. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +0 -175
  319. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +0 -1
  320. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +0 -411
  321. package/src/shade/renderer/camera/orbital/README.md +0 -81
  322. package/src/shade/renderer/camera/orbital/index.d.ts +0 -6
  323. package/src/shade/renderer/camera/orbital/index.d.ts.map +0 -1
  324. package/src/shade/renderer/camera/orbital/index.js +0 -9
  325. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +0 -964
  326. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +0 -361
  327. package/src/shade/renderer/geometry/bvh/BLAS_REFIT_BATCH_PLAN.md +0 -619
  328. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +0 -674
  329. package/src/shade/renderer/geometry/sdf/NOTES.md +0 -6
  330. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +0 -540
  331. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +0 -305
  332. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +0 -913
  333. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +0 -787
  334. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +0 -481
  335. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +0 -301
  336. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +0 -448
  337. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +0 -385
  338. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +0 -656
  339. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +0 -308
  340. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +0 -657
  341. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +0 -551
  342. package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +0 -529
  343. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts +0 -47
  344. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts.map +0 -1
  345. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.js +0 -80
  346. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts +0 -16
  347. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts.map +0 -1
  348. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.js +0 -67
  349. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts +0 -17
  350. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts.map +0 -1
  351. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.js +0 -145
  352. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts +0 -12
  353. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts.map +0 -1
  354. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.js +0 -105
  355. package/src/shade/renderer/global_illumination/lpv/NOTES.md +0 -3
  356. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +0 -4306
  357. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +0 -410
  358. package/src/shade/renderer/global_illumination/sharc/NOTES.md +0 -8
  359. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +0 -1369
  360. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +0 -202
  361. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +0 -94
  362. package/src/shade/renderer/hiz/NOTES.md +0 -3
  363. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +0 -8
  364. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +0 -1
  365. package/src/shade/renderer/light/cluster/NOTES.md +0 -11
  366. package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +0 -524
  367. package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +0 -1101
  368. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +0 -24
  369. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +0 -1
  370. package/src/shade/renderer/material/resident/shader_resident_texture_means.js +0 -120
  371. package/src/shade/renderer/particles/DESIGN.md +0 -1011
  372. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +0 -280
  373. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +0 -453
  374. package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +0 -520
  375. package/src/shade/renderer/postprocess/bloom/NOTES.md +0 -6
  376. package/src/shade/renderer/postprocess/fsr/NOTES.md +0 -4
  377. package/src/shade/renderer/postprocess/gtao/NOTES.md +0 -6
  378. package/src/shade/renderer/postprocess/nss/NOTES.md +0 -332
  379. package/src/shade/renderer/postprocess/perspective/NOTES.md +0 -3
  380. package/src/shade/renderer/postprocess/sscs/NOTES.md +0 -5
  381. package/src/shade/renderer/postprocess/ssr/NOTES.md +0 -14
  382. package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +0 -286
  383. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -39
  384. package/src/shade/renderer/postprocess/taa/NOTES.md +0 -11
  385. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +0 -78
  386. package/src/shade/renderer/postprocess/vrs/NOTES.md +0 -4
  387. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +0 -1218
  388. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +0 -600
  389. package/src/shade/renderer/restir/reservoir/NOTES.md +0 -6
  390. package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +0 -6
  391. package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +0 -391
  392. package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +0 -153
  393. package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +0 -322
  394. package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +0 -247
  395. package/src/shade/renderer/shader/chunk/fsr/NOTES.md +0 -3
  396. package/src/shade/renderer/shader/chunk/fsr/spd/NOTES.md +0 -4
  397. package/src/shade/renderer/shader/chunk/geometry/ray/NOTES.md +0 -4
  398. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +0 -159
  399. package/src/shade/renderer/shader/chunk/mboit/NOTES.md +0 -38
  400. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/NOTES.md +0 -3
  401. package/src/shade/renderer/shader/chunk/spherical_harmonics/sampling/NOTES.md +0 -8
  402. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +0 -927
  403. package/src/shade/renderer/shadow/contact/FINDINGS.md +0 -413
  404. package/src/shade/renderer/shadow/map/csm/NOTES.md +0 -5
  405. package/src/shade/renderer/shadow/ray/NOTES.md +0 -31
  406. package/src/shade/renderer/shadow/sdf/NOTES.md +0 -9
  407. package/src/shade/renderer/shadow/sdf/brixelizer/NOTES.md +0 -5
  408. package/src/shade/renderer/shadow/sdf/cascade/NOTES.md +0 -9
  409. package/src/shade/renderer/shadow/vsm/NOTES.md +0 -12
  410. package/src/shade/renderer/shadow/vsm/PLAN.md +0 -442
  411. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +0 -43
  412. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +0 -2444
  413. package/src/shade/renderer/texture/mipmaps/NOTES.md +0 -3
  414. package/src/shade/renderer/volumetrics/NOTES.md +0 -1329
  415. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +0 -336
  416. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +0 -23
  417. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +0 -1
  418. package/src/shade/renderer/water/medium/GPUWaterBodies.js +0 -75
  419. package/src/shade/wgsl/NOTES.md +0 -4
@@ -1,600 +0,0 @@
1
- # Adaptive voxel-based order-independent transparency (AVBOIT) — implementation plan
2
-
3
- **Status:** implemented, default mode, device tier in progress — revision 8
4
- **Date:** 2026-09-03
5
- **Author:** Alex Goldring / Company Named Limited, with Claude
6
- **Scope:** `src/shade/renderer/rasterize/native/avboit/` (new), `src/shade/renderer/ShadeTransparencyMode.js`
7
- (new), `src/shade/renderer/Renderer.js` (one field, one call site),
8
- `src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js` (two extra return values)
9
- **Source:** Drobot, M. — *Adaptive Voxel-Based Order Independent Transparency*, Advances in Real-Time Rendering in
10
- Games, SIGGRAPH 2025 (talk deck, 60 pages, `AVBOIT_SIG2025_MDROBOT-final.pdf`)
11
- **Ledger:** [`AVBOIT_LEDGER.md`](./AVBOIT_LEDGER.md) — what actually landed, step by step, and what each step found
12
-
13
- > **Revision 2** (ledger entries 12 and 14) amends §3.5, §4 and §7 on the transmission tint. Revision 1
14
- > derived a per-channel transmittance from the base colour unconditionally, and called that the OpenPBR
15
- > default; it is glTF's reading, OpenPBR's transmission colour defaults to white, and the engine's other
16
- > paths transmit untinted. The first real renders showed a red pane under AVBOIT and clear glass under
17
- > MBOIT and the path tracer, which a mode switch the contract calls safe to flip must not do. The tint is
18
- > kept and off by default, switched at runtime through `Renderer.avboit`.
19
- >
20
- > **Revision 3** (ledger entry 15): AVBOIT is the default (§0, §3.10); the slice floor is set by
21
- > `AVBOIT_VIRTUAL_SLICES_MAX = 4096` (§3.2, §9); the draw discards fragments the volume calls extinct before
22
- > shading them (§3.8); §6's software-device tier is a recorder, not an end-to-end runner, and the plan no
23
- > longer expects a full-orchestrator spec from it; §7's phase-2 list is decided item by item.
24
- >
25
- > **Revision 4** (ledger entry 18) is the review against the engine. The depth curve is the engine's own log
26
- > slicing (§3.2) rather than a second one; the bit fold reuses the Morton decode; the integral samples through
27
- > the sampler the draw already binds; the per-material draw loop is one shared module for both pipelines; and
28
- > the chunks follow the one-function-per-file convention (§5).
29
- >
30
- > **Revision 5** (ledger entry 19) widens the pipeline past meshlets. `AVBOITSideChannel` is a contract for a
31
- > transparent source that is not a meshlet bucket — the GPU particles are the first — asked for its occupancy,
32
- > its splat and its draw at the three points where the meshlet buckets contribute theirs (§3.1). The draw grew
33
- > a fourth accumulator, `emission`, for additive fragments: they cover nothing, so the resolve's
34
- > renormalization must not scale them (§3.8, §3.9). Integrate and resolve are otherwise untouched, and MBOIT,
35
- > now the legacy path, gets no channel of its own.
36
- >
37
- > **Revision 6** (ledger entry 22) adds the second side channel and the door to it. `DynamicMeshAVBOITChannel`
38
- > draws a `DynamicMeshBatch` — trails, first and only — through the three contracts, and a channel can now come
39
- > from outside the renderer: `Renderer.add_transparency_channel`, held across restarts by
40
- > `GraphicsEngine.add_transparency_channel` the way extensions are. A channel may say it is empty
41
- > (`avboit_is_empty`) and is then left out of the frame, so one that is always registered does not make the
42
- > orchestrator run on frames with nothing transparent. What the particle channel did privately and a second
43
- > channel needs — the coverage clamp, the covering/emitting routing, a world box's depth interval and the slice
44
- > marking — are shared chunks now. The meshlet passes are untouched.
45
- >
46
- > **Revision 7** (ledger entry 24): the dynamic meshes' splat is rasterized with four samples and weights each
47
- > fragment's extinction by the share of the voxel its triangle covers, so a trail thinner than a voxel
48
- > occludes steadily instead of in the columns whose centres it happens to cross (§9). The meshlet and particle
49
- > splats are unchanged.
50
- >
51
- > **Revision 8** (ledger entry 26) is the review against the deck. The lookup bias grows by the fragment's
52
- > own footprint (§3.8), which closes §9's sloped-surface risk. The particle splat's soft fade is averaged over
53
- > the voxel rather than read at its corner. A water plane in view takes the warp's whole budget (§9); taking
54
- > the water out of the volume was tried and withdrawn as anti-OIT.
55
- >
56
- > **Revision 9** (ledger entry 27): the warp build can try virtual resolutions between octaves
57
- > (`AVBOITSettings.warp_steps_per_octave`) and hold the previous frame's against refining
58
- > (`warp_hysteresis`), both off by default (§3.4). The deck's curve re-adjustment was measured and gives
59
- > nothing from a pure-log curve.
60
- >
61
- > **Revision 10** (ledger entry 28): the warp build is one workgroup, an invocation per occupancy word, with
62
- > subgroup reductions and a subgroup scan for the LUT (§3.4); it was one invocation.
63
- >
64
- > **Revision 11** (ledger entry 29): four steps per octave is the default, and revision 9's hysteresis is
65
- > removed.
66
-
67
- ---
68
-
69
- ## 0. The one thing this document is about
70
-
71
- A second transparency pipeline, selected by `Renderer.transparency_mode`, that sits next to the existing
72
- moment-based one and shares everything up to the draw commands. It replaces the *transmittance function*
73
- (four power moments per pixel) with a *voxelized extinction volume* at reduced resolution, integrated along
74
- view rays into a 3D transmittance lookup, with the depth axis adaptively packed so that the 128 physical slices
75
- land where transparent geometry actually is.
76
-
77
- Everything else — material filtering, meshlet expansion, HZB culling, indirect draw commands, forward shading,
78
- volumetric compositing, the final composite onto the scene colour — is the same as MBOIT, and is reused rather
79
- than copied where the existing code allows it.
80
-
81
- What this document is **not**: a survey of OIT techniques (the deck has one, slides 10–20). *Revision 3:*
82
- AVBOIT is the default, on the strength of the first real renders (ledger entries 12 and 15): it held the
83
- stacked-card case the way the reference did and MBOIT did not. MBOIT stays selectable.
84
-
85
- ---
86
-
87
- ## 1. What is there now
88
-
89
- `src/shade/renderer/rasterize/native/oit/` is MBOIT, wired at a single call site
90
- ([`Renderer.js:2222-2249`](../../../Renderer.js)), guarded by the private `#feature_enabled_transparencies`.
91
- Its orchestrator [`graph_rasterize_meshes_transparent_oit.js`](../oit/graph_rasterize_meshes_transparent_oit.js)
92
- records, per frame:
93
-
94
- 1. `filter_materials_by_bucket` twice — `(Transparent, Triangles, Front)` and `(…, Double)`.
95
- *2026-09-16: `ShadeDrawSide.Back` transparent materials used to be dropped here. They are not any
96
- more — `Back` and `Front` are one bucket now, so asking for either returns both.*
97
- 2. `graph_prepare_meshlet_draw_commands_by_material` twice — copy bucket, HZB mesh filter, expand to meshlets,
98
- HZB meshlet filter, count/scan/sort by material, build one indirect draw command per material.
99
- 3. `MBOIT/generate moments` twice (front clears, double loads) — additive MRT into `r32float` + `rgba32float`,
100
- which is what puts `float32-blendable` on the device floor
101
- ([`Renderer.js:1160`](../../../Renderer.js), [`RENDERER_CONTRACT.md` §2](../../../../RENDERER_CONTRACT.md)).
102
- 4. `MBOIT/resolve moments` twice — full forward shading, moments reconstruct transmittance, premultiplied
103
- colour × transmittance added into an `rgba16float` accumulator.
104
- 5. `shader_oit_blend` — one image pass onto the scene colour with `one / src-alpha` blending.
105
-
106
- Per-fragment inputs, depth conventions and the material coupling for transmission are described in the two
107
- shaders this plan mirrors: [`shader_oit_generate_moments.js`](../oit/shader_oit_generate_moments.js) (coverage,
108
- Fresnel for `transmission_factor > 0`, `OIT_COVERAGE_MAX`) and
109
- [`shader_oit_resolve_moments_ibl.js`](../oit/shader_oit_resolve_moments_ibl.js) (shading, volumetrics with
110
- `get_view_space_depth`, the additive output).
111
-
112
- Mode switches in `Renderer` follow one shape — an enum file next to `ShadeIndirectLightingMode.js`, a public
113
- field, a ternary at the call site — and the cleanest instance is `dof_algorithm`
114
- ([`Renderer.js:2321-2336`](../../../Renderer.js)).
115
-
116
- ---
117
-
118
- ## 2. The algorithm, as the deck presents it
119
-
120
- The talk's own summary of VBOIT (slide 48) and what the adaptive extension adds (slides 93–97):
121
-
122
- **VBOIT.**
123
- 1. Fit a log depth curve over the slices.
124
- 2. Clear a volumetric extinction buffer at reduced resolution (1/8 of the frame in XY).
125
- 3. Splat every transparent fragment into it — extinction `-log(1 - α)` in a normalized 8-bit fixed point, added
126
- with atomics, packed several fields per `u32`. *Linear* splatting (split by slice fraction between two
127
- adjacent slices) removes the aliasing that point splatting shows.
128
- 4. Integrate extinction along each view ray into a 3D transmittance-integral texture. Stop a ray when it
129
- saturates, or when the splat detected an overflow (the first overflowing slice is kept with an atomic min).
130
- 5. Draw transparencies in any order at full resolution: look the integral up at the fragment's depth, with a
131
- two-slice bias toward the camera so a surface does not occlude itself; weight the fragment by that
132
- transmittance; accumulate weighted colour, weighted α (the normalization denominator) and total extinction.
133
- 6. Resolve: `background × exp(-Σ extinction) + Σ(colour × w) / Σ(α × w) × (1 - exp(-Σ extinction))`.
134
-
135
- **Adaptive.** Before splatting, voxelize the *bounds* of transparent geometry into a 1-bit-per-slice
136
- occupancy at a high *virtual* slice resolution. If more slices are occupied than there are physical slices,
137
- halve the virtual resolution and repeat. A prefix sum over the occupied slices gives a 1D depth-warp LUT that
138
- maps virtual depth to a physical slice, skipping empty depth ranges; the LUT is sampled at splat and at draw.
139
- The result is a depth axis whose precision goes where the geometry is, at no per-sample cost.
140
-
141
- **Colour.** RGB extinction is kept in a second buffer (10|10|10 packed), and the talk's measured cost of RGB
142
- over monochrome is ~1.1× — practical, where MBOIT/WBOIT have no clean split.
143
-
144
- Known limits (slides 86–92): two events in the same slice degenerate to weighted blending, and the two-slice
145
- sample bias means events closer than that do not occlude each other. Slice separation is the whole game, which
146
- is what the adaptive packing buys.
147
-
148
- ---
149
-
150
- ## 3. Design for meep
151
-
152
- ### 3.1 Frame-graph passes
153
-
154
- All recorded under `graph.push_scope("transparencies")` by the new orchestrator
155
- `graph_rasterize_meshes_transparent_avboit(...)`, taking the same argument object as the MBOIT one and
156
- returning the resource ID of the composited colour.
157
-
158
- | # | Pass | Kind | Reads | Writes |
159
- |---|------|------|-------|--------|
160
- | 1 | draw-command prep × 2 (shared) | compute | buckets, HZB, camera | meshlets, draw commands, *meshlet collection*, *iterator command* |
161
- | 2 | `AVBOIT/occupancy` × 2 | compute, indirect | meshlet collection, meshlet metadata, scene database, camera | `occupancy` bits |
162
- | 3 | `AVBOIT/build warp` | compute, 1 workgroup | occupancy, camera | `warp` LUT + header |
163
- | 4 | `AVBOIT/splat` × 2 | render, 1/8 res | draw commands, meshlets, warp | `extinction` (atomics), `overflow` (atomics) |
164
- | 5 | `AVBOIT/integrate` | compute, per voxel column | extinction, overflow, warp | `integral` 3D texture |
165
- | 6 | `AVBOIT/draw` × 2 | render, internal res | draw commands, meshlets, depth, warp, integral, lights, volumetrics | `accum_color`, `accum_norm`, `accum_ext` |
166
- | 7 | `AVBOIT/resolve` | image | scene colour, the three accumulators | composited colour (new transient) |
167
-
168
- Step 1 is `graph_prepare_meshlet_draw_commands_by_material`, extended to also return the HZB-filtered meshlet
169
- collection (the one with a `count` header) and the indirect dispatch command it already builds over it. The
170
- sorted meshlet buffer the draw uses is a bare `array<MeshletDefinition>` with no count
171
- ([`shader_sort_meshlets_by_material.js:20`](../../bucket/shader_sort_meshlets_by_material.js)), so the
172
- occupancy pass cannot iterate it on its own; the collection before sorting can. The two extra return values are
173
- additive and MBOIT ignores them.
174
-
175
- The front and double-sided variants of steps 4 and 6 exist for the same reason as in MBOIT: different
176
- `cullMode`, so a different pipeline, threaded through `rp_rewrite_for_primitive_state`.
177
-
178
- *Revision 5:* steps 2, 4 and 6 also take contributions from **side channels** — transparent sources that are
179
- not meshlet buckets, the GPU particles being the first (*revision 6:* and the dynamic meshes, for trails, the
180
- second). `graph_rasterize_meshes_transparent_avboit` takes
181
- `side_channels`, an array of `AVBOITSideChannel`, and asks each for its occupancy after the meshlet buckets'
182
- (step 2), its splat after theirs (step 4) and its draw after theirs (step 6), threading the handles the way
183
- every pass here does. Steps 5 and 7 are unchanged and cannot tell the two apart. Step 6 writes a fourth
184
- accumulator, `accum_emission` (§3.9). The orchestrator now returns early only when there are neither
185
- transparent materials nor channels.
186
-
187
- ### 3.2 Depth curve and virtual slices
188
-
189
- Let `z` be the fragment's view-space depth (`get_view_space_depth`, positive, world units). *Revision 4:* the
190
- curve is the engine's log depth slicing — `cluster_depth_to_z_slice`, the same function the light clusters
191
- and the froxels use — with parameters from `build_light_cluster_parameters` built once per frame by
192
- `avboit_build_depth_curve`:
193
-
194
- ```
195
- slice(z) = log2(z · B + O) · scale clamped to [0, V_max]
196
- ```
197
-
198
- `build_light_cluster_parameters` takes a near offset and a `scale`; `scale` is the linearization the deck
199
- describes (larger flattens the curve toward linear), and AVBOIT chooses it so that `O` is zero — pure log
200
- from `near + AVBOIT_DEPTH_CURVE_NEAR_OFFSET` — because the adaptive warp makes near-plane precision free.
201
- The parameters are built for `V_max`; the coordinate at the active resolution `V` is `slice × V / V_max`.
202
- Revisions 1–3 carried a curve of their own with the same shape and a `z0` knob; it was a reinvention.
203
-
204
- `V` starts at `AVBOIT_VIRTUAL_SLICES_MAX = 4096` (128 words of occupancy bits; 1024 until revision 3) and
205
- halves until the occupied count fits `AVBOIT_PHYSICAL_SLICES = 128`. Halving keeps the curve fixed and doubles slice thickness, so the
206
- occupancy at the coarser level is exactly the OR of adjacent pairs — no re-voxelization, which is what the deck
207
- notes too ("coverage data doesn't need to be regenerated"). The loop terminates at `V = P` in the worst case
208
- (three halvings from 1024).
209
-
210
- ### 3.3 Occupancy prepass
211
-
212
- One thread per surviving meshlet (indirect over the filtered collection's count). The world AABB is projected
213
- with `aabb3_project(bounds, node.global)` exactly as the HZB filter does
214
- ([`shader_hzb_meshlet_filter_1way.js`](../../cull/hzb/shader_hzb_meshlet_filter_1way.js)), then again with
215
- `camera.view_matrix`; the view-space depth range is `[-max.z, -min.z]` (the camera looks down −Z; see
216
- `chunk_volumetrics_sun_optical_depth.js:123`). Entirely in front of `near` → skip. Otherwise clamp to
217
- `[near, far]`, map both ends through `t()`, dilate by one virtual slice each side, and `atomicOr` the bits of
218
- that range into `occupancy: array<atomic<u32>, 32>`.
219
-
220
- Only the Z axis is voxelized. The deck also keeps XY tile occupancy to skip empty tiles in clear and
221
- integration; that is an optimization on passes that cost ~0.25 ms at our resolution and is out of scope (§7).
222
-
223
- ### 3.4 Warp LUT build
224
-
225
- *Revision 10:* one workgroup of 128 invocations, one per occupancy word. Revisions 1–9 had a single
226
- invocation, on the argument that a 1 K-entry prefix sum is not a workload and that a single lane keeps the
227
- shader runnable in the WGSL emulator; at `V_max = 4096` the serial LUT alone measured 136 µs (ledger entry 27).
228
- A resolution tried is every invocation marking the virtual slices its finest word's runs touch, at most two
229
- words, OR-ed into workgroup memory, then every word of it dilated by its own invocation and counted with a
230
- subgroup reduction; the LUT is a subgroup scan of the chosen words' counts. Each decision is made on a count
231
- read back through `workgroupUniformLoad`. The emulator cannot run it: the pure parts are chunks with specs,
232
- and the whole was verified bit-exact against the single-lane build on a device (ledger entry 28).
233
-
234
- Per level, in order: dilate the occupancy by one slice each side *at this level* (a fragment on the edge of a
235
- meshlet's bounds linear-splats half its extinction one slice out, and that slice has to belong to the same run
236
- — dilating only at the finest level can shrink to nothing after halving), count, and either accept or halve the
237
- resolution, marked afresh from the finest bits, and repeat.
238
-
239
- Output, `AVBOIT_WARP_STRUCT`:
240
-
241
- ```
242
- virtual_count u32 V
243
- occupied_count u32 physical slices in use, ≤ P
244
- physical_count u32 P
245
- voxel_width, voxel_height u32 extinction resolution
246
- depth_near, depth_far, depth_z0 f32 the curve, copied so every consumer reads one place
247
- lut array<u32, V_max + 1> lut[v] = (prefix(v) << 1) | occupied(v); lut[V] = occupied_count << 1
248
- ```
249
-
250
- The warp itself is a continuous, monotonic, piecewise-linear map from virtual to physical depth:
251
-
252
- ```
253
- φ(v_f) = prefix(v) + occupied(v) × frac(v_f), v = min(floor(v_f), V - 1)
254
- ```
255
-
256
- Slope 1 inside an occupied run, flat across a gap. Flat is the property that makes the deck's "filterable"
257
- begin/end flags unnecessary here: a sample that falls in a gap lands exactly on the boundary between the two
258
- runs, and with the integral stored at slice *boundaries* (§3.6) that reads the previous run's full total and
259
- none of the next run's — which is the right answer for empty space.
260
-
261
- *Revision 9:* with `warp_steps_per_octave > 1` the build also tries `2 L · 2^(-i / steps)` virtual slices
262
- between the octave `L` that fits and the one above it, finest first, with the finest bits rewritten into
263
- those slices conservatively run by run, so the occupied count lands closer to the budget; any virtual count
264
- works downstream, since the coordinate is the finest one scaled by `V / V_max`. Ledger entry 27 has what it
265
- buys and costs. *Revision 11:* four steps is the default; the hysteresis revision 9 added beside the steps
266
- is removed (ledger entry 29).
267
-
268
- ### 3.5 Splat
269
-
270
- A render pass at `ceil(internal / AVBOIT_VOXEL_DOWNSCALE)` with the shared `vertex_shader_chunk`, no depth
271
- attachment, and a `r8unorm` transient colour attachment with `writeMask: 0` because WebGPU wants at least one
272
- attachment and the fragment shader has no outputs. No depth test against the opaque scene is needed: a splat
273
- behind an opaque surface lies at greater depth than any visible transparent fragment, and the integral at a
274
- depth only contains slices in front of it.
275
-
276
- The fragment computes `opacity` exactly as the MBOIT generate pass does (alpha, or Fresnel when
277
- `transmission_factor > 0`), then, new to this path, an RGB self-transmittance:
278
-
279
- ```
280
- coverage = min(opacity, OIT_COVERAGE_MAX)
281
- tint = mix(vec3(1), base_colour, transmission_factor) // clamped ≥ 1e-3
282
- T_self = (1 - coverage) × tint
283
- e = saturate(-log(T_self) / AVBOIT_EXTINCTION_MAX) // AVBOIT_EXTINCTION_MAX = ln 256
284
- ```
285
-
286
- so a plain alpha-blended material behaves exactly as under MBOIT (`tint = 1`) and a transmissive one filters
287
- the background per channel, which the scalar moment path cannot do and the deck lists as the reason RGB OIT is
288
- worth having.
289
-
290
- *Revision 2:* the tint weight is `transmission_factor × tint_from_base_color`, where the flag comes from
291
- `Renderer.avboit.transmission_tint_from_base_color` through the warp header, and is **off by default**. Base
292
- colour as transmission colour is glTF's semantics; the engine's material has no transmission colour, and its
293
- forward shader and path tracer transmit untinted, so the default keeps every mode agreeing on what an asset
294
- means. The RGB plumbing stays and costs nothing while it waits for a real transmission colour.
295
-
296
- Depth: `p_f = φ(t(z) × V)`; linear splat with `c = p_f - 0.5`, `(1 - frac c)` into `floor(c)` and `frac c`
297
- into the next slice, each clamped to `[0, P - 1]`. Each slice gets one `atomicAdd` of the three 8-bit counts
298
- packed 10|10|10 into a `u32` (§3.7). The returned previous value is checked per channel; a field that crosses
299
- 255 records the slice in `overflow` — three `array<atomic<u32>>` planes, one per channel, holding
300
- `P - slice` under `atomicMax` so that the buffer's zero-clear reads as "no overflow" and no fill pass is needed.
301
-
302
- ### 3.6 Integration
303
-
304
- One thread per voxel column. Walks `s = 0 … P - 1`, keeps a running RGB extinction, and stores it into
305
- `integral[x, y, s]` *before* adding slice `s` — an exclusive prefix, so texel `s` holds the integral at the
306
- near boundary of slice `s`, and the texture has `P + 1` depth texels with `integral[P]` holding the total. Per
307
- channel, once `s` reaches that channel's first overflow slice the running value is pinned at 1.0. Values are
308
- saturated at 1.0 throughout.
309
-
310
- Format: `rgba8unorm`, 3D, `STORAGE_BINDING | TEXTURE_BINDING`, sampled trilinearly. Eight bits is what the deck
311
- ships and what the splat already quantizes to; `rgba16float` is a one-constant change if a smoke gradient shows
312
- banding, at twice the memory (§9).
313
-
314
- Layout of `extinction`: column-major with slice fastest, `index = (y × W + x) × P + s`, so the integration
315
- reads 512 contiguous bytes per column.
316
-
317
- ### 3.7 Packing and precision
318
-
319
- Three 8-bit values in 10-bit fields, as the deck does: two guard bits per field so that four saturating events
320
- in one slice can pile up before a carry corrupts the low bits of the neighbouring channel, and overflow is
321
- flagged the first time a field's sum exceeds 255 — past which the ray is extinct anyway. A carry out of the top
322
- field lands in the two unused bits.
323
-
324
- `AVBOIT_EXTINCTION_MAX = ln 256`: the fixed-point unit is `ln 256 / 255 ≈ 0.0217` of extinction, so the
325
- finest non-zero occlusion a single event can register is ~2.2 % and full saturation is `T = 1/256`. The
326
- resolve does *not* depend on this quantization for the surfaces' own alpha — the accumulators are float and
327
- carry the exact `-log(1 - α)` — only the relative ordering weights do.
328
-
329
- ### 3.8 Draw
330
-
331
- A copy of the MBOIT resolve shader's shape — same vertex chunk, same material/scene/light groups, same forward
332
- shading and inline volumetric composite — with the moment lookup replaced by
333
-
334
- ```
335
- v_s = max(t(z) × V - AVBOIT_SAMPLE_BIAS_SLICES, 0) // bias in virtual slices, see below
336
- w = (φ(v_s) + 0.5) / (P + 1)
337
- E = textureSampleLevel(integral, linear, vec3(uv, w), 0).rgb
338
- T = exp(-E × AVBOIT_EXTINCTION_MAX)
339
- ```
340
-
341
- and, before any of the shading, a discard when `T ≤ 1/256` in every channel — the volume already calls the
342
- fragment extinct, so its shading would be multiplied away; what its own extinction would have added to the
343
- total is bounded by that same `1/256` (revision 3, `AVBOIT_EXTINCT_TRANSMITTANCE`). Then three additive
344
- `rgba16float` targets:
345
-
346
- ```
347
- accum_color += colour × coverage × T (premultiplied, as MBOIT)
348
- accum_norm += (1 - T_self) × T per channel
349
- accum_ext += -log(T_self) per channel
350
- ```
351
-
352
- The bias is applied in *virtual* space before the warp, not in physical space after it: inside a run the two
353
- are identical, and at the start of a run the virtual bias walks into the gap, where φ is flat and the sample
354
- reads the previous run's total — instead of reading two slices into a run that may be arbitrarily far away.
355
- With the splat and storage conventions above the analytic minimum that avoids any self-occlusion is 1.5 slices;
356
- `AVBOIT_SAMPLE_BIAS_SLICES = 2.0` follows the deck and leaves half a slice of margin.
357
-
358
- *Revision 8:* that minimum is for a surface splatted at its own depth, and the draw also reads the
359
- neighbouring columns, up to a voxel away, where a surface tilted away from the camera was splatted nearer.
360
- Every draw of a surface that splats adds `avboit_footprint_bias` — `8 × fwidth(v)` virtual slices, a voxel's
361
- width of its own depth change, capped at `2 V / P`, the base bias of the coarsest slicing — so a tilted
362
- surface does not occlude itself; additive particles, which write nothing into the volume, add none. A
363
- tilted fragment is then not occluded by what lies within that band in front of it (ledger entry 26). The
364
- cap bounds the band; the whole reach is at most `2 + 2 V / P`.
365
-
366
- IBL and Brick4 variants are two files, as for MBOIT, sharing the fragment body text; the Brick4 one carries
367
- the extra `brick4` storage buffer in the view group.
368
-
369
- ### 3.9 Resolve
370
-
371
- RGB total transmittance cannot go through fixed-function blending without dual-source blending, so the resolve
372
- reads the scene colour as an input and writes a fresh `rgba16float` transient (the MBOIT blend shader's own
373
- `TODO` says as much). Per channel:
374
-
375
- ```
376
- T_total = exp(-accum_ext)
377
- norm = accum_norm > 1e-4 ? (1 - T_total) / accum_norm : 0
378
- out = scene × T_total + accum_color × norm + accum_emission
379
- ```
380
-
381
- with the same NaN backstop as MBOIT, falling back to the scene colour.
382
-
383
- *Revision 5:* `accum_emission` is the fourth accumulator, for fragments that emit without covering —
384
- additive particles today. Such a fragment writes zero extinction and zero norm, so the normalization, whose
385
- job is to redistribute exactly the `1 - T_total` the covering surfaces took from the scene, must not touch
386
- it; it joins the sum as it is, already attenuated by the transmittance in front of it at draw time. The
387
- alternative, a three-target draw pipeline for frames with no such source, is a variant of the draw the plan
388
- refuses to keep two of (§5); the cost of the fourth target is one `rgba16float` at internal resolution and a
389
- `vec4(0)` written by every transparent mesh fragment.
390
-
391
- ### 3.10 The switch
392
-
393
- `src/shade/renderer/ShadeTransparencyMode.js`:
394
-
395
- ```js
396
- export const ShadeTransparencyMode = { MBOIT: 0, AVBOIT: 1 };
397
- ```
398
-
399
- `Renderer.transparency_mode = ShadeTransparencyMode.MBOIT` (public field, documented), and at the call site a
400
- ternary between the two orchestrators, which take the same argument object. Nothing else in `Renderer` changes.
401
-
402
- ### 3.11 Device requirements
403
-
404
- AVBOIT blends only `rgba16float`, so it does not need `float32-blendable`; the atomics it uses on storage
405
- buffers from the fragment stage are core WebGPU. The engine keeps requiring `float32-blendable` while MBOIT is
406
- the default; the contract gets a sentence saying which mode needs it. The subgroup-using CSDLDF scan in the
407
- draw-command prep is shared with MBOIT and unchanged.
408
-
409
- One layout detail with no precedent in the tree: no render pipeline here writes a storage buffer from the
410
- fragment stage yet, and `ShaderResourceSetDescriptor.generatePipelineLayout(stage)` gives every group the same
411
- visibility. WebGPU refuses a `storage` buffer binding visible to the vertex stage, so the splat pipeline builds
412
- its layout group by group — material, scene and view at `VERTEX | FRAGMENT`, the atomics group at `FRAGMENT`.
413
-
414
- ---
415
-
416
- ## 4. Decisions and the alternatives they beat
417
-
418
- | Decision | Alternative | Why not |
419
- |----------|-------------|---------|
420
- | RGB 10\|10\|10 extinction from the start | Scalar 8\|8\|8\|8 (four slices per word, 4× less memory) | The deck's whole argument for the voxel path is that RGB becomes affordable, and a transmission colour on the material is the obvious next step; the scalar buffer is a memory optimization for VFX-heavy content, listed in §7. *Revision 2:* the per-channel tint is opt-in (§3.5) — the material model does not carry a transmission colour, so deriving one from the base colour by default made one asset mean two things across the mode switch. |
421
- | Packed 8-bit counts with overflow-min | One `u32` per channel per slice (no carry, no overflow logic) | 3× memory (200 MB at 4 K) and three atomics per splat; the deck measured packed at the same speed as monochrome. |
422
- | Storage buffer for the extinction volume | 3D storage texture | WebGPU has no atomic image operations. |
423
- | Integral as exclusive prefix at slice boundaries, `P + 1` texels | Inclusive prefix at slice centres | Makes a gap sample land exactly on a run boundary and read the right total; costs one extra depth texel. |
424
- | Sample bias in virtual space before the warp | Bias in physical space after it | Across a gap the physical bias reaches into a different depth region; the virtual one stops at the flat boundary. |
425
- | *Revision 10:* warp built by one workgroup, an invocation per occupancy word, subgroup reductions and scan | One invocation (revisions 1–9) | At 4096 virtual slices the serial LUT alone cost 136 µs on an RTX 4090, and the steps' run walk up to 295 µs more; the workgroup takes 3–9 µs with the same output (ledger entry 28). The emulator cannot run it; its pure parts are chunks with specs. |
426
- | Occupancy from meshlet AABBs | Conservative software voxelization of quads and boxes (the deck) | The engine already has HZB-filtered meshlet bounds on the GPU; a meshlet is a tighter primitive than a mesh box. |
427
- | *Revision 4:* the engine's depth slicing, Morton decode, linear-clamp sampler and a shared draw loop | The pipeline's own curve, bit fold, sampler descriptor and a copy of the MBOIT draw loop | Reinventions, found in review. The one thing kept apart from the engine on purpose is the shared draw-fragment body text (`avboit_draw_fragment_body.js`): MBOIT duplicates its resolve body across the IBL and Brick4 files, and two 45-line bodies drifting apart is the worse failure. |
428
- | No depth test in the splat pass | Low-res depth from the HZB | Correctness does not need it (§3.5); it is a splat-throughput optimization to measure first. |
429
- | Resolve writes a new transient | Two in-place blend passes (multiply, then add) | One shader, one pass; the transient is aliased by the graph. |
430
- | `rgba8unorm` integral | `rgba16float` | Matches the deck and the splat quantization; the swap is one constant if banding shows. |
431
- | MBOIT stays the default | Flip to AVBOIT | The contract promises no lesser frame; the new path has not been seen on real content yet. |
432
-
433
- Rejected outright: the deck's chroma-skew approximation for memory-constrained platforms (slides 132–135) —
434
- it exists because that content could not afford the RGB buffer, and we can.
435
-
436
- ---
437
-
438
- ## 5. Files
439
-
440
- ```
441
- src/shade/renderer/ShadeTransparencyMode.js
442
- src/shade/renderer/rasterize/native/material_draw_indirect.js the per-material indirect draw loop, shared with MBOIT
443
- src/shade/renderer/rasterize/native/avboit/
444
- AVBOIT_PLAN_2026_09_03.md this document
445
- AVBOIT_LEDGER.md the step ledger
446
- AVBOIT_CONSTANTS.js P, V_max, downscale, curve offset, extinction max, bias, early-out
447
- AVBOITSettings.js Renderer.avboit
448
- AVBOIT_WARP_STRUCT.js header + LUT storage layout
449
- avboit_build_depth_curve.js cluster parameters for the finest resolution (JS)
450
- chunk_avboit_pack_counts.js 10|10|10 pack
451
- chunk_avboit_unpack_counts.js … and unpack
452
- chunk_avboit_transmittance_to_extinction.js
453
- chunk_avboit_extinction_to_transmittance.js
454
- chunk_avboit_extinction_to_counts.js
455
- chunk_avboit_counts_to_extinction.js
456
- chunk_avboit_overflows.js the per-channel overflow predicate
457
- chunk_avboit_occupancy_range.js slice interval → dilated slice range
458
- chunk_avboit_occupancy_word_mask.js bits of one word inside a range
459
- chunk_avboit_dilate_word.js one-slice dilation across words
460
- chunk_avboit_fold_pairs.js halve a word's resolution (via decode32_morton2); unused since rev 10
461
- chunk_avboit_warp_marks.js the virtual slices a finest word's runs touch (rev 10)
462
- chunk_avboit_warp_level_word.js a resolution's word, dilated and cut at V
463
- chunk_avboit_warp_step_count.js the resolutions between octaves
464
- chunk_avboit_warp_lut_entry.js one LUT entry from its word and the count below it
465
- chunk_avboit_warp.js φ(v_f) over the LUT
466
- chunk_avboit_view_depth_to_virtual.js the curve, scaled to the active resolution
467
- chunk_avboit_view_depth_to_physical.js curve then warp
468
- chunk_avboit_integral_depth_coordinate.js bias, warp, boundary-centred texel coordinate
469
- chunk_avboit_sample_transmittance.js trilinear sample and exp
470
- chunk_avboit_transmission_tint.js base colour × weight
471
- chunk_avboit_splat_slice.js the two-slice voxel write, shared with the side channels
472
- AVBOITSideChannel.js the contract for a non-meshlet transparent source (rev 5)
473
- shader_avboit_occupancy.js compute, per meshlet
474
- shader_avboit_build_warp.js compute, one workgroup (rev 10)
475
- shader_avboit_splat.js render pass, 1/8 resolution, atomics
476
- shader_avboit_integrate.js compute, per column
477
- avboit_draw_fragment_body.js shared WGSL text of the draw fragment
478
- shader_avboit_draw_ibl.js render pass, IBL indirect
479
- shader_avboit_draw_brick4.js render pass, Brick4 indirect
480
- shader_avboit_resolve.js image shader
481
- graph_rasterize_meshes_transparent_avboit.js
482
- avboit_spec_support.js test-only helpers
483
- *.spec.js one per chunk and shader, see §6
484
- src/shade/playground/avboit/ A/B page, see §6 tier 4
485
- ```
486
-
487
- Naming follows the directory's conventions: `chunk_*` for a `CodeChunk` holding exactly the one function the
488
- file is named after (650 of the engine's ~700 chunk files do; revision 4 brought these in line), `shader_*`
489
- for a complete pipeline, `graph_*` for a recorder, `SCREAMING_SNAKE` for structs and constants, specs beside
490
- their subject.
491
-
492
- ---
493
-
494
- ## 6. Verification
495
-
496
- The four tiers from [`gpu-testing-tiers`], each pinning what the one below cannot see:
497
-
498
- 1. **WGSL validity** — `avboit_shaders_wgsl_validity.spec.js`, `test.each` over every assembled module
499
- (vertex + fragment of splat and the two draws, the four compute shaders, the resolve image shader), zero
500
- diagnostics. Catches missing chunk dependencies and reserved words; proves nothing about types.
501
- 2. **Emulator** — numeric behaviour of the pure parts:
502
- - `chunk_avboit_depth_curve.spec.js`: `t(near) = 0`, `t(far) = 1`, monotonic, `z(t(z)) = z`.
503
- - `chunk_avboit_pack.spec.js`: pack/unpack round trip, the overflow predicate, extinction ↔ transmittance.
504
- - `shader_avboit_build_warp.spec.js`: sparse occupancy keeps `V_max`; dense occupancy halves until it fits;
505
- the LUT is a prefix sum with the dilation applied; `φ` is monotone, slope 1 on runs, flat on gaps.
506
- - `shader_avboit_integrate.spec.js`: one column with events at known slices → exclusive prefix, saturation,
507
- per-channel overflow pinning; written through `textureStore` into a 3D `CPUBitmapData`.
508
- - `chunk_avboit_sample_transmittance.spec.js`: sampling in a gap returns the previous run's total; the bias
509
- removes self-occlusion for an event splatted at the same depth.
510
- 3. **SoftwareGPUDevice** — `graph_rasterize_meshes_transparent_avboit.spec.js`: the warp build's dispatch and
511
- buffer, the integration's dispatch and its `P + 1`-deep storage-and-sampled texture, the resolve's single
512
- full-screen draw into a fresh target, the splat pipeline's atomics group visible to the fragment stage
513
- only, and a source-level pin of the `Renderer` switch. *Revision 3:* the software device records and
514
- validates; it is not an end-to-end runner and never was meant as one, so a spec of the whole orchestrator
515
- over a scene is not a goal of this plan. The composition is proven on a device.
516
- 4. **Real compile and eyes** — every module through `createShaderModule` on a real device (the validator has no
517
- type checker, [`wgsl-real-compile-via-browser-pane`]), then a playground page with layered transparent quads
518
- at controlled depth separations, a tinted glass pane, and the MBOIT/AVBOIT switch — the deck's own test
519
- harness in miniature. Bounded per [`bounded-user-verification`]: one scripted session, findings into the
520
- ledger.
521
-
522
- ---
523
-
524
- ## 7. Out of scope (deliberately, with the reason)
525
-
526
- *Revision 3* decides the optimizations one by one, against the rule that a phase-2 item has to be clean and
527
- unambiguous, must not break anything else, and must not be situational:
528
-
529
- - **Per-fragment extinct early-out** — *done* (§3.8). No new resource, no pass, a bounded error below the
530
- volume's own precision, and it removes the whole forward shading cost of every fragment behind something
531
- opaque-in-the-volume.
532
- - **XY tile occupancy** to skip empty tiles in clear and integration — *no*. The passes it would trim are
533
- sub-millisecond at 1/8 resolution and the clear is one `clearBuffer`; the prepass would gain a second
534
- output and the integration a second input for a saving that would not register.
535
- - **Zero-transmittance depth cull** (slides 77–85) — *not now*. It is the deck's largest measured win on
536
- VFX-heavy scenes, and it is exactly the situational kind: nothing on a scene without dense overdraw, a
537
- depth copy because post-process reads the scene depth after transparency, and a new pass that writes depth.
538
- Worth a plan of its own when there is a scene that needs it and a profile that shows the draw cost.
539
- - **Monochrome extinction buffer** beside the RGB one — *no*. Two representations of the same volume and a
540
- merge in the integration, for content that is mostly scalar VFX; this engine's transparent content is not
541
- known to be that.
542
- - **Sparse voxel texture** (slide 122) — *no*. The deck's own future work.
543
- - **Chroma skew** (§4).
544
- - **`ShadeDrawSide.Back` transparent materials** — ~~dropped today by MBOIT; the same filter is used here so
545
- the two modes draw the same set. Fixing it is a bucket-filter change that belongs to both.~~ **Done,
546
- 2026-09-16 (`ca95ad3ac`)**, and it was the bucket-filter change this predicted: `Back` is `Front` with
547
- the winding reversed in the vertex shader, so both modes draw it and neither needed a third pass.
548
- - **Exposing the tunables on `Renderer`** — the constants in `AVBOIT_CONSTANTS.js` are the knobs; whether any
549
- deserves a public field is a question for after the page in §6 has been looked at. *Revision 2:* one did —
550
- the transmission tint, because it changes a material's meaning rather than a quality/cost trade; it lives
551
- on `Renderer.avboit` (`AVBOITSettings`).
552
-
553
- ---
554
-
555
- ## 8. Staging
556
-
557
- Each step lands with its tests green before the next starts; the ledger records what each found.
558
-
559
- 1. **Skeleton and switch** — enum, `Renderer.transparency_mode`, an orchestrator that records only the shared
560
- prep and the resolve (identity), the prep helper's two extra return values. Proves the wiring compiles and
561
- the default frame is byte-identical.
562
- 2. **Depth curve, warp, pack chunks** with their emulator specs.
563
- 3. **Occupancy + warp build** shaders, the warp struct, emulator spec for the build.
564
- 4. **Splat** shader and the per-group pipeline layout; validity spec.
565
- 5. **Integrate** shader with its emulator spec; the 3D integral texture in the graph.
566
- 6. **Draw** (IBL and Brick4) and the sample chunk with its spec; the three accumulators.
567
- 7. **Resolve** image shader; the orchestrator complete; SoftwareGPUDevice spec.
568
- 8. **Real compile** of every module on a device; fix what the type checker finds.
569
- 9. **Playground** A/B page; look; record.
570
- 10. **Docs** — contract, changelog, ledger closed out.
571
-
572
- ---
573
-
574
- ## 9. Risks and open questions
575
-
576
- - **Sub-pixel geometry at 1/8 resolution** never reaches the extinction volume, so it does not occlude anything
577
- behind it (it still draws). The deck accepts this for VFX; thin glass edges may show it. The downscale is a
578
- constant.
579
- *Revision 7:* trails are the case where it showed — a moving thin trail occluded in some columns and not
580
- others — and the dynamic-mesh splat alone is multisampled and coverage-weighted now (ledger entry 24).
581
- Such a trail reaches the volume everywhere, diluted to the share of each voxel it covers.
582
- - **Meshlet bounds as occupancy** are conservative in depth only as far as the bounds are right; skinned meshes
583
- with stale bounds would splat outside their run and clamp to its edge. Watch for it on the page.
584
- - **8-bit integral** — banding in long smooth gradients; the swap to `rgba16float` is one constant.
585
- - **Contention** — every fragment of a large sprite covering the same low-res texel hits the same `u32`; the
586
- deck's numbers say this is fine on console, and a WebGPU number is what the page is for.
587
- - **The bias** — 2.0 virtual slices is the deck's figure; 1.5 is the analytic minimum here. Lower means closer
588
- events occlude each other; the page's layered quads are the test. *Revision 3:* kept at 2.0. The margin over
589
- the minimum is what covers the depth difference between a splat fragment (one 1/8-resolution pixel centre)
590
- and a draw fragment (a full-resolution pixel centre) on a sloped surface, and the slice floor was raised by
591
- `AVBOIT_VIRTUAL_SLICES_MAX` instead (§3.2).
592
- - **Sloped surfaces** — a splat fragment carries the depth of its low-resolution pixel centre; on a surface at
593
- a grazing angle that can differ from the full-resolution fragment's depth by more than the bias. Self-occlusion
594
- along the slope would be the symptom; the page's copyable camera state is what makes that reproducible.
595
- *Revision 8:* measured and closed. It was not only grazing angles: from about 30° at 1080p a tilted surface
596
- over another transparent layer striped in an 8-pixel sawtooth, 3–5 sRGB codes on the device at 45–60°. The
597
- footprint bias (§3.8) removes it up to its cap, about 85° in a sparse volume (ledger entry 26).
598
- - **A surface spanning a long depth range** — a water plane above all, from the shore to the horizon —
599
- occupies so many virtual slices that the warp halves to `V = P`, and every other transparent surface in
600
- the frame is sliced at the coarsest resolution (*revision 8*, measured in ledger entry 26).
@@ -1,6 +0,0 @@
1
- Basic idea is to stocastically decide which lights are visible, and feed that information into shading stage
2
-
3
- References:
4
- https://github.com/NVIDIAGameWorks/RTXDI
5
- http://www.zyanidelab.com/how-to-add-thousands-of-lights-to-your-renderer/
6
- https://cwyman.org/presentations/2021_HPG_Productizing_ReSTIR.pdf
@@ -1,6 +0,0 @@
1
- # references:
2
- https://sebh.github.io/publications/egsr2020.pdf
3
- https://www.shadertoy.com/view/slSXRW
4
- https://www.reddit.com/r/GraphicsProgramming/comments/osbbhg/shadertoy_implementation_of_a_scalable_and/
5
- https://github1s.com/Fewes/MinimalAtmosphere/blob/master/Assets/Atmosphere/Shaders/Atmosphere.cginc#L146
6
- https://github.com/GPUOpen-LibrariesAndSDKs/FidelityFX-SDK/blob/1bbe66e7ea0d358e84af4471a90aa9c35b583de0/framework/rendermodules/skydome/shaders/skydomeproc.hlsl#L70