@woosh/meep-engine 3.24.0 → 3.26.0

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 (349) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +59 -0
  3. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
  4. package/src/core/geom/3d/shape/HeightMapShape3D.js +285 -0
  5. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  6. package/src/core/geom/3d/shape/PosedShape3D.js +57 -0
  7. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  8. package/src/core/geom/3d/shape/TransformedShape3D.js +102 -0
  9. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  10. package/src/core/geom/3d/shape/UnionShape3D.js +64 -0
  11. package/src/engine/graphics3/PickingSystem.d.ts +3 -3
  12. package/src/engine/graphics3/PickingSystem.d.ts.map +1 -1
  13. package/src/engine/graphics3/PickingSystem.js +52 -55
  14. package/src/engine/graphics3/shader_picking_gather.d.ts +40 -0
  15. package/src/engine/graphics3/shader_picking_gather.d.ts.map +1 -0
  16. package/src/engine/graphics3/shader_picking_gather.js +120 -0
  17. package/src/engine/physics/cloth/MEASUREMENTS.md +1632 -0
  18. package/src/engine/physics/cloth/PLAN.md +738 -95
  19. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +84 -17
  20. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
  21. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +451 -42
  22. package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.d.ts +52 -0
  23. package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.d.ts.map +1 -0
  24. package/src/engine/physics/cloth/ecs/ClothColliderSerializationAdapter.js +70 -0
  25. package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts +12 -3
  26. package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts.map +1 -1
  27. package/src/engine/physics/cloth/ecs/ClothDynamics.js +340 -331
  28. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +101 -29
  29. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  30. package/src/engine/physics/cloth/ecs/ClothInstance.js +110 -31
  31. package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.d.ts +84 -0
  32. package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.d.ts.map +1 -0
  33. package/src/engine/physics/cloth/ecs/ClothSerializationAdapter.js +141 -0
  34. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +71 -81
  35. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  36. package/src/engine/physics/cloth/ecs/ClothSystem.js +135 -856
  37. package/src/engine/physics/cloth/ecs/ClothWorkerCore.d.ts +48 -0
  38. package/src/engine/physics/cloth/ecs/ClothWorkerCore.d.ts.map +1 -0
  39. package/src/engine/physics/cloth/ecs/ClothWorkerCore.js +107 -0
  40. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +323 -0
  41. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -0
  42. package/src/engine/physics/cloth/ecs/ClothWorld.js +1248 -0
  43. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +192 -0
  44. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -0
  45. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +578 -0
  46. package/src/engine/physics/cloth/ecs/cloth.worker.d.ts +2 -0
  47. package/src/engine/physics/cloth/ecs/cloth.worker.d.ts.map +1 -0
  48. package/src/engine/physics/cloth/ecs/cloth.worker.js +12 -0
  49. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  50. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +2 -1
  51. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +85 -3
  52. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  53. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +366 -271
  54. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +95 -12
  55. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  56. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +170 -27
  57. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +19 -0
  58. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  59. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +249 -201
  60. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -0
  61. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  62. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +62 -1
  63. package/src/engine/physics/cloth/ecs/cloth_worker_protocol.d.ts +29 -0
  64. package/src/engine/physics/cloth/ecs/cloth_worker_protocol.d.ts.map +1 -0
  65. package/src/engine/physics/cloth/ecs/cloth_worker_protocol.js +78 -0
  66. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  67. package/src/engine/physics/cloth/ecs/cloth_write_back.js +18 -10
  68. package/src/engine/physics/cloth/ecs/makeClothWorker.d.ts +17 -0
  69. package/src/engine/physics/cloth/ecs/makeClothWorker.d.ts.map +1 -0
  70. package/src/engine/physics/cloth/ecs/makeClothWorker.js +18 -0
  71. package/src/engine/physics/cloth/playground/README.md +73 -2
  72. package/src/engine/physics/cloth/playground/collide_main.js +1 -1
  73. package/src/engine/physics/cloth/playground/wind.html +166 -0
  74. package/src/engine/physics/cloth/playground/wind_build.d.ts +81 -0
  75. package/src/engine/physics/cloth/playground/wind_build.d.ts.map +1 -0
  76. package/src/engine/physics/cloth/playground/wind_build.js +141 -0
  77. package/src/engine/physics/cloth/playground/wind_main.d.ts +2 -0
  78. package/src/engine/physics/cloth/playground/wind_main.d.ts.map +1 -0
  79. package/src/engine/physics/cloth/playground/wind_main.js +681 -0
  80. package/src/engine/physics/cloth/solver/ClothState.d.ts +134 -79
  81. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  82. package/src/engine/physics/cloth/solver/ClothState.js +273 -12
  83. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +29 -8
  84. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  85. package/src/engine/physics/cloth/solver/cloth_contact_find.js +37 -9
  86. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +45 -2
  87. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  88. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +46 -2
  89. package/src/engine/physics/cloth/solver/cloth_step.d.ts +21 -2
  90. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  91. package/src/engine/physics/cloth/solver/cloth_step.js +173 -4
  92. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +40 -0
  93. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -0
  94. package/src/engine/physics/cloth/solver/cloth_step_instance.js +284 -0
  95. package/src/engine/physics/cloth/solver/cloth_wind_accelerate.d.ts +107 -0
  96. package/src/engine/physics/cloth/solver/cloth_wind_accelerate.d.ts.map +1 -0
  97. package/src/engine/physics/cloth/solver/cloth_wind_accelerate.js +263 -0
  98. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +9 -2
  99. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -1
  100. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +9 -2
  101. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts +102 -0
  102. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts.map +1 -0
  103. package/src/engine/physics/cloth/wind/AbstractClothWind.js +114 -0
  104. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts +87 -0
  105. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts.map +1 -0
  106. package/src/engine/physics/cloth/wind/ClothAmbientWind.js +185 -0
  107. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts +79 -0
  108. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -0
  109. package/src/engine/physics/cloth/wind/ClothFluidWind.js +213 -0
  110. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +106 -0
  111. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -0
  112. package/src/engine/physics/cloth/wind/cloth_sample_air.js +297 -0
  113. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  114. package/src/shade/device/mock/texture_copy.d.ts.map +1 -1
  115. package/src/shade/device/mock/texture_copy.js +28 -0
  116. package/src/shade/playground/vgeo_runtime/README.md +94 -0
  117. package/src/shade/playground/vgeo_runtime/index.html +62 -0
  118. package/src/shade/playground/vgeo_runtime/main.d.ts +2 -0
  119. package/src/shade/playground/vgeo_runtime/main.d.ts.map +1 -0
  120. package/src/shade/playground/vgeo_runtime/main.js +399 -0
  121. package/src/shade/playground/vgeo_viewer/sample_asset.js +1 -1
  122. package/src/shade/renderer/camera/Camera.d.ts +14 -0
  123. package/src/shade/renderer/camera/Camera.d.ts.map +1 -1
  124. package/src/shade/renderer/camera/Camera.js +7 -1
  125. package/src/shade/renderer/geometry/GEOMETRY_METADATA_STRUCT.d.ts.map +1 -1
  126. package/src/shade/renderer/geometry/GEOMETRY_METADATA_STRUCT.js +16 -1
  127. package/src/shade/renderer/geometry/GPUGeometryManager.d.ts.map +1 -1
  128. package/src/shade/renderer/geometry/GPUGeometryManager.js +29 -9
  129. package/src/shade/renderer/geometry/GPUGeometryMetadata.d.ts +10 -0
  130. package/src/shade/renderer/geometry/GPUGeometryMetadata.d.ts.map +1 -1
  131. package/src/shade/renderer/geometry/GPUGeometryMetadata.js +13 -0
  132. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +46 -18
  133. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +70 -22
  134. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +97 -19
  135. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +12 -2
  136. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  137. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +14 -3
  138. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts +2 -2
  139. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
  140. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +124 -6
  141. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts +22 -0
  142. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts.map +1 -0
  143. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.js +53 -0
  144. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +8 -1
  145. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
  146. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +8 -1
  147. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.d.ts +16 -0
  148. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.d.ts.map +1 -0
  149. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FEATURE_IGNORABLE_BOUNDED_PAGES.js +15 -0
  150. package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.d.ts +54 -0
  151. package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.d.ts.map +1 -0
  152. package/src/shade/renderer/geometry/virtual/format/page/VGEO_DEFAULT_PAGE_SIZE.js +53 -0
  153. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +13 -2
  154. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
  155. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +14 -2
  156. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +100 -0
  157. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
  158. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +113 -0
  159. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.d.ts.map +1 -1
  160. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.js +5 -0
  161. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
  162. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +108 -0
  163. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  164. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +23 -0
  165. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  166. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +40 -0
  167. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +228 -0
  168. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -0
  169. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +932 -0
  170. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +176 -0
  171. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -0
  172. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +425 -0
  173. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +241 -0
  174. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +574 -0
  175. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +120 -0
  176. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -0
  177. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +674 -0
  178. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +287 -0
  179. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -0
  180. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +976 -0
  181. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +42 -0
  182. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -0
  183. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +96 -0
  184. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.d.ts +16 -0
  185. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.d.ts.map +1 -0
  186. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_CULL.js +15 -0
  187. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts +19 -0
  188. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -0
  189. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +83 -0
  190. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.d.ts +9 -0
  191. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.d.ts.map +1 -0
  192. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_WORKGROUP_SIZE.js +8 -0
  193. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts +19 -0
  194. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -0
  195. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +160 -0
  196. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts +3 -0
  197. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -0
  198. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +255 -0
  199. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts +3 -0
  200. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -0
  201. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +80 -0
  202. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts +3 -0
  203. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -0
  204. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +144 -0
  205. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts +3 -0
  206. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -0
  207. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +530 -0
  208. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +39 -0
  209. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -0
  210. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +54 -0
  211. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.d.ts +41 -0
  212. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.d.ts.map +1 -0
  213. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_if_enabled.js +56 -0
  214. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts +49 -0
  215. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -0
  216. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +328 -0
  217. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts +10 -0
  218. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts.map +1 -0
  219. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.js +51 -0
  220. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts +13 -0
  221. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts.map +1 -0
  222. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.js +12 -0
  223. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +17 -0
  224. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts.map +1 -0
  225. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +99 -0
  226. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.d.ts +9 -0
  227. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.d.ts.map +1 -0
  228. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +8 -0
  229. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +7 -0
  230. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts.map +1 -0
  231. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +27 -0
  232. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.d.ts +14 -0
  233. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.d.ts.map +1 -0
  234. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_NONE.js +13 -0
  235. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.d.ts +7 -0
  236. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.d.ts.map +1 -0
  237. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_OFFSET.js +35 -0
  238. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.d.ts +9 -0
  239. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.d.ts.map +1 -0
  240. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GEOMETRY_ROW_WORDS.js +8 -0
  241. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.d.ts +15 -0
  242. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.d.ts.map +1 -0
  243. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_FLAG_SELECTABLE.js +14 -0
  244. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +7 -0
  245. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts.map +1 -0
  246. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +36 -0
  247. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +10 -0
  248. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -0
  249. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +9 -0
  250. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.d.ts +11 -0
  251. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.d.ts.map +1 -0
  252. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_OFFSET.js +54 -0
  253. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.d.ts +9 -0
  254. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.d.ts.map +1 -0
  255. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_INSTANCE_WORDS.js +8 -0
  256. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.d.ts +11 -0
  257. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.d.ts.map +1 -0
  258. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_LEAF_BIT.js +10 -0
  259. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.d.ts +7 -0
  260. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.d.ts.map +1 -0
  261. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_OFFSET.js +30 -0
  262. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.d.ts +9 -0
  263. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.d.ts.map +1 -0
  264. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NODE_ROW_WORDS.js +8 -0
  265. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.d.ts +13 -0
  266. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.d.ts.map +1 -0
  267. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_NO_CHILD_PAGE.js +12 -0
  268. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.d.ts +14 -0
  269. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.d.ts.map +1 -0
  270. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_NONE.js +13 -0
  271. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +11 -0
  272. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts.map +1 -0
  273. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +61 -0
  274. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts +9 -0
  275. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -0
  276. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +8 -0
  277. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.d.ts +13 -0
  278. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.d.ts.map +1 -0
  279. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_ITEM_WORDS.js +12 -0
  280. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.d.ts +9 -0
  281. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.d.ts.map +1 -0
  282. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_GROUP_BIT.js +8 -0
  283. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.d.ts +20 -0
  284. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.d.ts.map +1 -0
  285. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_WANT_WORDS.js +19 -0
  286. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts +23 -0
  287. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -0
  288. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +70 -0
  289. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +18 -0
  290. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -0
  291. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +25 -0
  292. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts +35 -0
  293. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts.map +1 -0
  294. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.js +41 -0
  295. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +32 -0
  296. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -0
  297. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +138 -0
  298. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  299. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  300. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  301. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +9 -0
  302. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  303. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +12 -1
  304. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  305. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +12 -1
  306. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  307. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +10 -0
  308. package/src/shade/renderer/scene/GPUSceneContext.d.ts +18 -0
  309. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  310. package/src/shade/renderer/scene/GPUSceneContext.js +647 -594
  311. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
  312. package/src/shade/renderer/scene/rows/GPUSceneRows.js +22 -0
  313. package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.d.ts +35 -0
  314. package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.d.ts.map +1 -0
  315. package/src/shade/renderer/shader/chunk/geometry/mat3/chunk_mat3_singular_values.js +91 -0
  316. package/src/engine/graphics3/instantiate_scene_bundle.d.ts +0 -54
  317. package/src/engine/graphics3/instantiate_scene_bundle.d.ts.map +0 -1
  318. package/src/engine/graphics3/shade_node_to_entity_composition.d.ts +0 -39
  319. package/src/engine/graphics3/shade_node_to_entity_composition.d.ts.map +0 -1
  320. package/src/shade/renderer/animation/compute_skin_world_bounds.d.ts +0 -35
  321. package/src/shade/renderer/animation/compute_skin_world_bounds.d.ts.map +0 -1
  322. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.d.ts +0 -96
  323. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.d.ts.map +0 -1
  324. package/src/shade/renderer/animation/pose/pose_evaluate_world.d.ts +0 -20
  325. package/src/shade/renderer/animation/pose/pose_evaluate_world.d.ts.map +0 -1
  326. package/src/shade/renderer/animation/skin_bind_transform.d.ts +0 -25
  327. package/src/shade/renderer/animation/skin_bind_transform.d.ts.map +0 -1
  328. package/src/shade/renderer/animation/skin_frame_defect.d.ts +0 -34
  329. package/src/shade/renderer/animation/skin_frame_defect.d.ts.map +0 -1
  330. package/src/shade/renderer/animation/skin_joint_matrix.d.ts +0 -24
  331. package/src/shade/renderer/animation/skin_joint_matrix.d.ts.map +0 -1
  332. package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts +0 -70
  333. package/src/shade/renderer/animation/skin_normalize_mesh_frame.d.ts.map +0 -1
  334. package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts +0 -96
  335. package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts.map +0 -1
  336. package/src/shade/renderer/scene/InstanceBatch.d.ts +0 -92
  337. package/src/shade/renderer/scene/InstanceBatch.d.ts.map +0 -1
  338. package/src/shade/renderer/scene/Mesh.d.ts +0 -55
  339. package/src/shade/renderer/scene/Mesh.d.ts.map +0 -1
  340. package/src/shade/renderer/scene/Node3D.d.ts +0 -159
  341. package/src/shade/renderer/scene/Node3D.d.ts.map +0 -1
  342. package/src/shade/renderer/scene/Node3DDirtyList.d.ts +0 -59
  343. package/src/shade/renderer/scene/Node3DDirtyList.d.ts.map +0 -1
  344. package/src/shade/renderer/scene/SceneNodeBinding.d.ts +0 -52
  345. package/src/shade/renderer/scene/SceneNodeBinding.d.ts.map +0 -1
  346. package/src/shade/renderer/scene/SkinnedMesh.d.ts +0 -27
  347. package/src/shade/renderer/scene/SkinnedMesh.d.ts.map +0 -1
  348. package/src/shade/renderer/scene/TransformAuthority.d.ts +0 -19
  349. package/src/shade/renderer/scene/TransformAuthority.d.ts.map +0 -1
@@ -0,0 +1,255 @@
1
+ import { atomic_u32, u32 } from "../../../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
2
+ import { WebGPUArray } from "../../../../shader/type/WebGPUArray.js";
3
+ import { CAMERA_UNIFORM_STRUCT } from "../../../../camera/CAMERA_UNIFORM_STRUCT.js";
4
+ import { CodeChunk } from "../../../../shader/compiler/CodeChunk.js";
5
+ import { COLLECTION_U32_STRUCT_READ } from "../../../../gpu_primitive/COLLECTION_U32_STRUCT_READ.js";
6
+ import { COLLECTION_U32_STRUCT_WRITE } from "../../../../gpu_primitive/COLLECTION_U32_STRUCT_WRITE.js";
7
+ import { ComputeShader } from "../../../../shader/ComputeShader.js";
8
+ import { GEOMETRY_METADATA_STRUCT } from "../../../GEOMETRY_METADATA_STRUCT.js";
9
+ import { chunk_mat3_singular_values } from "../../../../shader/chunk/geometry/mat3/chunk_mat3_singular_values.js";
10
+ import { chunk_mat4_inverse } from "../../../../shader/chunk/geometry/mat4/chunk_mat4_inverse.js";
11
+ import { chunk_scene_database_access } from "../../../../scene/chunk_scene_database_access.js";
12
+ import { ShaderResourceSetDescriptor } from "../../../../shader/resource/ShaderResourceSetDescriptor.js";
13
+ import { VGEO_CUT_STAT } from "../layout/VGEO_CUT_STAT.js";
14
+ import { VGEO_FEEDBACK_OFFSET } from "../layout/VGEO_FEEDBACK_OFFSET.js";
15
+ import { VGEO_GEOMETRY_ROW_NONE } from "../layout/VGEO_GEOMETRY_ROW_NONE.js";
16
+ import { VGEO_GEOMETRY_ROW_OFFSET } from "../layout/VGEO_GEOMETRY_ROW_OFFSET.js";
17
+ import { VGEO_GEOMETRY_ROW_WORDS } from "../layout/VGEO_GEOMETRY_ROW_WORDS.js";
18
+ import { VGEO_INSTANCE_OFFSET } from "../layout/VGEO_INSTANCE_OFFSET.js";
19
+ import { VGEO_INSTANCE_WORDS } from "../layout/VGEO_INSTANCE_WORDS.js";
20
+ import { VGEO_CUT_PARAMS_STRUCT } from "./VGEO_CUT_PARAMS_STRUCT.js";
21
+ import { VGEO_CUT_WORKGROUP_SIZE } from "./VGEO_CUT_WORKGROUP_SIZE.js";
22
+
23
+ /**
24
+ * Pick the virtual-geometry instances out of a list of visible meshes, and put each one into object
25
+ * space once.
26
+ *
27
+ * This is `MICRON_COMPARISON_2026_08_20.md` §2.7 as design §3.1 adopted it, and it is the only
28
+ * place the transform is touched: multiply the camera's view-projection by the instance transform,
29
+ * take the frustum out of the result, invert the transform once for the eye, and every cull and
30
+ * error test downstream runs against untransformed cluster bounds. One matrix per instance instead
31
+ * of a transform per cluster — with thousands of instances sharing one geometry, that difference is
32
+ * the entire cost.
33
+ *
34
+ * It also emits each instance's claim width, which the prefix scan turns into the base the seed
35
+ * pass writes back. The width is the geometry's **ordinal capacity** rather than its resident page
36
+ * count, because ordinals come from a free list and can be sparse; a bitmask indexed by a sparse
37
+ * ordinal has to be as wide as the highest one handed out.
38
+ *
39
+ * @author Alex Goldring
40
+ * @copyright Company Named Limited (c) 2026
41
+ */
42
+
43
+ const resources = new ShaderResourceSetDescriptor();
44
+
45
+ resources.createGroup()
46
+ .addUniform("params", VGEO_CUT_PARAMS_STRUCT)
47
+ .addUniform("camera", CAMERA_UNIFORM_STRUCT)
48
+ .addStorageBuffer("scene_database", WebGPUArray.from(u32), false)
49
+ .addStorageBuffer("geometries", WebGPUArray.from(GEOMETRY_METADATA_STRUCT), false)
50
+ .addStorageBuffer("vg_geometries", WebGPUArray.from(u32), false)
51
+ ;
52
+
53
+ resources.createGroup()
54
+ .addStorageBuffer("input_meshes", COLLECTION_U32_STRUCT_READ, false)
55
+ .addStorageBuffer("instances", WebGPUArray.from(u32), true)
56
+ .addStorageBuffer("claim_widths", COLLECTION_U32_STRUCT_WRITE, true)
57
+ // the frame's counters, so an instance this pass refuses is counted where every other drop is
58
+ .addStorageBuffer("feedback", WebGPUArray.from(atomic_u32), true)
59
+ ;
60
+
61
+ const body = CodeChunk.from(
62
+ //language=WGSL
63
+ `
64
+ const VG_GEOMETRY_ROW_NONE = ${VGEO_GEOMETRY_ROW_NONE}u;
65
+ const VG_INSTANCE_WORDS = ${VGEO_INSTANCE_WORDS}u;
66
+ const VG_GEOMETRY_ROW_WORDS = ${VGEO_GEOMETRY_ROW_WORDS}u;
67
+
68
+ fn vg_store(base: u32, field: u32, value: f32) {
69
+ instances[base + field] = bitcast<u32>(value);
70
+ }
71
+
72
+ /**
73
+ * One frustum plane out of a row combination of the object-space view-projection, normalized so a
74
+ * sphere test is a plain signed distance.
75
+ *
76
+ * Gribb-Hartmann, and the far plane is simply not extracted: the projection is infinite reverse-Z,
77
+ * so its row is degenerate and normalizing it produces nothing a test can use. Ordering near last
78
+ * is what makes the traversal's "test the first five" true by construction.
79
+ *
80
+ * **The near plane is w − z, and it was w + z here.** Under reverse-Z the near plane is the one
81
+ * clip space bounds by z <= w; w + z is the row an *infinite* projection makes degenerate, which is
82
+ * exactly the row this function then normalized into a plane the test could not use.
83
+ * Camera.construct_frustum_planes has had the sign right all along and is worth comparing against
84
+ * rather than re-deriving.
85
+ */
86
+ fn vg_store_plane(base: u32, plane: u32, row_w: vec4<f32>, row: vec4<f32>, sign: f32) {
87
+ let raw = row_w + row * sign;
88
+
89
+ let length_xyz = length(raw.xyz);
90
+
91
+ let normalized = select(raw, raw / length_xyz, length_xyz > 0.0);
92
+
93
+ let word = base + ${VGEO_INSTANCE_OFFSET.FRUSTUM}u + plane * 4u;
94
+
95
+ instances[word] = bitcast<u32>(normalized.x);
96
+ instances[word + 1u] = bitcast<u32>(normalized.y);
97
+ instances[word + 2u] = bitcast<u32>(normalized.z);
98
+ instances[word + 3u] = bitcast<u32>(normalized.w);
99
+ }
100
+
101
+ @compute @workgroup_size(${VGEO_CUT_WORKGROUP_SIZE})
102
+ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
103
+ let input_index = global_id.x;
104
+
105
+ if (input_index >= input_meshes.count) {
106
+ return;
107
+ }
108
+
109
+ let mesh_index = input_meshes.elements[input_index];
110
+
111
+ let mesh = scene_read_mesh(&scene_database, mesh_index);
112
+
113
+ let geometry_row = geometries[mesh.geometry].vg_row;
114
+
115
+ if (geometry_row == VG_GEOMETRY_ROW_NONE) {
116
+ // an ordinary mesh; the static expansion beside this pass is what draws it
117
+ return;
118
+ }
119
+
120
+ let node = scene_read_node(&scene_database, mesh.node);
121
+
122
+ let linear = mat3x3<f32>(
123
+ node.global[0].xyz, node.global[1].xyz, node.global[2].xyz
124
+ );
125
+
126
+ /*
127
+ Error and distance are both object-space, so a **uniform** scale cancels out of r_e * k / d
128
+ exactly and needs no term at all. A non-uniform one does not, and the correction is the ratio
129
+ of the largest stretch this transform applies to any direction to the smallest — which is the
130
+ ratio of its singular values, not of its column lengths. A shear has unit columns and stretches
131
+ space without bound, so column lengths report 1 and under-refine, which is the direction a
132
+ conservative correction is not allowed to fail in.
133
+ */
134
+ let stretch = mat3_singular_values(linear);
135
+
136
+ if (!(abs(determinant(linear)) > 0.0) || !(stretch.y > 0.0)) {
137
+ /*
138
+ A singular transform — an instance scaled to zero in some direction. mat4_inverse says so
139
+ by dividing by a zero determinant, and the NaN that comes back makes **every** comparison
140
+ in vg_project and the frustum test fail open, so one zero-scaled instance draws its whole
141
+ resident set. It covers no pixels, so dropping it is also the right picture.
142
+
143
+ **The determinant is the test, and sigma_min alone was not.** This guard used to be
144
+ !(sigma_min > 0) on its own, and the closed form's own doc offered sigma_min as a
145
+ degeneracy test — true in exact arithmetic, false in f32. An axis-aligned flatten makes
146
+ MtM exactly diagonal and takes the exact branch, which does return zero. A ROTATED one
147
+ takes the trigonometric branch, where sigma_min is a difference of nearly equal numbers
148
+ with an absolute error of about sqrt(eps_f32) * sigma_max — so it came back near 1e-4
149
+ rather than 0, and thirty-six of forty rotated zero-scale instances passed this line with
150
+ a NaN eye and a projection scale of 6.2e10 behind it (REVIEW_LEDGER M3, re-review
151
+ 2026-09-12). The determinant does not have that problem: a flattened instance has one
152
+ exactly-zero column at every rotation, and every term of the expansion carries a factor
153
+ from it. It is also, exactly, the number mat4_inverse divides by two lines below.
154
+
155
+ sigma_min is kept beside it because it is not redundant: a matrix that is merely very
156
+ close to singular has a non-zero determinant and can still report sigma_min as zero, and
157
+ the ratio below would then be an infinity rather than a correction.
158
+
159
+ Both written as !(x > 0) rather than x <= 0 so that a NaN — which compares false against
160
+ everything — is caught rather than passed through.
161
+ */
162
+ atomicAdd(
163
+ &feedback[${VGEO_FEEDBACK_OFFSET.STATS}u + ${VGEO_CUT_STAT.INSTANCES_DROPPED}u], 1u
164
+ );
165
+
166
+ return;
167
+ }
168
+
169
+ let slot = atomicAdd(&claim_widths.count, 1u);
170
+
171
+ if (slot >= params.instance_capacity) {
172
+ /*
173
+ Bounded like every other append in the cut. As the seam is wired this cannot fire — one
174
+ instance record per element of input_meshes, and both collections are sized from the same
175
+ limit — but the invariant lives a call away and the buffer is created here, so the check
176
+ belongs here too. Dropping the instance is the safe direction: a cut run without a claim
177
+ slice draws every page once per parent that reaches it.
178
+ */
179
+ atomicAdd(
180
+ &feedback[${VGEO_FEEDBACK_OFFSET.STATS}u + ${VGEO_CUT_STAT.INSTANCES_DROPPED}u], 1u
181
+ );
182
+
183
+ return;
184
+ }
185
+
186
+ let base = slot * VG_INSTANCE_WORDS;
187
+
188
+ let to_object = mat4_inverse(node.global);
189
+
190
+ // the camera's position in this instance's object space, out of the camera's own world transform
191
+ let eye = to_object * vec4<f32>(camera.transform[3].xyz, 1.0);
192
+
193
+ vg_store(base, ${VGEO_INSTANCE_OFFSET.EYE}u, eye.x / eye.w);
194
+ vg_store(base, ${VGEO_INSTANCE_OFFSET.EYE + 1}u, eye.y / eye.w);
195
+ vg_store(base, ${VGEO_INSTANCE_OFFSET.EYE + 2}u, eye.z / eye.w);
196
+
197
+ vg_store(
198
+ base, ${VGEO_INSTANCE_OFFSET.PROJECTION_K}u,
199
+ params.projection_k * (stretch.x / stretch.y)
200
+ );
201
+
202
+ // one matrix multiply, and every plane below comes out of it
203
+ let object_view_projection = camera.view_projection_matrix * node.global;
204
+
205
+ // WGSL matrices are column-major, so a row of the matrix is a component across its columns
206
+ let row_x = vec4<f32>(
207
+ object_view_projection[0].x, object_view_projection[1].x,
208
+ object_view_projection[2].x, object_view_projection[3].x
209
+ );
210
+ let row_y = vec4<f32>(
211
+ object_view_projection[0].y, object_view_projection[1].y,
212
+ object_view_projection[2].y, object_view_projection[3].y
213
+ );
214
+ let row_z = vec4<f32>(
215
+ object_view_projection[0].z, object_view_projection[1].z,
216
+ object_view_projection[2].z, object_view_projection[3].z
217
+ );
218
+ let row_w = vec4<f32>(
219
+ object_view_projection[0].w, object_view_projection[1].w,
220
+ object_view_projection[2].w, object_view_projection[3].w
221
+ );
222
+
223
+ vg_store_plane(base, 0u, row_w, row_x, 1.0);
224
+ vg_store_plane(base, 1u, row_w, row_x, -1.0);
225
+ vg_store_plane(base, 2u, row_w, row_y, 1.0);
226
+ vg_store_plane(base, 3u, row_w, row_y, -1.0);
227
+ vg_store_plane(base, 4u, row_w, row_z, -1.0);
228
+
229
+ let geometry_base = geometry_row * VG_GEOMETRY_ROW_WORDS;
230
+
231
+ let ordinal_capacity = vg_geometries[
232
+ geometry_base + ${VGEO_GEOMETRY_ROW_OFFSET.ORDINAL_CAPACITY}u
233
+ ];
234
+
235
+ instances[base + ${VGEO_INSTANCE_OFFSET.MESH_INDEX}u] = mesh_index;
236
+ instances[base + ${VGEO_INSTANCE_OFFSET.ROOT_PAGE_ROW}u] =
237
+ vg_geometries[geometry_base + ${VGEO_GEOMETRY_ROW_OFFSET.ROOT_PAGE_ROW}u];
238
+ instances[base + ${VGEO_INSTANCE_OFFSET.LOOKUP_WORD_OFFSET}u] =
239
+ vg_geometries[geometry_base + ${VGEO_GEOMETRY_ROW_OFFSET.LOOKUP_WORD_OFFSET}u];
240
+ instances[base + ${VGEO_INSTANCE_OFFSET.ORDINAL_CAPACITY}u] = ordinal_capacity;
241
+ instances[base + ${VGEO_INSTANCE_OFFSET.CLAIM_BASE}u] = 0u;
242
+
243
+ claim_widths.elements[slot] = ordinal_capacity;
244
+ }
245
+ `, [
246
+ chunk_scene_database_access,
247
+ chunk_mat3_singular_values,
248
+ chunk_mat4_inverse,
249
+ ]);
250
+
251
+ export const shader_vgeo_cut_collect = ComputeShader.from({
252
+ label: "VGeo cut collect instances",
253
+ body,
254
+ resources,
255
+ });
@@ -0,0 +1,3 @@
1
+ export const shader_vgeo_cut_queue_prepare: ComputeShader;
2
+ import { ComputeShader } from "../../../../shader/ComputeShader.js";
3
+ //# sourceMappingURL=shader_vgeo_cut_queue_prepare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_vgeo_cut_queue_prepare.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js"],"names":[],"mappings":"AA2EA,0DAIG;8BA3E2B,qCAAqC"}
@@ -0,0 +1,80 @@
1
+ import { atomic_u32 } from "../../../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
2
+ import { WebGPUArray } from "../../../../shader/type/WebGPUArray.js";
3
+ import { CodeChunk } from "../../../../shader/compiler/CodeChunk.js";
4
+ import { COLLECTION_U32_STRUCT_WRITE } from "../../../../gpu_primitive/COLLECTION_U32_STRUCT_WRITE.js";
5
+ import { ComputeShader } from "../../../../shader/ComputeShader.js";
6
+ import {
7
+ STRUCT_DISPATCH_COMPUTE_COMMAND
8
+ } from "../../../../gpu_primitive/indirect/STRUCT_DISPATCH_COMPUTE_COMMAND.js";
9
+ import { ShaderResourceSetDescriptor } from "../../../../shader/resource/ShaderResourceSetDescriptor.js";
10
+ import { chunk_divide_round_up_u32 } from "../../../../shader/chunk/math/chunk_divide_round_up_u32.js";
11
+ import { VGEO_CUT_STAT } from "../layout/VGEO_CUT_STAT.js";
12
+ import { VGEO_FEEDBACK_OFFSET } from "../layout/VGEO_FEEDBACK_OFFSET.js";
13
+ import { VGEO_CUT_PARAMS_STRUCT } from "./VGEO_CUT_PARAMS_STRUCT.js";
14
+ import { VGEO_CUT_WORKGROUP_SIZE } from "./VGEO_CUT_WORKGROUP_SIZE.js";
15
+
16
+ /**
17
+ * Between two wavefronts: clamp what the last one produced, turn it into a dispatch, and empty the
18
+ * queue the next one will write.
19
+ *
20
+ * The clamp is the load-bearing half. A wavefront reserves its output slots with `atomicAdd` and
21
+ * bounds-checks each write, so an overflowing iteration writes what fits and counts the rest — but
22
+ * the count itself runs past capacity, and handing *that* to an indirect dispatch would dispatch
23
+ * lanes over the end of a pooled buffer. Clamping here is what keeps the overflow a lost subtree
24
+ * rather than a read of somebody else's transient.
25
+ *
26
+ * Zeroing the *other* queue is here for the same reason it is here at all: the two ping-pong, so
27
+ * the buffer this iteration reads is the one the next iteration writes, and there is exactly one
28
+ * moment when neither pass is touching it.
29
+ *
30
+ * @author Alex Goldring
31
+ * @copyright Company Named Limited (c) 2026
32
+ */
33
+
34
+ const resources = new ShaderResourceSetDescriptor();
35
+
36
+ resources.createGroup()
37
+ .addUniform("params", VGEO_CUT_PARAMS_STRUCT)
38
+ // what the wavefront just produced, and what the next one consumes
39
+ .addStorageBuffer("queue_ready", COLLECTION_U32_STRUCT_WRITE, true)
40
+ // what the next wavefront will produce into
41
+ .addStorageBuffer("queue_spare", COLLECTION_U32_STRUCT_WRITE, true)
42
+ .addStorageBuffer("command", STRUCT_DISPATCH_COMPUTE_COMMAND, true)
43
+ // the frame's counters: this is the only pass that can see how deep the descent went
44
+ .addStorageBuffer("feedback", WebGPUArray.from(atomic_u32), true)
45
+ ;
46
+
47
+ const body = CodeChunk.from(
48
+ //language=WGSL
49
+ `
50
+ @compute @workgroup_size(1)
51
+ fn main() {
52
+ let produced = atomicLoad(&queue_ready.count);
53
+
54
+ let count = min(produced, params.queue_capacity);
55
+
56
+ atomicStore(&queue_ready.count, count);
57
+ atomicStore(&queue_spare.count, 0u);
58
+
59
+ /*
60
+ What was outstanding when this pass ran. A plain store rather than an add, so the last prepare
61
+ of the frame is the one that is read — and the seam records one extra prepare after the
62
+ wavefront loop, whose whole purpose is to leave this number behind. A descent that stops with
63
+ work still queued is the one degradation that costs a hole rather than coarseness, and until
64
+ now nothing anywhere counted it (REVIEW_LEDGER M8).
65
+ */
66
+ atomicStore(&feedback[${VGEO_FEEDBACK_OFFSET.STATS}u + ${VGEO_CUT_STAT.QUEUE_REMAINING}u], count);
67
+
68
+ command.workgroupCountX = divide_round_up_u32(count, ${VGEO_CUT_WORKGROUP_SIZE}u);
69
+ command.workgroupCountY = 1u;
70
+ command.workgroupCountZ = 1u;
71
+ }
72
+ `, [
73
+ chunk_divide_round_up_u32,
74
+ ]);
75
+
76
+ export const shader_vgeo_cut_queue_prepare = ComputeShader.from({
77
+ label: "VGeo cut queue prepare",
78
+ body,
79
+ resources,
80
+ });
@@ -0,0 +1,3 @@
1
+ export const shader_vgeo_cut_seed: ComputeShader;
2
+ import { ComputeShader } from "../../../../shader/ComputeShader.js";
3
+ //# sourceMappingURL=shader_vgeo_cut_seed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_vgeo_cut_seed.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js"],"names":[],"mappings":"AA2IA,iDAIG;8BA1I2B,qCAAqC"}
@@ -0,0 +1,144 @@
1
+ import { atomic_u32, u32 } from "../../../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
2
+ import { WebGPUArray } from "../../../../shader/type/WebGPUArray.js";
3
+ import { CodeChunk } from "../../../../shader/compiler/CodeChunk.js";
4
+ import { COLLECTION_U32_STRUCT_READ } from "../../../../gpu_primitive/COLLECTION_U32_STRUCT_READ.js";
5
+ import { COLLECTION_U32_STRUCT_WRITE } from "../../../../gpu_primitive/COLLECTION_U32_STRUCT_WRITE.js";
6
+ import { ComputeShader } from "../../../../shader/ComputeShader.js";
7
+ import { ShaderResourceSetDescriptor } from "../../../../shader/resource/ShaderResourceSetDescriptor.js";
8
+ import { VGEO_CUT_STAT } from "../layout/VGEO_CUT_STAT.js";
9
+ import { VGEO_FEEDBACK_OFFSET } from "../layout/VGEO_FEEDBACK_OFFSET.js";
10
+ import { VGEO_INSTANCE_OFFSET } from "../layout/VGEO_INSTANCE_OFFSET.js";
11
+ import { VGEO_INSTANCE_WORDS } from "../layout/VGEO_INSTANCE_WORDS.js";
12
+ import { VGEO_PAGE_ROW_NONE } from "../layout/VGEO_PAGE_ROW_NONE.js";
13
+ import { VGEO_PAGE_ROW_OFFSET } from "../layout/VGEO_PAGE_ROW_OFFSET.js";
14
+ import { VGEO_CUT_PARAMS_STRUCT } from "./VGEO_CUT_PARAMS_STRUCT.js";
15
+ import { VGEO_CUT_WORKGROUP_SIZE } from "./VGEO_CUT_WORKGROUP_SIZE.js";
16
+
17
+ /**
18
+ * Seed the wavefront: one item per visible VG instance, naming its root page's node 0.
19
+ *
20
+ * This is also where each instance learns where its slice of the claim bitmask starts, out of the
21
+ * prefix scan over instance ordinal capacities — the same scan shape `graph_expand_meshes_to_meshlets`
22
+ * runs to size its meshlet output, for the same reason.
23
+ *
24
+ * **An instance whose slice does not fit is refused**, and that direction is not arbitrary. A cut
25
+ * run without a claim visits every page once per parent page that reaches it and emits its whole
26
+ * cut that many times over; the failure reads as corrupt geometry rather than as a missing
27
+ * instance, and a missing instance is the one a human can see and attribute.
28
+ *
29
+ * @author Alex Goldring
30
+ * @copyright Company Named Limited (c) 2026
31
+ */
32
+
33
+ const resources = new ShaderResourceSetDescriptor();
34
+
35
+ resources.createGroup()
36
+ .addUniform("params", VGEO_CUT_PARAMS_STRUCT)
37
+ // the page slots; this pass reads one header field out of one of them
38
+ .addStorageBuffer("vg_arena", WebGPUArray.from(u32), false)
39
+ .addStorageBuffer("prefix_sums", COLLECTION_U32_STRUCT_READ, false)
40
+ ;
41
+
42
+ resources.createGroup()
43
+ .addStorageBuffer("instances", WebGPUArray.from(u32), true)
44
+ .addStorageBuffer("queue_out", COLLECTION_U32_STRUCT_WRITE, true)
45
+ .addStorageBuffer("claim", WebGPUArray.from(atomic_u32), true)
46
+ .addStorageBuffer("feedback", WebGPUArray.from(atomic_u32), true)
47
+ ;
48
+
49
+ const body = CodeChunk.from(
50
+ //language=WGSL
51
+ `
52
+ @compute @workgroup_size(${VGEO_CUT_WORKGROUP_SIZE})
53
+ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
54
+ let instance_slot = global_id.x;
55
+
56
+ if (instance_slot >= prefix_sums.count) {
57
+ return;
58
+ }
59
+
60
+ let instance_base = instance_slot * ${VGEO_INSTANCE_WORDS}u;
61
+
62
+ // inclusive scan: this instance's base is the total below it
63
+ var claim_base = 0u;
64
+
65
+ if (instance_slot > 0u) {
66
+ claim_base = prefix_sums.elements[instance_slot - 1u];
67
+ }
68
+
69
+ let capacity = instances[instance_base + ${VGEO_INSTANCE_OFFSET.ORDINAL_CAPACITY}u];
70
+
71
+ if ((claim_base + capacity + 31u) >> 5u > params.claim_word_count) {
72
+ atomicAdd(
73
+ &feedback[${VGEO_FEEDBACK_OFFSET.STATS}u + ${VGEO_CUT_STAT.INSTANCES_DROPPED}u], 1u
74
+ );
75
+
76
+ // left with a capacity of zero, so nothing downstream can claim on its behalf either
77
+ instances[instance_base + ${VGEO_INSTANCE_OFFSET.ORDINAL_CAPACITY}u] = 0u;
78
+
79
+ return;
80
+ }
81
+
82
+ instances[instance_base + ${VGEO_INSTANCE_OFFSET.CLAIM_BASE}u] = claim_base;
83
+
84
+ let page_row = instances[instance_base + ${VGEO_INSTANCE_OFFSET.ROOT_PAGE_ROW}u];
85
+
86
+ /*
87
+ A geometry whose root page is not resident draws nothing, and saying so here is one compare.
88
+ The host refuses to register such a geometry at all, but it used to say so through
89
+ \`assert.notEqual\`, and this engine ships with \`assert.*\` stripped — so in a shipped build the
90
+ sentinel reached this line, was multiplied by the slot stride as a u32, and wrapped into a live
91
+ word of the feedback buffer (REVIEW_LEDGER C7). A guard the build cannot remove costs less than
92
+ the failure it prevents is worth diagnosing.
93
+ */
94
+ if (page_row == ${VGEO_PAGE_ROW_NONE}u) {
95
+ return;
96
+ }
97
+
98
+ /*
99
+ The root page is pinned, so this claim always wins — but it is taken rather than assumed,
100
+ because it is also what stamps the root page as touched, and a root that never reports a touch
101
+ is a root that ages out of the touch-LRU while it is on screen.
102
+ */
103
+ let ordinal = vg_arena[
104
+ page_row * params.page_slot_words + ${VGEO_PAGE_ROW_OFFSET.ORDINAL}u
105
+ ];
106
+
107
+ let bit = claim_base + ordinal;
108
+
109
+ atomicOr(&claim[bit >> 5u], 1u << (bit & 31u));
110
+
111
+ atomicAdd(&feedback[${VGEO_FEEDBACK_OFFSET.STATS}u + ${VGEO_CUT_STAT.PAGES}u], 1u);
112
+
113
+ if (atomicExchange(&feedback[params.touch_stamp_base + page_row], 1u) == 0u) {
114
+ let touch_slot = atomicAdd(&feedback[${VGEO_FEEDBACK_OFFSET.TOUCH_COUNT}u], 1u);
115
+
116
+ if (touch_slot < params.touch_capacity) {
117
+ atomicStore(&feedback[params.touch_base + touch_slot], page_row);
118
+ }
119
+ }
120
+
121
+ let slot = atomicAdd(&queue_out.count, 1u);
122
+
123
+ if (slot >= params.queue_capacity) {
124
+ atomicAdd(
125
+ &feedback[${VGEO_FEEDBACK_OFFSET.STATS}u + ${VGEO_CUT_STAT.QUEUE_DROPPED}u], 1u
126
+ );
127
+
128
+ return;
129
+ }
130
+
131
+ let base = slot * 4u;
132
+
133
+ queue_out.elements[base] = instance_slot;
134
+ queue_out.elements[base + 1u] = page_row;
135
+ queue_out.elements[base + 2u] = 0u;
136
+ queue_out.elements[base + 3u] = 0u;
137
+ }
138
+ `, []);
139
+
140
+ export const shader_vgeo_cut_seed = ComputeShader.from({
141
+ label: "VGeo cut seed",
142
+ body,
143
+ resources,
144
+ });
@@ -0,0 +1,3 @@
1
+ export const shader_vgeo_cut_traverse: ComputeShader;
2
+ import { ComputeShader } from "../../../../shader/ComputeShader.js";
3
+ //# sourceMappingURL=shader_vgeo_cut_traverse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_vgeo_cut_traverse.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js"],"names":[],"mappings":"AA6gBA,qDAIG;8BA9gB2B,qCAAqC"}