@woosh/meep-engine 3.56.0 → 3.58.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 (1920) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/editor/ecs/component/editors/ColorEditor.js +2 -2
  3. package/editor/particles/effect/ParticleEffectDocument.d.ts.map +1 -1
  4. package/editor/particles/effect/ParticleEffectDocument.js +2 -5
  5. package/editor/tools/GridPaintTool.js +2 -2
  6. package/editor/view/node-graph/NodeGraphEditorView.d.ts +1 -1
  7. package/editor/view/node-graph/NodeGraphEditorView.d.ts.map +1 -1
  8. package/editor/view/node-graph/NodeGraphEditorView.js +2 -2
  9. package/editor/view/node-graph/NodeGraphView.d.ts +0 -1
  10. package/editor/view/node-graph/NodeGraphView.d.ts.map +1 -1
  11. package/editor/view/node-graph/NodeGraphView.js +0 -2
  12. package/package.json +1 -1
  13. package/src/DUPLICATION_REVIEW_2026_10_24.md +1072 -0
  14. package/src/core/binary/BitSet.js +1 -1
  15. package/src/core/binary/FLOAT16_MAX.d.ts +2 -0
  16. package/src/core/binary/FLOAT16_MAX.d.ts.map +1 -0
  17. package/src/core/binary/FLOAT16_MAX.js +1 -0
  18. package/src/core/binary/base58/base58_encode.js +2 -2
  19. package/src/core/binary/type/TypeBuilder.js +1 -1
  20. package/src/core/bvh2/bvh3/BVH.js +1 -1
  21. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.d.ts.map +1 -1
  22. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.js +7 -3
  23. package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.d.ts.map +1 -1
  24. package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.js +5 -1
  25. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.d.ts.map +1 -1
  26. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +195 -246
  27. package/src/core/bvh8/build/NodeProxy.js +2 -2
  28. package/src/core/bvh8/build/aabb3_compute_merge_cost.js +4 -4
  29. package/src/core/bvh8/build/bvh8_build_for_geometry.js +2 -2
  30. package/src/core/collection/CuckooFilter.js +1 -1
  31. package/src/core/collection/array/isArrayEqual.d.ts.map +1 -1
  32. package/src/core/collection/array/isArrayEqual.js +33 -58
  33. package/src/core/collection/array/typed/array_buffer_hash.d.ts.map +1 -1
  34. package/src/core/collection/array/typed/array_buffer_hash.js +41 -39
  35. package/src/core/collection/array/typed/float32_array_hash.js +38 -38
  36. package/src/core/collection/array/typed/uint16_array_hash.d.ts +2 -1
  37. package/src/core/collection/array/typed/uint16_array_hash.d.ts.map +1 -1
  38. package/src/core/collection/array/typed/uint16_array_hash.js +30 -29
  39. package/src/core/collection/array/typed/uint32_array_hash.d.ts +2 -1
  40. package/src/core/collection/array/typed/uint32_array_hash.d.ts.map +1 -1
  41. package/src/core/collection/array/typed/uint32_array_hash.js +21 -20
  42. package/src/core/collection/array/typed/uint8_array_hash.d.ts +2 -1
  43. package/src/core/collection/array/typed/uint8_array_hash.d.ts.map +1 -1
  44. package/src/core/collection/array/typed/uint8_array_hash.js +37 -36
  45. package/src/core/collection/array/typed/uint_array_for_count.js +2 -2
  46. package/src/core/collection/list/List.d.ts.map +1 -1
  47. package/src/core/collection/list/List.js +3 -19
  48. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  49. package/src/core/collection/table/RowFirstTable.js +4 -28
  50. package/src/core/debug/matchers/DescribeAs.d.ts.map +1 -1
  51. package/src/core/debug/matchers/DescribeAs.js +62 -64
  52. package/src/core/function/FunctionCompiler.js +4 -4
  53. package/src/core/function/objectsEqual.d.ts.map +1 -1
  54. package/src/core/function/objectsEqual.js +3 -2
  55. package/src/core/geom/2d/bvh/BVH2D.d.ts.map +1 -1
  56. package/src/core/geom/2d/bvh/BVH2D.js +4 -3
  57. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts +5 -2
  58. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts.map +1 -1
  59. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js +49 -11
  60. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.d.ts.map +1 -1
  61. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.js +122 -159
  62. package/src/core/geom/2d/hash-grid/shg_query_elements_line.d.ts.map +1 -1
  63. package/src/core/geom/2d/hash-grid/shg_query_elements_line.js +8 -5
  64. package/src/core/geom/2d/line/line2_segment_intersection_fraction_2d.d.ts +1 -1
  65. package/src/core/geom/2d/line/line2_segment_intersection_fraction_2d.js +1 -1
  66. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts +18 -0
  67. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts.map +1 -0
  68. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.js +97 -0
  69. package/src/core/geom/2d/r-tree/StaticR2Tree.js +2 -2
  70. package/src/core/geom/2d/triangle/tri2_intersects_aabb2.d.ts +17 -0
  71. package/src/core/geom/2d/triangle/tri2_intersects_aabb2.d.ts.map +1 -0
  72. package/src/core/geom/2d/triangle/tri2_intersects_aabb2.js +64 -0
  73. package/src/core/geom/2d/triangle/tri2_rasterize_barycentric.d.ts +23 -0
  74. package/src/core/geom/2d/triangle/tri2_rasterize_barycentric.d.ts.map +1 -0
  75. package/src/core/geom/2d/triangle/tri2_rasterize_barycentric.js +81 -0
  76. package/src/core/geom/2d/triangle/tri2_rasterize_conservative.d.ts.map +1 -1
  77. package/src/core/geom/2d/triangle/tri2_rasterize_conservative.js +36 -99
  78. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts +21 -0
  79. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts.map +1 -0
  80. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.js +54 -0
  81. package/src/core/geom/3d/aabb/aabb3_build_frustum.d.ts +0 -11
  82. package/src/core/geom/3d/aabb/aabb3_build_frustum.d.ts.map +1 -1
  83. package/src/core/geom/3d/aabb/aabb3_build_frustum.js +3 -41
  84. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts +1 -1
  85. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts.map +1 -1
  86. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.js +11 -42
  87. package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts.map +1 -1
  88. package/src/core/geom/3d/atlas/pack/atlas_pack_charts.js +30 -32
  89. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts.map +1 -1
  90. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.js +1 -5
  91. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts.map +1 -1
  92. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js +1 -15
  93. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts.map +1 -1
  94. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +105 -116
  95. package/src/core/geom/3d/box/box3_raycast.d.ts +1 -1
  96. package/src/core/geom/3d/box/box3_raycast.js +1 -1
  97. package/src/core/geom/3d/line/line3_compute_segment_closest_point_to_aabb3_t.d.ts +1 -1
  98. package/src/core/geom/3d/line/line3_compute_segment_closest_point_to_aabb3_t.js +1 -1
  99. package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.d.ts.map +1 -1
  100. package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.js +36 -54
  101. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts +5 -10
  102. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts.map +1 -1
  103. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.js +20 -82
  104. package/src/core/geom/3d/plane/plane3_slerp.d.ts.map +1 -1
  105. package/src/core/geom/3d/plane/plane3_slerp.js +87 -102
  106. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts +12 -0
  107. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts.map +1 -1
  108. package/src/core/geom/3d/polygon/polygon3_compute_normal.js +107 -60
  109. package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts +3 -3
  110. package/src/core/geom/3d/quaternion/quat3_to_matrix3.js +3 -3
  111. package/src/core/geom/3d/ray/ray3_compute_closest_point.d.ts.map +1 -1
  112. package/src/core/geom/3d/ray/ray3_compute_closest_point.js +37 -43
  113. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
  114. package/src/core/geom/3d/shape/ConvexHullShape3D.js +5 -16
  115. package/src/core/geom/3d/shape/HeightMapShape3D.js +2 -2
  116. package/src/core/geom/3d/shape/MeshShape3D.d.ts +2 -2
  117. package/src/core/geom/3d/shape/MeshShape3D.js +4 -58
  118. package/src/core/geom/3d/shape/PosedShape3D.js +2 -2
  119. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  120. package/src/core/geom/3d/shape/TransformedShape3D.js +10 -7
  121. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  122. package/src/core/geom/3d/shape/UnionShape3D.js +9 -3
  123. package/src/core/geom/3d/shape/json/shape_to_type.js +2 -2
  124. package/src/core/geom/3d/sphere/harmonics/SH3_COEFFICIENTS.js +17 -17
  125. package/src/core/geom/3d/sphere/sphere_matrix4_transform.d.ts +0 -7
  126. package/src/core/geom/3d/sphere/sphere_matrix4_transform.d.ts.map +1 -1
  127. package/src/core/geom/3d/sphere/sphere_matrix4_transform.js +0 -4
  128. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.d.ts.map +1 -1
  129. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.js +6 -2
  130. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts.map +1 -1
  131. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +3 -2
  132. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_compute_tet_quality.d.ts +1 -1
  133. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_compute_tet_quality.js +1 -1
  134. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.d.ts +1 -1
  135. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.js +1 -1
  136. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts +20 -2
  137. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts.map +1 -1
  138. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +52 -37
  139. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts.map +1 -1
  140. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +40 -56
  141. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
  142. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +251 -260
  143. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts.map +1 -1
  144. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.js +104 -113
  145. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple.d.ts +1 -1
  146. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple.js +1 -1
  147. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.d.ts.map +1 -1
  148. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.js +227 -238
  149. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  150. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +15 -24
  151. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.d.ts.map +1 -1
  152. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +31 -115
  153. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.d.ts +1 -1
  154. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.js +1 -1
  155. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.d.ts +2 -2
  156. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.js +2 -2
  157. package/src/core/geom/3d/topology/struct/binary/io/face/bt_face_poke.d.ts +0 -14
  158. package/src/core/geom/3d/topology/struct/binary/io/face/bt_face_poke.d.ts.map +1 -1
  159. package/src/core/geom/3d/topology/struct/binary/io/face/bt_face_poke.js +0 -5
  160. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.d.ts.map +1 -1
  161. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.js +142 -150
  162. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
  163. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +3 -46
  164. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.js +1 -1
  165. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.d.ts.map +1 -1
  166. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.js +60 -85
  167. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_vertex_adjacent_faces.d.ts +1 -1
  168. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_vertex_adjacent_faces.js +1 -1
  169. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.d.ts.map +1 -1
  170. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.js +156 -171
  171. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.d.ts.map +1 -1
  172. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.js +1 -2
  173. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.d.ts.map +1 -1
  174. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.js +8 -44
  175. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
  176. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +2 -7
  177. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts.map +1 -1
  178. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +3 -2
  179. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.d.ts.map +1 -1
  180. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.js +128 -133
  181. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts +0 -14
  182. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts.map +1 -1
  183. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.js +0 -57
  184. package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
  185. package/src/core/geom/3d/triangle/tri3_ray_intersection.js +7 -144
  186. package/src/core/geom/ConicRay.d.ts.map +1 -1
  187. package/src/core/geom/ConicRay.js +230 -237
  188. package/src/core/geom/clipmap/ClipmapCascadePlacement.d.ts +137 -0
  189. package/src/core/geom/clipmap/ClipmapCascadePlacement.d.ts.map +1 -0
  190. package/src/core/geom/clipmap/ClipmapCascadePlacement.js +350 -0
  191. package/src/core/geom/polyline/polyline_simplify_by_error.d.ts +16 -0
  192. package/src/core/geom/polyline/polyline_simplify_by_error.d.ts.map +1 -0
  193. package/src/core/geom/polyline/polyline_simplify_by_error.js +52 -0
  194. package/src/core/geom/vec3/v3_quaternion_apply.d.ts +1 -1
  195. package/src/core/geom/vec3/v3_quaternion_apply.js +1 -1
  196. package/src/core/geom/vec3/v3_quaternion_apply_inverse.d.ts +2 -2
  197. package/src/core/geom/vec3/v3_quaternion_apply_inverse.js +2 -2
  198. package/src/core/geom/vec3/v3_triple_cross.d.ts +1 -1
  199. package/src/core/geom/vec3/v3_triple_cross.js +1 -1
  200. package/src/core/localization/LocaleDataset.d.ts +6 -0
  201. package/src/core/localization/LocaleDataset.d.ts.map +1 -1
  202. package/src/core/localization/LocaleDataset.js +48 -37
  203. package/src/core/localization/LocalizationEngine.d.ts.map +1 -1
  204. package/src/core/localization/LocalizationEngine.js +3 -2
  205. package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
  206. package/src/core/math/lookup/ParameterLookupTable.js +3 -1
  207. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts.map +1 -1
  208. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.js +330 -400
  209. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts +16 -0
  210. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts.map +1 -1
  211. package/src/core/math/spline/spline3_hermite_nearest_point.js +134 -167
  212. package/src/core/model/DebouncedObservedBoolean.d.ts +1 -2
  213. package/src/core/model/DebouncedObservedBoolean.d.ts.map +1 -1
  214. package/src/core/model/DebouncedObservedBoolean.js +1 -1
  215. package/src/core/model/node-graph/node/NodeInstance.d.ts.map +1 -1
  216. package/src/core/model/node-graph/node/NodeInstance.js +2 -7
  217. package/src/core/model/node-graph/node/parameter/NodeParameterDescription.js +1 -1
  218. package/src/core/model/object/write_property.js +1 -1
  219. package/src/core/model/reactive/evaluation/MultiPredicateEvaluator.js +2 -2
  220. package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
  221. package/src/core/process/executor/ConcurrentExecutor.js +14 -2
  222. package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts +6 -3
  223. package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts.map +1 -1
  224. package/src/engine/achievements/gateway/StorageAchievementGateway.js +31 -75
  225. package/src/engine/asset/loaders/SVGAssetLoader.d.ts.map +1 -1
  226. package/src/engine/asset/loaders/SVGAssetLoader.js +33 -31
  227. package/src/engine/asset/preloader/AssetPreloader.d.ts +0 -5
  228. package/src/engine/asset/preloader/AssetPreloader.d.ts.map +1 -1
  229. package/src/engine/asset/preloader/AssetPreloader.js +0 -6
  230. package/src/engine/control/first-person/math/criticallyDampedSpring.d.ts.map +1 -1
  231. package/src/engine/control/first-person/math/criticallyDampedSpring.js +3 -14
  232. package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
  233. package/src/engine/ecs/EntityComponentDataset.js +4 -1
  234. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts +0 -2
  235. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts.map +1 -1
  236. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.js +3 -3
  237. package/src/engine/ecs/terrain/ecs/layers/TerrainLayer.js +2 -2
  238. package/src/engine/ecs/terrain/tiles/TerrainTile.d.ts.map +1 -1
  239. package/src/engine/ecs/terrain/tiles/TerrainTile.js +25 -12
  240. package/src/engine/graphics/ecs/decal/v2/Decal.d.ts +2 -2
  241. package/src/engine/graphics/ecs/decal/v2/Decal.js +2 -2
  242. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts.map +1 -1
  243. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +420 -418
  244. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.d.ts +1 -0
  245. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +10 -0
  246. package/src/engine/graphics/ecs/particles/ParticleEffect.js +3 -3
  247. package/src/engine/graphics/ecs/path/tube/build/makeTubeStream.js +2 -2
  248. package/src/engine/graphics/geometry/buffered/build_height_field_geometry.d.ts +12 -0
  249. package/src/engine/graphics/geometry/buffered/build_height_field_geometry.d.ts.map +1 -1
  250. package/src/engine/graphics/geometry/buffered/build_height_field_geometry.js +29 -2
  251. package/src/engine/graphics/sh3/path_tracer/geometry/sort_triangles_by_distance_to_point.js +1 -1
  252. package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.js +1 -1
  253. package/src/engine/graphics/texture/sprite/prototypeSpriteCutoutGeometry.js +1 -1
  254. package/src/engine/graphics3/ShadedGeometrySystem.d.ts +2 -1
  255. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  256. package/src/engine/graphics3/ShadedGeometrySystem.js +7 -5
  257. package/src/engine/graphics3/Trail3DSystem.d.ts +1 -1
  258. package/src/engine/graphics3/Trail3DSystem.js +1 -1
  259. package/src/engine/graphics3/WaterSystem.d.ts +60 -0
  260. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  261. package/src/engine/graphics3/WaterSystem.js +734 -300
  262. package/src/engine/graphics3/make_default_environment.d.ts.map +1 -1
  263. package/src/engine/graphics3/make_default_environment.js +2 -4
  264. package/src/engine/graphics3/prefab/prefab_place.js +1 -1
  265. package/src/engine/graphics3/prefab/prefab_skin_frame.d.ts.map +1 -1
  266. package/src/engine/graphics3/prefab/prefab_skin_frame.js +1 -12
  267. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts +1 -1
  268. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
  269. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +141 -137
  270. package/src/engine/input/ecs/systems/InputControllerSystem.d.ts.map +1 -1
  271. package/src/engine/input/ecs/systems/InputControllerSystem.js +13 -3
  272. package/src/engine/input/ecs/systems/InputSystem.d.ts.map +1 -1
  273. package/src/engine/input/ecs/systems/InputSystem.js +2 -1
  274. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts +1 -1
  275. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts.map +1 -1
  276. package/src/engine/intelligence/behavior/composite/ParallelBehavior.js +4 -1
  277. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.d.ts.map +1 -1
  278. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.js +3 -1
  279. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.d.ts.map +1 -1
  280. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.js +3 -1
  281. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.d.ts.map +1 -1
  282. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.js +39 -33
  283. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts +5 -0
  284. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts.map +1 -1
  285. package/src/engine/intelligence/behavior/util/ConditionalBehavior.js +93 -75
  286. package/src/engine/intelligence/behavior/util/RotationBehavior.d.ts.map +1 -1
  287. package/src/engine/intelligence/behavior/util/RotationBehavior.js +79 -76
  288. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts +1 -0
  289. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts.map +1 -1
  290. package/src/engine/intelligence/blackboard/BlackboardStack.js +159 -123
  291. package/src/engine/intelligence/mcts/StateNode.d.ts.map +1 -1
  292. package/src/engine/intelligence/mcts/StateNode.js +366 -364
  293. package/src/engine/intelligence/resource/ResourceAllocationSolver.js +1 -1
  294. package/src/engine/navigation/ecs/components/Path.d.ts.map +1 -1
  295. package/src/engine/navigation/ecs/components/Path.js +2 -1
  296. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
  297. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +5 -2
  298. package/src/engine/navigation/mesh/build/clip_soup_against_overhangs.js +628 -628
  299. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
  300. package/src/engine/physics/body/SolverBodyState.js +2 -6
  301. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  302. package/src/engine/physics/ccd/linear_sweep.js +3 -16
  303. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  304. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +2 -16
  305. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +13 -1
  306. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  307. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +15 -4
  308. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  309. package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
  310. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  311. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts +12 -0
  312. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts.map +1 -0
  313. package/src/engine/physics/inertia/locked_inverse_inertia.js +22 -0
  314. package/src/engine/physics/inertia/world_inverse_inertia.js +1 -1
  315. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
  316. package/src/engine/physics/integration/integrate_velocity.js +3 -18
  317. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts +1 -0
  318. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
  319. package/src/engine/physics/mls-mpm/MLS_MPM.js +5 -4
  320. package/src/engine/physics/narrowphase/convex_decomposition.d.ts.map +1 -1
  321. package/src/engine/physics/narrowphase/convex_decomposition.js +7 -16
  322. package/src/engine/physics/narrowphase/narrowphase_step.js +1 -1
  323. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  324. package/src/engine/physics/vehicle/RaycastVehicle.js +15 -5
  325. package/src/engine/save/StorageBackedList.d.ts +5 -0
  326. package/src/engine/save/StorageBackedList.d.ts.map +1 -1
  327. package/src/engine/save/StorageBackedList.js +161 -144
  328. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  329. package/src/engine/simulation/Ticker.js +394 -391
  330. package/src/engine/sound/simulation/probe/AcousticProbeField.d.ts.map +1 -1
  331. package/src/engine/sound/simulation/probe/AcousticProbeField.js +6 -19
  332. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts +15 -0
  333. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts.map +1 -1
  334. package/src/engine/sound/simulation/probe/probe_edge_visible.js +59 -41
  335. package/src/engine/sound/simulation/probe/probe_refine_connectivity.d.ts.map +1 -1
  336. package/src/engine/sound/simulation/probe/probe_refine_connectivity.js +164 -181
  337. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts.map +1 -1
  338. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +20 -5
  339. package/src/engine/sound/simulation/render/reverbImpulseResponse.d.ts +0 -1
  340. package/src/engine/sound/simulation/render/reverbImpulseResponse.d.ts.map +1 -1
  341. package/src/engine/sound/simulation/render/reverbImpulseResponse.js +0 -6
  342. package/src/engine/sound/simulation/render/reverb_band_tails.d.ts +1 -1
  343. package/src/engine/sound/simulation/render/reverb_band_tails.js +1 -1
  344. package/src/engine/sound/sopra/runtime/EventInstance.js +1 -1
  345. package/src/format/image/avif/av1/decode/Av1FrameContext.d.ts.map +1 -1
  346. package/src/format/image/avif/av1/decode/Av1FrameContext.js +3 -10
  347. package/src/format/image/avif/av1/decode/reconstruct.d.ts +20 -0
  348. package/src/format/image/avif/av1/decode/reconstruct.d.ts.map +1 -1
  349. package/src/format/image/avif/av1/decode/reconstruct.js +22 -9
  350. package/src/format/image/avif/av1/encode/choose_restoration.js +2 -18
  351. package/src/format/image/avif/av1/encode/quantise.d.ts.map +1 -1
  352. package/src/format/image/avif/av1/encode/quantise.js +1 -55
  353. package/src/format/image/avif/av1/filter/loop_restoration.d.ts +9 -0
  354. package/src/format/image/avif/av1/filter/loop_restoration.d.ts.map +1 -1
  355. package/src/format/image/avif/av1/filter/loop_restoration.js +1 -1
  356. package/src/format/texture/basis/transcode/etc1s_to_bc7.js +2 -33
  357. package/src/format/texture/basis/transcode/fit_endpoints.d.ts +11 -0
  358. package/src/format/texture/basis/transcode/fit_endpoints.d.ts.map +1 -1
  359. package/src/format/texture/basis/transcode/fit_endpoints.js +1 -1
  360. package/src/format/texture/basis/uastc/uastc_decode_block.d.ts.map +1 -1
  361. package/src/format/texture/basis/uastc/uastc_decode_block.js +2 -19
  362. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +220 -0
  363. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +172 -0
  364. package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +86 -0
  365. package/src/generation/foliage/FOLIAGE_DESIGN.md +238 -31
  366. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +158 -0
  367. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +486 -0
  368. package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +86 -0
  369. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +346 -0
  370. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +248 -0
  371. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +694 -0
  372. package/src/generation/foliage/analysis/CrownOpacity.d.ts +118 -0
  373. package/src/generation/foliage/analysis/CrownOpacity.d.ts.map +1 -0
  374. package/src/generation/foliage/analysis/CrownOpacity.js +182 -0
  375. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts +10 -0
  376. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts.map +1 -0
  377. package/src/generation/foliage/analysis/crown_opacity_frames.js +132 -0
  378. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts +51 -0
  379. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts.map +1 -0
  380. package/src/generation/foliage/analysis/crown_opacity_measure.js +627 -0
  381. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts +66 -0
  382. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts.map +1 -0
  383. package/src/generation/foliage/analysis/foliage_measure_leaf_area.js +186 -0
  384. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts +27 -0
  385. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts.map +1 -0
  386. package/src/generation/foliage/analysis/tree_crown_opacity.js +58 -0
  387. package/src/generation/foliage/analysis/tree_leaf_area_targets.d.ts +66 -0
  388. package/src/generation/foliage/analysis/tree_leaf_area_targets.d.ts.map +1 -0
  389. package/src/generation/foliage/analysis/tree_leaf_area_targets.js +95 -0
  390. package/src/generation/foliage/analysis/tree_render_cost.d.ts +88 -0
  391. package/src/generation/foliage/analysis/tree_render_cost.d.ts.map +1 -0
  392. package/src/generation/foliage/analysis/tree_render_cost.js +157 -0
  393. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts +3 -2
  394. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts.map +1 -1
  395. package/src/generation/foliage/animation/build_tree_wind_rig.js +12 -30
  396. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts +12 -0
  397. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts.map +1 -0
  398. package/src/generation/foliage/animation/tree_wind_bend_limit.js +13 -0
  399. package/src/generation/foliage/asset/TreeAsset.d.ts +12 -6
  400. package/src/generation/foliage/asset/TreeAsset.d.ts.map +1 -1
  401. package/src/generation/foliage/asset/TreeAsset.js +16 -7
  402. package/src/generation/foliage/asset/TreeLODAsset.d.ts +24 -11
  403. package/src/generation/foliage/asset/TreeLODAsset.d.ts.map +1 -1
  404. package/src/generation/foliage/asset/TreeLODAsset.js +49 -20
  405. package/src/generation/foliage/asset/generate_tree.d.ts +11 -0
  406. package/src/generation/foliage/asset/generate_tree.d.ts.map +1 -1
  407. package/src/generation/foliage/asset/generate_tree.js +105 -14
  408. package/src/generation/foliage/asset/tree_lod_plan.d.ts +71 -0
  409. package/src/generation/foliage/asset/tree_lod_plan.d.ts.map +1 -0
  410. package/src/generation/foliage/asset/tree_lod_plan.js +119 -0
  411. package/src/generation/foliage/config/BranchGeneratorConfig.d.ts +264 -0
  412. package/src/generation/foliage/config/BranchGeneratorConfig.d.ts.map +1 -0
  413. package/src/generation/foliage/config/BranchGeneratorConfig.js +471 -0
  414. package/src/generation/foliage/config/BranchSpawnRule.d.ts +118 -0
  415. package/src/generation/foliage/config/BranchSpawnRule.d.ts.map +1 -0
  416. package/src/generation/foliage/config/BranchSpawnRule.js +217 -0
  417. package/src/generation/foliage/config/FoliageCardType.d.ts +1 -1
  418. package/src/generation/foliage/config/FoliageCardType.js +2 -2
  419. package/src/generation/foliage/config/FoliageConfig.d.ts +23 -45
  420. package/src/generation/foliage/config/FoliageConfig.d.ts.map +1 -1
  421. package/src/generation/foliage/config/FoliageConfig.js +47 -93
  422. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +12 -20
  423. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -1
  424. package/src/generation/foliage/config/FoliageMaterialConfig.js +261 -279
  425. package/src/generation/foliage/config/FoliageSpawnRule.d.ts +77 -0
  426. package/src/generation/foliage/config/FoliageSpawnRule.d.ts.map +1 -0
  427. package/src/generation/foliage/config/FoliageSpawnRule.js +135 -0
  428. package/src/generation/foliage/config/FoliageTileContent.d.ts +9 -0
  429. package/src/generation/foliage/config/FoliageTileContent.d.ts.map +1 -0
  430. package/src/generation/foliage/config/FoliageTileContent.js +12 -0
  431. package/src/generation/foliage/config/LeafApexShape.d.ts +12 -0
  432. package/src/generation/foliage/config/LeafApexShape.d.ts.map +1 -0
  433. package/src/generation/foliage/config/LeafApexShape.js +17 -0
  434. package/src/generation/foliage/config/LeafArchitecture.d.ts +155 -0
  435. package/src/generation/foliage/config/LeafArchitecture.d.ts.map +1 -0
  436. package/src/generation/foliage/config/LeafArchitecture.js +288 -0
  437. package/src/generation/foliage/config/LeafBaseShape.d.ts +14 -0
  438. package/src/generation/foliage/config/LeafBaseShape.d.ts.map +1 -0
  439. package/src/generation/foliage/config/LeafBaseShape.js +21 -0
  440. package/src/generation/foliage/config/LeafLobation.d.ts +10 -0
  441. package/src/generation/foliage/config/LeafLobation.d.ts.map +1 -0
  442. package/src/generation/foliage/config/LeafLobation.js +14 -0
  443. package/src/generation/foliage/config/PhyllotaxisMode.d.ts +11 -0
  444. package/src/generation/foliage/config/PhyllotaxisMode.d.ts.map +1 -1
  445. package/src/generation/foliage/config/PhyllotaxisMode.js +36 -0
  446. package/src/generation/foliage/config/ShootBudZone.d.ts +105 -0
  447. package/src/generation/foliage/config/ShootBudZone.d.ts.map +1 -0
  448. package/src/generation/foliage/config/ShootBudZone.js +219 -0
  449. package/src/generation/foliage/config/ShootGrowthConfig.d.ts +119 -0
  450. package/src/generation/foliage/config/ShootGrowthConfig.d.ts.map +1 -0
  451. package/src/generation/foliage/config/ShootGrowthConfig.js +200 -0
  452. package/src/generation/foliage/config/ShootSystemRule.d.ts +144 -0
  453. package/src/generation/foliage/config/ShootSystemRule.d.ts.map +1 -0
  454. package/src/generation/foliage/config/ShootSystemRule.js +320 -0
  455. package/src/generation/foliage/config/TreeLODConfig.d.ts +14 -37
  456. package/src/generation/foliage/config/TreeLODConfig.d.ts.map +1 -1
  457. package/src/generation/foliage/config/TreeLODConfig.js +23 -116
  458. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts +41 -8
  459. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts.map +1 -1
  460. package/src/generation/foliage/config/TreeSpeciesConfig.js +125 -74
  461. package/src/generation/foliage/config/TreeWindConfig.d.ts +23 -10
  462. package/src/generation/foliage/config/TreeWindConfig.d.ts.map +1 -1
  463. package/src/generation/foliage/config/TreeWindConfig.js +34 -25
  464. package/src/generation/foliage/index.d.ts +19 -2
  465. package/src/generation/foliage/index.js +63 -44
  466. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts +59 -0
  467. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts.map +1 -0
  468. package/src/generation/foliage/material/FoliageAtlasCutout.js +93 -0
  469. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts +26 -0
  470. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts.map +1 -0
  471. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.js +63 -0
  472. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts +36 -0
  473. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts.map +1 -0
  474. package/src/generation/foliage/material/foliage_atlas_cutout.js +179 -0
  475. package/src/generation/foliage/material/foliage_material_from_samplers.d.ts +13 -0
  476. package/src/generation/foliage/material/foliage_material_from_samplers.d.ts.map +1 -0
  477. package/src/generation/foliage/material/foliage_material_from_samplers.js +69 -0
  478. package/src/generation/foliage/material/foliage_tile.d.ts +129 -0
  479. package/src/generation/foliage/material/foliage_tile.d.ts.map +1 -0
  480. package/src/generation/foliage/material/foliage_tile.js +294 -0
  481. package/src/generation/foliage/material/leaf_geometry.d.ts +110 -0
  482. package/src/generation/foliage/material/leaf_geometry.d.ts.map +1 -0
  483. package/src/generation/foliage/material/leaf_geometry.js +540 -0
  484. package/src/generation/foliage/material/make_foliage_material.d.ts +14 -35
  485. package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -1
  486. package/src/generation/foliage/material/make_foliage_material.js +302 -605
  487. package/src/generation/foliage/material/tree_cluster_atlas_pack.d.ts +14 -0
  488. package/src/generation/foliage/material/tree_cluster_atlas_pack.d.ts.map +1 -0
  489. package/src/generation/foliage/material/tree_cluster_atlas_pack.js +28 -0
  490. package/src/generation/foliage/material/tree_cluster_bake.d.ts +74 -0
  491. package/src/generation/foliage/material/tree_cluster_bake.d.ts.map +1 -0
  492. package/src/generation/foliage/material/tree_cluster_bake.js +415 -0
  493. package/src/generation/foliage/material/tree_cluster_press.d.ts +18 -0
  494. package/src/generation/foliage/material/tree_cluster_press.d.ts.map +1 -0
  495. package/src/generation/foliage/material/tree_cluster_press.js +83 -0
  496. package/src/generation/foliage/material/tree_cluster_tiles.d.ts +46 -0
  497. package/src/generation/foliage/material/tree_cluster_tiles.d.ts.map +1 -0
  498. package/src/generation/foliage/material/tree_cluster_tiles.js +75 -0
  499. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +60 -7
  500. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -1
  501. package/src/generation/foliage/mesh/foliage_collect_attachments.js +649 -569
  502. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts +48 -0
  503. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts.map +1 -0
  504. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.js +232 -0
  505. package/src/generation/foliage/mesh/tree_cluster_cards.d.ts +61 -0
  506. package/src/generation/foliage/mesh/tree_cluster_cards.d.ts.map +1 -0
  507. package/src/generation/foliage/mesh/tree_cluster_cards.js +114 -0
  508. package/src/generation/foliage/mesh/tree_cluster_representatives.d.ts +121 -0
  509. package/src/generation/foliage/mesh/tree_cluster_representatives.d.ts.map +1 -0
  510. package/src/generation/foliage/mesh/tree_cluster_representatives.js +309 -0
  511. package/src/generation/foliage/mesh/tree_clusters.d.ts +71 -0
  512. package/src/generation/foliage/mesh/tree_clusters.d.ts.map +1 -0
  513. package/src/generation/foliage/mesh/tree_clusters.js +174 -0
  514. package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
  515. package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1428 -1049
  516. package/src/generation/foliage/mesh/tree_mesh_build_clusters.d.ts +25 -0
  517. package/src/generation/foliage/mesh/tree_mesh_build_clusters.d.ts.map +1 -0
  518. package/src/generation/foliage/mesh/tree_mesh_build_clusters.js +144 -0
  519. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +14 -10
  520. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -1
  521. package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +441 -454
  522. package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
  523. package/src/generation/foliage/presets/make_tree_species_preset.js +1520 -870
  524. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts +38 -0
  525. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts.map +1 -0
  526. package/src/generation/foliage/skeleton/ShootFrameworkHash.js +134 -0
  527. package/src/generation/foliage/skeleton/ShootGirth.d.ts +51 -0
  528. package/src/generation/foliage/skeleton/ShootGirth.d.ts.map +1 -0
  529. package/src/generation/foliage/skeleton/ShootGirth.js +213 -0
  530. package/src/generation/foliage/skeleton/ShootLightField.d.ts +82 -0
  531. package/src/generation/foliage/skeleton/ShootLightField.d.ts.map +1 -0
  532. package/src/generation/foliage/skeleton/ShootLightField.js +222 -0
  533. package/src/generation/foliage/skeleton/ShootWoodHash.d.ts +89 -0
  534. package/src/generation/foliage/skeleton/ShootWoodHash.d.ts.map +1 -0
  535. package/src/generation/foliage/skeleton/ShootWoodHash.js +195 -0
  536. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts +112 -3
  537. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts.map +1 -1
  538. package/src/generation/foliage/skeleton/TreeSkeleton.js +226 -39
  539. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts +13 -0
  540. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts.map +1 -0
  541. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.js +16 -0
  542. package/src/generation/foliage/skeleton/foliage_card_density.d.ts +71 -0
  543. package/src/generation/foliage/skeleton/foliage_card_density.d.ts.map +1 -0
  544. package/src/generation/foliage/skeleton/foliage_card_density.js +101 -0
  545. package/src/generation/foliage/skeleton/foliage_senescence.d.ts +101 -0
  546. package/src/generation/foliage/skeleton/foliage_senescence.d.ts.map +1 -0
  547. package/src/generation/foliage/skeleton/foliage_senescence.js +149 -0
  548. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts +76 -0
  549. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts.map +1 -0
  550. package/src/generation/foliage/skeleton/foliage_unit_cards.js +95 -0
  551. package/src/generation/foliage/skeleton/shoot_demography.d.ts +35 -0
  552. package/src/generation/foliage/skeleton/shoot_demography.d.ts.map +1 -0
  553. package/src/generation/foliage/skeleton/shoot_demography.js +112 -0
  554. package/src/generation/foliage/skeleton/shoot_geometry.d.ts +65 -0
  555. package/src/generation/foliage/skeleton/shoot_geometry.d.ts.map +1 -0
  556. package/src/generation/foliage/skeleton/shoot_geometry.js +126 -0
  557. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts +205 -0
  558. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts.map +1 -0
  559. package/src/generation/foliage/skeleton/shoot_systems_simulate.js +1055 -0
  560. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts +53 -12
  561. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts.map +1 -1
  562. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.js +173 -102
  563. package/src/generation/foliage/skeleton/tree_skeleton_bind_skin_joints.d.ts +10 -0
  564. package/src/generation/foliage/skeleton/tree_skeleton_bind_skin_joints.d.ts.map +1 -0
  565. package/src/generation/foliage/skeleton/tree_skeleton_bind_skin_joints.js +12 -0
  566. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts +112 -0
  567. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts.map +1 -0
  568. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js +408 -0
  569. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts.map +1 -1
  570. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js +208 -206
  571. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts +5 -2
  572. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
  573. package/src/generation/foliage/skeleton/tree_skeleton_grow.js +2049 -1871
  574. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts +21 -0
  575. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts.map +1 -0
  576. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.js +327 -0
  577. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts +14 -0
  578. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts.map +1 -0
  579. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.js +26 -0
  580. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts +10 -0
  581. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts.map +1 -0
  582. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.js +20 -0
  583. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
  584. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +4 -1
  585. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +1 -0
  586. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
  587. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +98 -86
  588. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +263 -0
  589. package/src/shade/descriptor/WebGPUExtensionType.d.ts +17 -0
  590. package/src/shade/descriptor/WebGPUExtensionType.d.ts.map +1 -1
  591. package/src/shade/descriptor/WebGPUExtensionType.js +31 -1
  592. package/src/shade/descriptor/binding/BindGroupLayoutEntry.js +6 -6
  593. package/src/shade/descriptor/pipeline/render/ColorTargetState.js +2 -2
  594. package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.js +3 -3
  595. package/src/shade/playground/additive_blending/main.js +529 -529
  596. package/src/shade/playground/avboit/main.js +1 -1
  597. package/src/shade/playground/basis_textures/main.js +365 -365
  598. package/src/shade/playground/caldera/main.js +1 -1
  599. package/src/shade/playground/contact_shadows/main.js +1 -1
  600. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts +37 -0
  601. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts.map +1 -0
  602. package/src/shade/playground/foliage_wind/FoliageRigOverlay.js +491 -0
  603. package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
  604. package/src/shade/playground/foliage_wind/foliage_world.js +600 -602
  605. package/src/shade/playground/foliage_wind/index.html +6 -0
  606. package/src/shade/playground/foliage_wind/main.js +289 -275
  607. package/src/shade/playground/mesh_row_ceiling/main.js +1 -1
  608. package/src/shade/playground/particle_ecs/main.js +1 -1
  609. package/src/shade/playground/particle_system/main.js +1 -1
  610. package/src/shade/playground/sh_exponential/main.js +1 -1
  611. package/src/shade/playground/skinned_blas_refit/main.js +1 -1
  612. package/src/shade/playground/skinned_mesh_soup/main.js +1 -1
  613. package/src/shade/playground/sponza_path_trace/main.js +1 -1
  614. package/src/shade/playground/ssr_motion/main.js +1 -1
  615. package/src/shade/playground/ssr_reprojection/main.js +1 -1
  616. package/src/shade/playground/tonemap_sdr/main.js +1 -1
  617. package/src/shade/playground/vgeo_runtime/main.js +1 -1
  618. package/src/shade/playground/vgeo_scene/main.js +1 -1
  619. package/src/shade/playground/volumetrics_froxel/main.js +1 -1
  620. package/src/shade/playground/vsm/index.html +4 -1
  621. package/src/shade/playground/vsm/main.d.ts.map +1 -1
  622. package/src/shade/playground/vsm/main.js +8 -5
  623. package/src/shade/playground/water_refraction/main.js +1 -1
  624. package/src/shade/playground/water_surface/main.js +1 -1
  625. package/src/shade/renderer/Renderer.d.ts +13 -0
  626. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  627. package/src/shade/renderer/Renderer.js +132 -3
  628. package/src/shade/renderer/ShadeIndirectLightingMode.d.ts +1 -0
  629. package/src/shade/renderer/ShadeIndirectLightingMode.js +6 -0
  630. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  631. package/src/shade/renderer/animation/GPUAnimationManager.js +2 -1
  632. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts +2 -1
  633. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts.map +1 -1
  634. package/src/shade/renderer/animation/foliage/FoliageWindJoint.js +2 -1
  635. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.d.ts.map +1 -1
  636. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.js +4 -2
  637. package/src/shade/renderer/buffer/table/GPUTypedTable.js +1 -1
  638. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
  639. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +403 -401
  640. package/src/shade/renderer/camera/orbital/README.md +3 -6
  641. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_restir.d.ts +1 -1
  642. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_restir.js +1 -1
  643. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.d.ts.map +1 -1
  644. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.js +3 -0
  645. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.d.ts.map +1 -1
  646. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.js +6 -1
  647. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +1 -1
  648. package/src/shade/renderer/fluid/FluidCascadePlacement.d.ts +8 -105
  649. package/src/shade/renderer/fluid/FluidCascadePlacement.d.ts.map +1 -1
  650. package/src/shade/renderer/fluid/FluidCascadePlacement.js +13 -306
  651. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +5 -5
  652. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts.map +1 -1
  653. package/src/shade/renderer/fluid/GPUFluidCascade.js +6 -3
  654. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  655. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +361 -0
  656. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.d.ts.map +1 -1
  657. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js +335 -241
  658. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.d.ts.map +1 -1
  659. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js +108 -101
  660. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  661. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.d.ts.map +1 -1
  662. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.js +69 -67
  663. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts +7 -6
  664. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts.map +1 -1
  665. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js +341 -287
  666. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_command.d.ts.map +1 -1
  667. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_command.js +8 -14
  668. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts +6 -4
  669. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts.map +1 -1
  670. package/src/shade/renderer/fluid/mac/FluidMacPasses.js +427 -400
  671. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts +10 -5
  672. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts.map +1 -1
  673. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.js +532 -190
  674. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.d.ts.map +1 -1
  675. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.js +231 -237
  676. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts +2 -2
  677. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts.map +1 -1
  678. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js +282 -245
  679. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts +1 -3
  680. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts.map +1 -1
  681. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.js +139 -109
  682. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts +6 -6
  683. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts.map +1 -1
  684. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.js +257 -222
  685. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts +8 -7
  686. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts.map +1 -1
  687. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.js +119 -92
  688. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts +6 -9
  689. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts.map +1 -1
  690. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.js +229 -181
  691. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +18 -8
  692. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts.map +1 -1
  693. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.js +634 -621
  694. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts +8 -6
  695. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts.map +1 -1
  696. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js +166 -149
  697. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts +8 -6
  698. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts.map +1 -1
  699. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js +219 -183
  700. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.d.ts.map +1 -1
  701. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.js +142 -122
  702. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  703. package/src/shade/renderer/geometry/BoxGeometry.d.ts +0 -1
  704. package/src/shade/renderer/geometry/BoxGeometry.d.ts.map +1 -1
  705. package/src/shade/renderer/geometry/BoxGeometry.js +0 -9
  706. package/src/shade/renderer/geometry/GPUGeometryManager.d.ts +4 -2
  707. package/src/shade/renderer/geometry/GPUGeometryManager.d.ts.map +1 -1
  708. package/src/shade/renderer/geometry/GPUGeometryManager.js +13 -2
  709. package/src/shade/renderer/geometry/Geometry.js +2 -2
  710. package/src/shade/renderer/geometry/blas_from_meshlets.d.ts.map +1 -1
  711. package/src/shade/renderer/geometry/blas_from_meshlets.js +12 -2
  712. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  713. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +18 -0
  714. package/src/shade/renderer/geometry/bvh/bvh2_derive_topology.d.ts.map +1 -1
  715. package/src/shade/renderer/geometry/bvh/bvh2_derive_topology.js +5 -0
  716. package/src/shade/renderer/geometry/mesh_compute_surface_area.js +4 -4
  717. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +674 -663
  718. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +1 -1
  719. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  720. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +63 -29
  721. package/src/shade/renderer/geometry/meshlet/MeshletBatch.d.ts +5 -0
  722. package/src/shade/renderer/geometry/meshlet/MeshletBatch.d.ts.map +1 -1
  723. package/src/shade/renderer/geometry/meshlet/MeshletBatch.js +15 -0
  724. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  725. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +77 -87
  726. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.d.ts.map +1 -1
  727. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.js +4 -3
  728. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts +11 -11
  729. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts.map +1 -1
  730. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.js +17 -19
  731. package/src/shade/renderer/geometry/meshlet_batch_to_bvh.d.ts.map +1 -1
  732. package/src/shade/renderer/geometry/meshlet_batch_to_bvh.js +35 -26
  733. package/src/shade/renderer/geometry/meshlet_geometry_build_from_geometry.d.ts.map +1 -1
  734. package/src/shade/renderer/geometry/meshlet_geometry_build_from_geometry.js +2 -1
  735. package/src/shade/renderer/geometry/normals/decode_octahedral_u32_to_normal.d.ts +13 -0
  736. package/src/shade/renderer/geometry/normals/decode_octahedral_u32_to_normal.d.ts.map +1 -0
  737. package/src/shade/renderer/geometry/normals/decode_octahedral_u32_to_normal.js +33 -0
  738. package/src/shade/renderer/geometry/normals/geometry_build_tangents.js +7 -7
  739. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +189 -45
  740. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  741. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +1853 -144
  742. package/src/shade/renderer/geometry/sdf/MESH_SDF.d.ts +60 -0
  743. package/src/shade/renderer/geometry/sdf/MESH_SDF.d.ts.map +1 -0
  744. package/src/shade/renderer/geometry/sdf/MESH_SDF.js +62 -0
  745. package/src/shade/renderer/geometry/sdf/MESH_SDF_RESOURCES.d.ts +29 -0
  746. package/src/shade/renderer/geometry/sdf/MESH_SDF_RESOURCES.d.ts.map +1 -0
  747. package/src/shade/renderer/geometry/sdf/MESH_SDF_RESOURCES.js +41 -0
  748. package/src/shade/renderer/geometry/sdf/MESH_SDF_STRUCT.d.ts +12 -0
  749. package/src/shade/renderer/geometry/sdf/MESH_SDF_STRUCT.d.ts.map +1 -0
  750. package/src/shade/renderer/geometry/sdf/MESH_SDF_STRUCT.js +53 -0
  751. package/src/shade/renderer/geometry/sdf/MeshSDFLayout.d.ts +79 -0
  752. package/src/shade/renderer/geometry/sdf/MeshSDFLayout.d.ts.map +1 -0
  753. package/src/shade/renderer/geometry/sdf/MeshSDFLayout.js +168 -0
  754. package/src/shade/renderer/geometry/sdf/bake/MESH_SDF_BAKE.d.ts +75 -0
  755. package/src/shade/renderer/geometry/sdf/bake/MESH_SDF_BAKE.d.ts.map +1 -0
  756. package/src/shade/renderer/geometry/sdf/bake/MESH_SDF_BAKE.js +110 -0
  757. package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_bake.d.ts +48 -0
  758. package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_bake.d.ts.map +1 -0
  759. package/src/shade/renderer/geometry/sdf/bake/chunk_mesh_sdf_bake.js +146 -0
  760. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_classify.d.ts +31 -0
  761. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_classify.d.ts.map +1 -0
  762. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_classify.js +136 -0
  763. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_evaluate.d.ts +29 -0
  764. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_evaluate.d.ts.map +1 -0
  765. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_evaluate.js +146 -0
  766. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_free.d.ts +19 -0
  767. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_free.d.ts.map +1 -0
  768. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_free.js +77 -0
  769. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_store.d.ts +18 -0
  770. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_store.d.ts.map +1 -0
  771. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_store.js +84 -0
  772. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_take.d.ts +19 -0
  773. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_take.d.ts.map +1 -0
  774. package/src/shade/renderer/geometry/sdf/bake/shader_mesh_sdf_take.js +72 -0
  775. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +171 -0
  776. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -0
  777. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +884 -0
  778. package/src/shade/renderer/geometry/sdf/cards/MESH_CARDS.d.ts +82 -0
  779. package/src/shade/renderer/geometry/sdf/cards/MESH_CARDS.d.ts.map +1 -0
  780. package/src/shade/renderer/geometry/sdf/cards/MESH_CARDS.js +127 -0
  781. package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_RESOURCES.d.ts +24 -0
  782. package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_RESOURCES.d.ts.map +1 -0
  783. package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_RESOURCES.js +29 -0
  784. package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_SET_STRUCT.d.ts +12 -0
  785. package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_SET_STRUCT.d.ts.map +1 -0
  786. package/src/shade/renderer/geometry/sdf/cards/MESH_CARD_SET_STRUCT.js +31 -0
  787. package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_card_surface.d.ts +29 -0
  788. package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_card_surface.d.ts.map +1 -0
  789. package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_card_surface.js +179 -0
  790. package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_cards.d.ts +17 -0
  791. package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_cards.d.ts.map +1 -0
  792. package/src/shade/renderer/geometry/sdf/cards/chunk_mesh_cards.js +107 -0
  793. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_capture.d.ts +36 -0
  794. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_capture.d.ts.map +1 -0
  795. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_capture.js +237 -0
  796. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_compact.d.ts +19 -0
  797. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_compact.d.ts.map +1 -0
  798. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_compact.js +61 -0
  799. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.d.ts +18 -0
  800. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.d.ts.map +1 -0
  801. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.js +102 -0
  802. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_log.d.ts +15 -0
  803. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_log.d.ts.map +1 -0
  804. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_log.js +65 -0
  805. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_merge.d.ts +22 -0
  806. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_merge.d.ts.map +1 -0
  807. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_merge.js +136 -0
  808. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_pages.d.ts +20 -0
  809. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_pages.d.ts.map +1 -0
  810. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_pages.js +104 -0
  811. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_split.d.ts +30 -0
  812. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_split.d.ts.map +1 -0
  813. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_split.js +146 -0
  814. package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.d.ts +35 -0
  815. package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.d.ts.map +1 -0
  816. package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.js +161 -0
  817. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf.d.ts +21 -0
  818. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf.d.ts.map +1 -0
  819. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf.js +112 -0
  820. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_normal.d.ts +15 -0
  821. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_normal.d.ts.map +1 -0
  822. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_normal.js +34 -0
  823. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_raymarch.d.ts +17 -0
  824. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_raymarch.d.ts.map +1 -0
  825. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_raymarch.js +64 -0
  826. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_sample.d.ts +32 -0
  827. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_sample.d.ts.map +1 -0
  828. package/src/shade/renderer/geometry/sdf/chunk_mesh_sdf_sample.js +104 -0
  829. package/src/shade/renderer/geometry/sdf/shader_sdf_visualize.d.ts +2 -0
  830. package/src/shade/renderer/geometry/sdf/shader_sdf_visualize.d.ts.map +1 -1
  831. package/src/shade/renderer/geometry/sdf/shader_sdf_visualize.js +13 -23
  832. package/src/shade/renderer/geometry/util/geometry_compute_surface_area.js +2 -2
  833. package/src/shade/renderer/geometry/util/geometry_estimate_uv_aspect.js +2 -2
  834. package/src/shade/renderer/geometry/util/geometry_simplify_redundant_topology.js +2 -2
  835. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_bake_ao.js +2 -2
  836. package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.js +2 -2
  837. package/src/shade/renderer/global_illumination/lpv/graph_bake_irradiance_lookup_2d.js +4 -4
  838. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts +0 -2
  839. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts.map +1 -1
  840. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.js +3 -13
  841. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.d.ts +10 -16
  842. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.d.ts.map +1 -1
  843. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +39 -82
  844. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.d.ts.map +1 -1
  845. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.js +5 -1
  846. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +115 -0
  847. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -0
  848. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +369 -0
  849. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +2677 -0
  850. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +83 -0
  851. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -0
  852. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +626 -0
  853. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +265 -0
  854. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -0
  855. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +475 -0
  856. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.d.ts +131 -0
  857. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.d.ts.map +1 -0
  858. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.js +181 -0
  859. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_MOVERS.d.ts +37 -0
  860. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_MOVERS.d.ts.map +1 -0
  861. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_MOVERS.js +48 -0
  862. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts +223 -0
  863. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts.map +1 -0
  864. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.js +984 -0
  865. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap.d.ts +69 -0
  866. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap.d.ts.map +1 -0
  867. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap.js +169 -0
  868. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts +191 -0
  869. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts.map +1 -0
  870. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.js +590 -0
  871. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK_INSTANCE_STRUCT.d.ts +30 -0
  872. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK_INSTANCE_STRUCT.d.ts.map +1 -0
  873. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK_INSTANCE_STRUCT.js +43 -0
  874. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MeshSDFBrickProvider.d.ts +35 -0
  875. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MeshSDFBrickProvider.d.ts.map +1 -0
  876. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MeshSDFBrickProvider.js +124 -0
  877. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +29 -0
  878. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts.map +1 -0
  879. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +97 -0
  880. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_object.d.ts +21 -0
  881. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_object.d.ts.map +1 -0
  882. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_object.js +42 -0
  883. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_texel.d.ts +26 -0
  884. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_texel.d.ts.map +1 -0
  885. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_texel.js +73 -0
  886. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_provider.d.ts +35 -0
  887. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_provider.d.ts.map +1 -0
  888. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_provider.js +247 -0
  889. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_clear.d.ts +10 -0
  890. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_clear.d.ts.map +1 -0
  891. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_clear.js +44 -0
  892. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_coarse.d.ts +24 -0
  893. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_coarse.d.ts.map +1 -0
  894. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_coarse.js +92 -0
  895. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_free.d.ts +26 -0
  896. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_free.d.ts.map +1 -0
  897. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_free.js +133 -0
  898. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_movers.d.ts +21 -0
  899. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_movers.d.ts.map +1 -0
  900. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_movers.js +146 -0
  901. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_movers_command.d.ts +18 -0
  902. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_movers_command.d.ts.map +1 -0
  903. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_movers_command.js +84 -0
  904. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_requeue.d.ts +16 -0
  905. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_requeue.d.ts.map +1 -0
  906. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_requeue.js +67 -0
  907. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_scroll.d.ts +20 -0
  908. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_scroll.d.ts.map +1 -0
  909. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_scroll.js +128 -0
  910. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_store.d.ts +20 -0
  911. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_store.d.ts.map +1 -0
  912. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_store.js +127 -0
  913. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_take.d.ts +20 -0
  914. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_take.d.ts.map +1 -0
  915. package/src/shade/renderer/global_illumination/probe_clipmap/brick/shader_brick_clipmap_take.js +79 -0
  916. package/src/shade/renderer/global_illumination/probe_clipmap/debug/ProbeClipmapDebugView.d.ts +11 -0
  917. package/src/shade/renderer/global_illumination/probe_clipmap/debug/ProbeClipmapDebugView.d.ts.map +1 -0
  918. package/src/shade/renderer/global_illumination/probe_clipmap/debug/ProbeClipmapDebugView.js +16 -0
  919. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.d.ts +29 -0
  920. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.d.ts.map +1 -0
  921. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.js +160 -0
  922. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_cards.d.ts +34 -0
  923. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_cards.d.ts.map +1 -0
  924. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_cards.js +189 -0
  925. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_sdf.d.ts +25 -0
  926. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_sdf.d.ts.map +1 -0
  927. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_mesh_sdf.js +138 -0
  928. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +170 -0
  929. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -0
  930. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +982 -0
  931. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +216 -0
  932. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -0
  933. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +289 -0
  934. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +232 -0
  935. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -0
  936. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +448 -0
  937. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +41 -0
  938. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -0
  939. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +110 -0
  940. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +30 -0
  941. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts.map +1 -0
  942. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js +261 -0
  943. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.d.ts +34 -0
  944. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.d.ts.map +1 -0
  945. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.js +169 -0
  946. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts +22 -0
  947. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts.map +1 -0
  948. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.js +110 -0
  949. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_fill.d.ts +10 -0
  950. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_fill.d.ts.map +1 -0
  951. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_fill.js +39 -0
  952. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts +26 -0
  953. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts.map +1 -0
  954. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.js +177 -0
  955. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_publish.d.ts +18 -0
  956. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_publish.d.ts.map +1 -0
  957. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_publish.js +105 -0
  958. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.d.ts +25 -0
  959. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.d.ts.map +1 -0
  960. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.js +124 -0
  961. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.d.ts +21 -0
  962. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.d.ts.map +1 -0
  963. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.js +118 -0
  964. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts +19 -0
  965. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts.map +1 -0
  966. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.js +72 -0
  967. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts +24 -0
  968. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -0
  969. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +141 -0
  970. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts +33 -0
  971. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -0
  972. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +203 -0
  973. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace_command.d.ts +19 -0
  974. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace_command.d.ts.map +1 -0
  975. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace_command.js +88 -0
  976. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts +27 -0
  977. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts.map +1 -0
  978. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.js +199 -0
  979. package/src/shade/renderer/gpu_primitive/indirect/chunk_folded_dispatch.d.ts +19 -0
  980. package/src/shade/renderer/gpu_primitive/indirect/chunk_folded_dispatch.d.ts.map +1 -0
  981. package/src/shade/renderer/gpu_primitive/indirect/chunk_folded_dispatch.js +31 -0
  982. package/src/shade/renderer/gpu_primitive/slot_stack/chunk_slot_stack.d.ts +33 -0
  983. package/src/shade/renderer/gpu_primitive/slot_stack/chunk_slot_stack.d.ts.map +1 -0
  984. package/src/shade/renderer/gpu_primitive/slot_stack/chunk_slot_stack.js +58 -0
  985. package/src/shade/renderer/gpu_primitive/slot_stack/shader_slot_stack_fill.d.ts +31 -0
  986. package/src/shade/renderer/gpu_primitive/slot_stack/shader_slot_stack_fill.d.ts.map +1 -0
  987. package/src/shade/renderer/gpu_primitive/slot_stack/shader_slot_stack_fill.js +62 -0
  988. package/src/shade/renderer/gpu_primitive/slot_stack/shader_slot_stack_push_range.d.ts +21 -0
  989. package/src/shade/renderer/gpu_primitive/slot_stack/shader_slot_stack_push_range.d.ts.map +1 -0
  990. package/src/shade/renderer/gpu_primitive/slot_stack/shader_slot_stack_push_range.js +61 -0
  991. package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
  992. package/src/shade/renderer/light/GPULightCollection.js +12 -11
  993. package/src/shade/renderer/light/cluster/cull/shader_cull_lights_frustum.d.ts +0 -1
  994. package/src/shade/renderer/light/cluster/cull/shader_cull_lights_frustum.d.ts.map +1 -1
  995. package/src/shade/renderer/light/cluster/cull/shader_cull_lights_frustum.js +117 -120
  996. package/src/shade/renderer/light/environment/octahedral_z_pole_uv_to_direction.d.ts +1 -2
  997. package/src/shade/renderer/light/environment/octahedral_z_pole_uv_to_direction.d.ts.map +1 -1
  998. package/src/shade/renderer/light/environment/octahedral_z_pole_uv_to_direction.js +44 -45
  999. package/src/shade/renderer/lightmap/atlas/rescale_uvs.js +2 -2
  1000. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  1001. package/src/shade/renderer/loader/gltf/load_gltf.js +11 -35
  1002. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  1003. package/src/shade/renderer/loader/usd/load_usd.d.ts.map +1 -1
  1004. package/src/shade/renderer/loader/usd/load_usd.js +6 -19
  1005. package/src/shade/renderer/material/StandardShadeMaterial.js +5 -5
  1006. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +10 -4
  1007. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  1008. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +112 -8
  1009. package/src/shade/renderer/material/resident/RESIDENT_MATERIAL_TEXTURE_LAYOUT.d.ts +21 -0
  1010. package/src/shade/renderer/material/resident/RESIDENT_MATERIAL_TEXTURE_LAYOUT.d.ts.map +1 -0
  1011. package/src/shade/renderer/material/resident/RESIDENT_MATERIAL_TEXTURE_LAYOUT.js +30 -0
  1012. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +24 -0
  1013. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +1 -0
  1014. package/src/shade/renderer/material/resident/shader_resident_texture_means.js +120 -0
  1015. package/src/shade/renderer/particles/GPUParticleSystem.js +7 -7
  1016. package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts +0 -1
  1017. package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts.map +1 -1
  1018. package/src/shade/renderer/particles/graph/validate_particle_graph.js +0 -6
  1019. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
  1020. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +199 -193
  1021. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -1
  1022. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +151 -143
  1023. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  1024. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +5 -6
  1025. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.d.ts.map +1 -1
  1026. package/src/shade/renderer/particles/shaders/shader_particle_emit_wide.js +5 -7
  1027. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  1028. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +3 -2
  1029. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.d.ts.map +1 -1
  1030. package/src/shade/renderer/particles/shaders/shader_particle_simulate_wide.js +3 -2
  1031. package/src/shade/renderer/particles/warmup/shader_particle_warmup.d.ts.map +1 -1
  1032. package/src/shade/renderer/particles/warmup/shader_particle_warmup.js +316 -318
  1033. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance.d.ts.map +1 -1
  1034. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance.js +3 -2
  1035. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.d.ts.map +1 -1
  1036. package/src/shade/renderer/particles/warmup/shader_particle_warmup_advance_wide.js +2 -0
  1037. package/src/shade/renderer/path_tracer/shader/chunk_indirect_sample_texture.js +1 -1
  1038. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.d.ts.map +1 -1
  1039. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.js +11 -5
  1040. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.d.ts.map +1 -1
  1041. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.js +6 -18
  1042. package/src/shade/renderer/postprocess/gtao/GTAO.js +1 -1
  1043. package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.d.ts.map +1 -1
  1044. package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.js +75 -78
  1045. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  1046. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +3 -5
  1047. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts +0 -5
  1048. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
  1049. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +377 -382
  1050. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +1 -1
  1051. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  1052. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.d.ts.map +1 -1
  1053. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.js +7 -3
  1054. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
  1055. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +4 -2
  1056. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
  1057. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +4 -1
  1058. package/src/shade/renderer/postprocess/ssr/downsample_karis.d.ts.map +1 -1
  1059. package/src/shade/renderer/postprocess/ssr/downsample_karis.js +6 -3
  1060. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
  1061. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +4 -3
  1062. package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_add_hit_irradiance.js +1 -0
  1063. package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_sample_radiance.d.ts +2 -1
  1064. package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_sample_radiance.d.ts.map +1 -1
  1065. package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_sample_radiance.js +3 -1
  1066. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.d.ts.map +1 -1
  1067. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.js +4 -1
  1068. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
  1069. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +4 -2
  1070. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts.map +1 -1
  1071. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.js +35 -39
  1072. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.d.ts.map +1 -1
  1073. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.js +20 -17
  1074. package/src/shade/renderer/postprocess/taa/shader_taa.d.ts.map +1 -1
  1075. package/src/shade/renderer/postprocess/taa/shader_taa.js +6 -3
  1076. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  1077. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -1
  1078. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect.d.ts +1 -0
  1079. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect.d.ts.map +1 -1
  1080. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect.js +2 -0
  1081. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +1 -1
  1082. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +2 -2
  1083. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +1 -1
  1084. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.d.ts.map +1 -1
  1085. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.js +92 -83
  1086. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +1 -1
  1087. package/src/shade/renderer/scene/GPUSceneContext.d.ts +17 -2
  1088. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  1089. package/src/shade/renderer/scene/GPUSceneContext.js +38 -2
  1090. package/src/shade/renderer/scene/MESH_INSTANCE_METADATA_STRUCT.d.ts +17 -0
  1091. package/src/shade/renderer/scene/MESH_INSTANCE_METADATA_STRUCT.d.ts.map +1 -1
  1092. package/src/shade/renderer/scene/MESH_INSTANCE_METADATA_STRUCT.js +27 -0
  1093. package/src/shade/renderer/scene/bvh/StaticSceneBVH.d.ts.map +1 -1
  1094. package/src/shade/renderer/scene/bvh/StaticSceneBVH.js +4 -6
  1095. package/src/shade/renderer/scene/chunk_mesh_flags.d.ts +9 -0
  1096. package/src/shade/renderer/scene/chunk_mesh_flags.d.ts.map +1 -0
  1097. package/src/shade/renderer/scene/chunk_mesh_flags.js +22 -0
  1098. package/src/shade/renderer/scene/movers/SCENE_MOVER_LAYOUT.d.ts +65 -0
  1099. package/src/shade/renderer/scene/movers/SCENE_MOVER_LAYOUT.d.ts.map +1 -0
  1100. package/src/shade/renderer/scene/movers/SCENE_MOVER_LAYOUT.js +87 -0
  1101. package/src/shade/renderer/scene/movers/SceneMoverTracker.d.ts +42 -0
  1102. package/src/shade/renderer/scene/movers/SceneMoverTracker.d.ts.map +1 -0
  1103. package/src/shade/renderer/scene/movers/SceneMoverTracker.js +153 -0
  1104. package/src/shade/renderer/scene/movers/chunk_scene_append_mover.d.ts +14 -0
  1105. package/src/shade/renderer/scene/movers/chunk_scene_append_mover.d.ts.map +1 -0
  1106. package/src/shade/renderer/scene/movers/chunk_scene_append_mover.js +33 -0
  1107. package/src/shade/renderer/scene/movers/graph_scene_movers.d.ts +33 -0
  1108. package/src/shade/renderer/scene/movers/graph_scene_movers.d.ts.map +1 -0
  1109. package/src/shade/renderer/scene/movers/graph_scene_movers.js +114 -0
  1110. package/src/shade/renderer/scene/movers/shader_scene_movers.d.ts +33 -0
  1111. package/src/shade/renderer/scene/movers/shader_scene_movers.d.ts.map +1 -0
  1112. package/src/shade/renderer/scene/movers/shader_scene_movers.js +197 -0
  1113. package/src/shade/renderer/scene/movers/shader_scene_skinned_movers.d.ts +24 -0
  1114. package/src/shade/renderer/scene/movers/shader_scene_skinned_movers.d.ts.map +1 -0
  1115. package/src/shade/renderer/scene/movers/shader_scene_skinned_movers.js +112 -0
  1116. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts +26 -4
  1117. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
  1118. package/src/shade/renderer/scene/rows/GPUSceneRows.js +64 -6
  1119. package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
  1120. package/src/shade/renderer/shader/ShaderDescriptor.js +12 -4
  1121. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.d.ts.map +1 -1
  1122. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.js +294 -286
  1123. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_nearest_point_on_surface.js +1 -1
  1124. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_mat4_decompose_transform.d.ts +1 -1
  1125. package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_mat4_decompose_transform.js +2 -2
  1126. package/src/shade/renderer/shader/chunk/geometry/quaternion/chunk_quat_decode_u32.d.ts +1 -1
  1127. package/src/shade/renderer/shader/chunk/geometry/quaternion/chunk_quat_decode_u32.js +1 -1
  1128. package/src/shade/renderer/shader/chunk/geometry/quaternion/chunk_quat_encode_u32.d.ts +1 -1
  1129. package/src/shade/renderer/shader/chunk/geometry/quaternion/chunk_quat_encode_u32.js +1 -1
  1130. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_interpolate_probe_irradiance8.js +5 -5
  1131. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.d.ts.map +1 -1
  1132. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.js +5 -3
  1133. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.d.ts.map +1 -1
  1134. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.js +9 -6
  1135. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.d.ts.map +1 -1
  1136. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.js +33 -38
  1137. package/src/shade/renderer/shader/chunk/random/reservoir/chunk_sample_discrete_wrs_mat2x4.d.ts.map +1 -1
  1138. package/src/shade/renderer/shader/chunk/random/reservoir/chunk_sample_discrete_wrs_mat2x4.js +10 -7
  1139. package/src/shade/renderer/shader/chunk/random/reservoir/chunk_sample_discrete_wrs_vec4.d.ts.map +1 -1
  1140. package/src/shade/renderer/shader/chunk/random/reservoir/chunk_sample_discrete_wrs_vec4.js +6 -3
  1141. package/src/shade/renderer/shader/chunk/sdf/chunk_scene_sdf_raymarch.d.ts +22 -0
  1142. package/src/shade/renderer/shader/chunk/sdf/chunk_scene_sdf_raymarch.d.ts.map +1 -1
  1143. package/src/shade/renderer/shader/chunk/sdf/chunk_scene_sdf_raymarch.js +62 -34
  1144. package/src/shade/renderer/shader/compiler/CodeChunk.d.ts +1 -1
  1145. package/src/shade/renderer/shader/compiler/ShaderSwitch.d.ts +1 -1
  1146. package/src/shade/renderer/shader/compiler/ShaderSwitchSet.d.ts +1 -1
  1147. package/src/shade/renderer/shader/resource/ShaderResourceDescriptor.d.ts +1 -1
  1148. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  1149. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +690 -675
  1150. package/src/shade/renderer/shader/type/WebGPUArray.d.ts +3 -0
  1151. package/src/shade/renderer/shader/type/WebGPUArray.d.ts.map +1 -1
  1152. package/src/shade/renderer/shader/type/WebGPUArray.js +185 -167
  1153. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  1154. package/src/shade/renderer/shader/type/WebGPUStruct.js +461 -455
  1155. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.d.ts.map +1 -1
  1156. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.js +335 -211
  1157. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.d.ts.map +1 -1
  1158. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.js +329 -221
  1159. package/src/shade/renderer/shader/type/type_has_f16.d.ts +12 -0
  1160. package/src/shade/renderer/shader/type/type_has_f16.d.ts.map +1 -0
  1161. package/src/shade/renderer/shader/type/type_has_f16.js +66 -0
  1162. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +4 -4
  1163. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts +50 -11
  1164. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  1165. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +188 -51
  1166. package/src/shade/renderer/shadow/map/SHADOWMAP_PATCH_MIN_SIDE.d.ts +8 -0
  1167. package/src/shade/renderer/shadow/map/SHADOWMAP_PATCH_MIN_SIDE.d.ts.map +1 -0
  1168. package/src/shade/renderer/shadow/map/SHADOWMAP_PATCH_MIN_SIDE.js +7 -0
  1169. package/src/shade/renderer/shadow/map/Shadowmap.d.ts +7 -7
  1170. package/src/shade/renderer/shadow/map/Shadowmap.js +7 -7
  1171. package/src/shade/renderer/shadow/map/ShadowmapResolutionPolicy.d.ts +17 -0
  1172. package/src/shade/renderer/shadow/map/ShadowmapResolutionPolicy.d.ts.map +1 -1
  1173. package/src/shade/renderer/shadow/map/ShadowmapResolutionPolicy.js +29 -8
  1174. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_get_light_visibility.d.ts +0 -1
  1175. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_get_light_visibility.d.ts.map +1 -1
  1176. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_get_light_visibility.js +0 -3
  1177. package/src/shade/renderer/shadow/sdf/SDF_DRAW_SETTINGS_STRUCT.d.ts.map +1 -1
  1178. package/src/shade/renderer/shadow/sdf/SDF_DRAW_SETTINGS_STRUCT.js +2 -5
  1179. package/src/shade/renderer/shadow/sdf/chunk_geometry_sdf_query_distance.d.ts +8 -0
  1180. package/src/shade/renderer/shadow/sdf/chunk_geometry_sdf_query_distance.d.ts.map +1 -1
  1181. package/src/shade/renderer/shadow/sdf/chunk_geometry_sdf_query_distance.js +13 -41
  1182. package/src/shade/renderer/shadow/sdf/chunk_ray_query_sdf_raycast_traversal_count.js +6 -5
  1183. package/src/shade/renderer/shadow/sdf/chunk_sdf_geometry_raymarch.d.ts +8 -0
  1184. package/src/shade/renderer/shadow/sdf/chunk_sdf_geometry_raymarch.d.ts.map +1 -1
  1185. package/src/shade/renderer/shadow/sdf/chunk_sdf_geometry_raymarch.js +20 -73
  1186. package/src/shade/renderer/shadow/sdf/chunk_sdf_mesh_raymarch.d.ts.map +1 -1
  1187. package/src/shade/renderer/shadow/sdf/chunk_sdf_mesh_raymarch.js +4 -0
  1188. package/src/shade/renderer/shadow/sdf/graph_draw_sdf_shadows.d.ts +2 -0
  1189. package/src/shade/renderer/shadow/sdf/graph_draw_sdf_shadows.d.ts.map +1 -1
  1190. package/src/shade/renderer/shadow/sdf/graph_draw_sdf_shadows.js +14 -8
  1191. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_LOW_LOAD_FACTOR.d.ts +12 -0
  1192. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_LOW_LOAD_FACTOR.d.ts.map +1 -0
  1193. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_LOW_LOAD_FACTOR.js +11 -0
  1194. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_DYNAMIC_LOD_BIAS.d.ts +9 -0
  1195. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_DYNAMIC_LOD_BIAS.d.ts.map +1 -0
  1196. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_DYNAMIC_LOD_BIAS.js +8 -0
  1197. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_LOAD_FACTOR.d.ts +13 -0
  1198. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_LOAD_FACTOR.d.ts.map +1 -0
  1199. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_LOAD_FACTOR.js +12 -0
  1200. package/src/shade/renderer/shadow/vsm/PLAN.md +3 -1
  1201. package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts +80 -1
  1202. package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts.map +1 -1
  1203. package/src/shade/renderer/shadow/vsm/VSMPageManager.js +303 -3
  1204. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts +54 -3
  1205. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts.map +1 -1
  1206. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.js +418 -338
  1207. package/src/shade/renderer/shadow/vsm/graph_vsm_feedback.d.ts +8 -9
  1208. package/src/shade/renderer/shadow/vsm/graph_vsm_feedback.d.ts.map +1 -1
  1209. package/src/shade/renderer/shadow/vsm/graph_vsm_feedback.js +9 -92
  1210. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_stale.js +6 -6
  1211. package/src/shade/renderer/texture/atlas/GPUTileAtlas2D.d.ts +90 -0
  1212. package/src/shade/renderer/texture/atlas/GPUTileAtlas2D.d.ts.map +1 -0
  1213. package/src/shade/renderer/texture/atlas/GPUTileAtlas2D.js +208 -0
  1214. package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts +23 -4
  1215. package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts.map +1 -1
  1216. package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.js +56 -5
  1217. package/src/shade/renderer/view/GPUViewContext.js +2 -2
  1218. package/src/shade/renderer/volumetrics/chunk_volumetrics_sun_shadow_group_list.d.ts +59 -0
  1219. package/src/shade/renderer/volumetrics/chunk_volumetrics_sun_shadow_group_list.d.ts.map +1 -0
  1220. package/src/shade/renderer/volumetrics/chunk_volumetrics_sun_shadow_group_list.js +152 -0
  1221. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
  1222. package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +145 -46
  1223. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts +2 -1
  1224. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts.map +1 -1
  1225. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.js +3 -1
  1226. package/src/shade/renderer/volumetrics/shader_volumetrics_bin_sun_shadow_media.d.ts +21 -0
  1227. package/src/shade/renderer/volumetrics/shader_volumetrics_bin_sun_shadow_media.d.ts.map +1 -0
  1228. package/src/shade/renderer/volumetrics/shader_volumetrics_bin_sun_shadow_media.js +125 -0
  1229. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  1230. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +16 -2
  1231. package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.d.ts +4 -44
  1232. package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.d.ts.map +1 -1
  1233. package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.js +558 -311
  1234. package/src/shade/renderer/volumetrics/shader_volumetrics_cull_sun_shadow_media.d.ts +18 -0
  1235. package/src/shade/renderer/volumetrics/shader_volumetrics_cull_sun_shadow_media.d.ts.map +1 -0
  1236. package/src/shade/renderer/volumetrics/shader_volumetrics_cull_sun_shadow_media.js +84 -0
  1237. package/src/shade/renderer/volumetrics/shader_volumetrics_split_participating_media.d.ts +4 -0
  1238. package/src/shade/renderer/volumetrics/shader_volumetrics_split_participating_media.d.ts.map +1 -1
  1239. package/src/shade/renderer/volumetrics/shader_volumetrics_split_participating_media.js +1 -1
  1240. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
  1241. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +5 -2
  1242. package/src/shade/renderer/water/chunk_water_gi.d.ts +2 -2
  1243. package/src/shade/renderer/water/chunk_water_gi.d.ts.map +1 -1
  1244. package/src/shade/renderer/water/chunk_water_gi.js +4 -2
  1245. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +127 -0
  1246. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts.map +1 -0
  1247. package/src/shade/renderer/water/query/GPUWaterQueries.js +741 -0
  1248. package/src/shade/renderer/water/query/WATER_QUERY_DATABASE_SPEC.d.ts +58 -0
  1249. package/src/shade/renderer/water/query/WATER_QUERY_DATABASE_SPEC.d.ts.map +1 -0
  1250. package/src/shade/renderer/water/query/WATER_QUERY_DATABASE_SPEC.js +79 -0
  1251. package/src/shade/renderer/water/query/shader_water_surface_query.d.ts +32 -0
  1252. package/src/shade/renderer/water/query/shader_water_surface_query.d.ts.map +1 -0
  1253. package/src/shade/renderer/water/query/shader_water_surface_query.js +227 -0
  1254. package/src/shade/renderer/water/shader_water_avboit.js +1 -1
  1255. package/src/shade/renderer/wind/GPUSceneWind.d.ts +1 -1
  1256. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  1257. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +272 -29
  1258. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts +6 -7
  1259. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  1260. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +289 -70
  1261. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  1262. package/src/shade/wgsl/validate_wgsl_source.js +53 -1
  1263. package/src/view/common/LabelView.js +1 -1
  1264. package/src/view/common/VirtualListView.js +1 -1
  1265. package/src/view/controller/controls/ListController.d.ts.map +1 -1
  1266. package/src/view/controller/controls/ListController.js +118 -113
  1267. package/src/view/controller/controls/Vector1Control.js +97 -97
  1268. package/src/view/elements/image/SvgImageView.d.ts +1 -0
  1269. package/src/view/elements/image/SvgImageView.d.ts.map +1 -1
  1270. package/src/view/elements/image/SvgImageView.js +92 -90
  1271. package/src/view/elements/progress/SmoothProgressBar.js +1 -1
  1272. package/src/view/minimap/dom/MinimapTerrainView.d.ts +1 -0
  1273. package/src/view/minimap/dom/MinimapTerrainView.d.ts.map +1 -1
  1274. package/src/view/minimap/dom/MinimapTerrainView.js +151 -147
  1275. package/src/view/tooltip/TooltipManager.js +1 -1
  1276. package/src/view/tooltip/gml/TooltipParser.js +2 -2
  1277. package/editor/view/ecs/components/DatGuiController.d.ts +0 -2
  1278. package/editor/view/ecs/components/DatGuiController.d.ts.map +0 -1
  1279. package/editor/view/ecs/components/DatGuiController.js +0 -2
  1280. package/editor/view/v2/SplitView.d.ts +0 -2
  1281. package/editor/view/v2/SplitView.d.ts.map +0 -1
  1282. package/editor/view/v2/SplitView.js +0 -2
  1283. package/src/core/binary/hash/XXH128Hash.d.ts +0 -2
  1284. package/src/core/binary/hash/XXH128Hash.d.ts.map +0 -1
  1285. package/src/core/binary/hash/XXH128Hash.js +0 -4
  1286. package/src/core/binary/hash/XXH3_SECRET.d.ts +0 -2
  1287. package/src/core/binary/hash/XXH3_SECRET.d.ts.map +0 -1
  1288. package/src/core/binary/hash/XXH3_SECRET.js +0 -4
  1289. package/src/core/binary/hash/crc32.d.ts +0 -2
  1290. package/src/core/binary/hash/crc32.d.ts.map +0 -1
  1291. package/src/core/binary/hash/crc32.js +0 -4
  1292. package/src/core/binary/hash/xxh3_128.d.ts +0 -2
  1293. package/src/core/binary/hash/xxh3_128.d.ts.map +0 -1
  1294. package/src/core/binary/hash/xxh3_128.js +0 -4
  1295. package/src/core/binary/hash/xxh3_64.d.ts +0 -2
  1296. package/src/core/binary/hash/xxh3_64.d.ts.map +0 -1
  1297. package/src/core/binary/hash/xxh3_64.js +0 -4
  1298. package/src/core/binary/hash/xxh3_common.d.ts +0 -2
  1299. package/src/core/binary/hash/xxh3_common.d.ts.map +0 -1
  1300. package/src/core/binary/hash/xxh3_common.js +0 -90
  1301. package/src/core/binary/lsb_32.d.ts +0 -17
  1302. package/src/core/binary/lsb_32.d.ts.map +0 -1
  1303. package/src/core/binary/lsb_32.js +0 -17
  1304. package/src/core/color/hex/hex2rgb.d.ts +0 -2
  1305. package/src/core/color/hex/hex2rgb.d.ts.map +0 -1
  1306. package/src/core/color/hex/hex2rgb.js +0 -7
  1307. package/src/core/color/hex/rgb2hex.d.ts +0 -2
  1308. package/src/core/color/hex/rgb2hex.d.ts.map +0 -1
  1309. package/src/core/color/hex/rgb2hex.js +0 -7
  1310. package/src/core/color/hsv/hsv2rgb.d.ts +0 -2
  1311. package/src/core/color/hsv/hsv2rgb.d.ts.map +0 -1
  1312. package/src/core/color/hsv/hsv2rgb.js +0 -8
  1313. package/src/core/color/hsv/rgb2hsv.d.ts +0 -2
  1314. package/src/core/color/hsv/rgb2hsv.d.ts.map +0 -1
  1315. package/src/core/color/hsv/rgb2hsv.js +0 -7
  1316. package/src/core/color/hunt/hpe_to_xyz.d.ts +0 -2
  1317. package/src/core/color/hunt/hpe_to_xyz.d.ts.map +0 -1
  1318. package/src/core/color/hunt/hpe_to_xyz.js +0 -4
  1319. package/src/core/color/hunt/xyz_to_hpe.d.ts +0 -2
  1320. package/src/core/color/hunt/xyz_to_hpe.d.ts.map +0 -1
  1321. package/src/core/color/hunt/xyz_to_hpe.js +0 -12
  1322. package/src/core/color/int2rgb.d.ts +0 -2
  1323. package/src/core/color/int2rgb.d.ts.map +0 -1
  1324. package/src/core/color/int2rgb.js +0 -7
  1325. package/src/core/color/rgb2uint24.d.ts +0 -2
  1326. package/src/core/color/rgb2uint24.d.ts.map +0 -1
  1327. package/src/core/color/rgb2uint24.js +0 -7
  1328. package/src/core/color/rgb2uint32.d.ts +0 -2
  1329. package/src/core/color/rgb2uint32.d.ts.map +0 -1
  1330. package/src/core/color/rgb2uint32.js +0 -7
  1331. package/src/core/geom/2d/aabb/aabb2_array_combine.d.ts +0 -7
  1332. package/src/core/geom/2d/aabb/aabb2_array_combine.d.ts.map +0 -1
  1333. package/src/core/geom/2d/aabb/aabb2_array_combine.js +0 -7
  1334. package/src/core/geom/2d/aabb/aabb2_compute_area.d.ts +0 -7
  1335. package/src/core/geom/2d/aabb/aabb2_compute_area.d.ts.map +0 -1
  1336. package/src/core/geom/2d/aabb/aabb2_compute_area.js +0 -7
  1337. package/src/core/geom/2d/aabb/aabb2_compute_center_from_multiple.d.ts +0 -7
  1338. package/src/core/geom/2d/aabb/aabb2_compute_center_from_multiple.d.ts.map +0 -1
  1339. package/src/core/geom/2d/aabb/aabb2_compute_center_from_multiple.js +0 -7
  1340. package/src/core/geom/2d/aabb/aabb2_compute_overlap.d.ts +0 -7
  1341. package/src/core/geom/2d/aabb/aabb2_compute_overlap.d.ts.map +0 -1
  1342. package/src/core/geom/2d/aabb/aabb2_compute_overlap.js +0 -7
  1343. package/src/core/geom/2d/aabb/aabb2_from_v2_array.d.ts +0 -7
  1344. package/src/core/geom/2d/aabb/aabb2_from_v2_array.d.ts.map +0 -1
  1345. package/src/core/geom/2d/aabb/aabb2_from_v2_array.js +0 -7
  1346. package/src/core/geom/2d/aabb/aabb2_intersects_point.d.ts +0 -7
  1347. package/src/core/geom/2d/aabb/aabb2_intersects_point.d.ts.map +0 -1
  1348. package/src/core/geom/2d/aabb/aabb2_intersects_point.js +0 -7
  1349. package/src/core/geom/2d/aabb/aabb2_overlap_exists.d.ts +0 -7
  1350. package/src/core/geom/2d/aabb/aabb2_overlap_exists.d.ts.map +0 -1
  1351. package/src/core/geom/2d/aabb/aabb2_overlap_exists.js +0 -7
  1352. package/src/core/geom/2d/circle/circle_compute_circle_intersection.d.ts +0 -7
  1353. package/src/core/geom/2d/circle/circle_compute_circle_intersection.d.ts.map +0 -1
  1354. package/src/core/geom/2d/circle/circle_compute_circle_intersection.js +0 -7
  1355. package/src/core/geom/2d/circle/circle_compute_circle_penetration.d.ts +0 -7
  1356. package/src/core/geom/2d/circle/circle_compute_circle_penetration.d.ts.map +0 -1
  1357. package/src/core/geom/2d/circle/circle_compute_circle_penetration.js +0 -7
  1358. package/src/core/geom/2d/circle/circle_intersects_point.d.ts +0 -7
  1359. package/src/core/geom/2d/circle/circle_intersects_point.d.ts.map +0 -1
  1360. package/src/core/geom/2d/circle/circle_intersects_point.js +0 -7
  1361. package/src/core/geom/2d/compute_polygon_area_2d.d.ts +0 -7
  1362. package/src/core/geom/2d/compute_polygon_area_2d.d.ts.map +0 -1
  1363. package/src/core/geom/2d/compute_polygon_area_2d.js +0 -7
  1364. package/src/core/geom/2d/convex-hull/fixed_convex_hull_humus.d.ts +0 -7
  1365. package/src/core/geom/2d/convex-hull/fixed_convex_hull_humus.d.ts.map +0 -1
  1366. package/src/core/geom/2d/convex-hull/fixed_convex_hull_humus.js +0 -7
  1367. package/src/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.d.ts +0 -7
  1368. package/src/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.d.ts.map +0 -1
  1369. package/src/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.js +0 -7
  1370. package/src/core/geom/2d/convex-hull/orientation3_array.d.ts +0 -7
  1371. package/src/core/geom/2d/convex-hull/orientation3_array.d.ts.map +0 -1
  1372. package/src/core/geom/2d/convex-hull/orientation3_array.js +0 -7
  1373. package/src/core/geom/2d/intersect_ray_2d.d.ts +0 -7
  1374. package/src/core/geom/2d/intersect_ray_2d.d.ts.map +0 -1
  1375. package/src/core/geom/2d/intersect_ray_2d.js +0 -7
  1376. package/src/core/geom/2d/line/line2_distance_to_point_sqr.d.ts +0 -7
  1377. package/src/core/geom/2d/line/line2_distance_to_point_sqr.d.ts.map +0 -1
  1378. package/src/core/geom/2d/line/line2_distance_to_point_sqr.js +0 -7
  1379. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_2d.d.ts +0 -7
  1380. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_2d.d.ts.map +0 -1
  1381. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_2d.js +0 -7
  1382. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_array_2d.d.ts +0 -7
  1383. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_array_2d.d.ts.map +0 -1
  1384. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_array_2d.js +0 -7
  1385. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_2d.d.ts +0 -7
  1386. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_2d.d.ts.map +0 -1
  1387. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_2d.js +0 -7
  1388. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_array_2d.d.ts +0 -7
  1389. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_array_2d.d.ts.map +0 -1
  1390. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_array_2d.js +0 -7
  1391. package/src/core/geom/2d/line/line_segment_intersection_fraction_2d.d.ts +0 -7
  1392. package/src/core/geom/2d/line/line_segment_intersection_fraction_2d.d.ts.map +0 -1
  1393. package/src/core/geom/2d/line/line_segment_intersection_fraction_2d.js +0 -7
  1394. package/src/core/geom/2d/line/line_segment_line_segment_intersection_exists_2d.d.ts +0 -7
  1395. package/src/core/geom/2d/line/line_segment_line_segment_intersection_exists_2d.d.ts.map +0 -1
  1396. package/src/core/geom/2d/line/line_segment_line_segment_intersection_exists_2d.js +0 -7
  1397. package/src/core/geom/2d/quad-tree/qt_query_data_nearest_to_point.d.ts +0 -7
  1398. package/src/core/geom/2d/quad-tree/qt_query_data_nearest_to_point.d.ts.map +0 -1
  1399. package/src/core/geom/2d/quad-tree/qt_query_data_nearest_to_point.js +0 -7
  1400. package/src/core/geom/2d/rectangle_to_aabb.d.ts +0 -7
  1401. package/src/core/geom/2d/rectangle_to_aabb.d.ts.map +0 -1
  1402. package/src/core/geom/2d/rectangle_to_aabb.js +0 -7
  1403. package/src/core/geom/2d/spline_bezier2_2d.d.ts +0 -7
  1404. package/src/core/geom/2d/spline_bezier2_2d.d.ts.map +0 -1
  1405. package/src/core/geom/2d/spline_bezier2_2d.js +0 -7
  1406. package/src/core/geom/2d/triangle2d_compute_area.d.ts +0 -7
  1407. package/src/core/geom/2d/triangle2d_compute_area.d.ts.map +0 -1
  1408. package/src/core/geom/2d/triangle2d_compute_area.js +0 -7
  1409. package/src/core/geom/2d/triangle2d_contains_point.d.ts +0 -7
  1410. package/src/core/geom/2d/triangle2d_contains_point.d.ts.map +0 -1
  1411. package/src/core/geom/2d/triangle2d_contains_point.js +0 -7
  1412. package/src/core/geom/2d/triangle2d_get_barycentric.d.ts +0 -7
  1413. package/src/core/geom/2d/triangle2d_get_barycentric.d.ts.map +0 -1
  1414. package/src/core/geom/2d/triangle2d_get_barycentric.js +0 -7
  1415. package/src/core/geom/3d/aabb/aabb3_array_intersects_frustum_degree.d.ts +0 -7
  1416. package/src/core/geom/3d/aabb/aabb3_array_intersects_frustum_degree.d.ts.map +0 -1
  1417. package/src/core/geom/3d/aabb/aabb3_array_intersects_frustum_degree.js +0 -7
  1418. package/src/core/geom/3d/aabb/aabb3_box_surface_area_2.d.ts +0 -7
  1419. package/src/core/geom/3d/aabb/aabb3_box_surface_area_2.d.ts.map +0 -1
  1420. package/src/core/geom/3d/aabb/aabb3_box_surface_area_2.js +0 -7
  1421. package/src/core/geom/3d/aabb/aabb3_combined_surface_area.d.ts +0 -7
  1422. package/src/core/geom/3d/aabb/aabb3_combined_surface_area.d.ts.map +0 -1
  1423. package/src/core/geom/3d/aabb/aabb3_combined_surface_area.js +0 -7
  1424. package/src/core/geom/3d/aabb/aabb3_compute_half_surface_area.d.ts +0 -7
  1425. package/src/core/geom/3d/aabb/aabb3_compute_half_surface_area.d.ts.map +0 -1
  1426. package/src/core/geom/3d/aabb/aabb3_compute_half_surface_area.js +0 -7
  1427. package/src/core/geom/3d/aabb/aabb3_compute_projected_area.d.ts +0 -7
  1428. package/src/core/geom/3d/aabb/aabb3_compute_projected_area.d.ts.map +0 -1
  1429. package/src/core/geom/3d/aabb/aabb3_compute_projected_area.js +0 -7
  1430. package/src/core/geom/3d/aabb/aabb3_compute_surface_area.d.ts +0 -7
  1431. package/src/core/geom/3d/aabb/aabb3_compute_surface_area.d.ts.map +0 -1
  1432. package/src/core/geom/3d/aabb/aabb3_compute_surface_area.js +0 -7
  1433. package/src/core/geom/3d/aabb/aabb3_detailed_volume_intersection.d.ts +0 -7
  1434. package/src/core/geom/3d/aabb/aabb3_detailed_volume_intersection.d.ts.map +0 -1
  1435. package/src/core/geom/3d/aabb/aabb3_detailed_volume_intersection.js +0 -7
  1436. package/src/core/geom/3d/aabb/aabb3_estimate_projected_area2.d.ts +0 -7
  1437. package/src/core/geom/3d/aabb/aabb3_estimate_projected_area2.d.ts.map +0 -1
  1438. package/src/core/geom/3d/aabb/aabb3_estimate_projected_area2.js +0 -7
  1439. package/src/core/geom/3d/aabb/aabb3_intersects_frustum_degree.d.ts +0 -7
  1440. package/src/core/geom/3d/aabb/aabb3_intersects_frustum_degree.d.ts.map +0 -1
  1441. package/src/core/geom/3d/aabb/aabb3_intersects_frustum_degree.js +0 -7
  1442. package/src/core/geom/3d/aabb/aabb3_intersects_line_segment.d.ts +0 -7
  1443. package/src/core/geom/3d/aabb/aabb3_intersects_line_segment.d.ts.map +0 -1
  1444. package/src/core/geom/3d/aabb/aabb3_intersects_line_segment.js +0 -7
  1445. package/src/core/geom/3d/aabb/aabb3_near_distance_to_intersection_ray_segment.d.ts +0 -7
  1446. package/src/core/geom/3d/aabb/aabb3_near_distance_to_intersection_ray_segment.d.ts.map +0 -1
  1447. package/src/core/geom/3d/aabb/aabb3_near_distance_to_intersection_ray_segment.js +0 -7
  1448. package/src/core/geom/3d/aabb/aabb3_nearest_point_on_surface.d.ts +0 -7
  1449. package/src/core/geom/3d/aabb/aabb3_nearest_point_on_surface.d.ts.map +0 -1
  1450. package/src/core/geom/3d/aabb/aabb3_nearest_point_on_surface.js +0 -7
  1451. package/src/core/geom/3d/aabb/aabb3_raycast.d.ts +0 -7
  1452. package/src/core/geom/3d/aabb/aabb3_raycast.d.ts.map +0 -1
  1453. package/src/core/geom/3d/aabb/aabb3_raycast.js +0 -7
  1454. package/src/core/geom/3d/aabb/compute_aabb_from_points.d.ts +0 -7
  1455. package/src/core/geom/3d/aabb/compute_aabb_from_points.d.ts.map +0 -1
  1456. package/src/core/geom/3d/aabb/compute_aabb_from_points.js +0 -7
  1457. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.d.ts +0 -7
  1458. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.d.ts.map +0 -1
  1459. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.js +0 -7
  1460. package/src/core/geom/3d/compute_circle_bounding_box.d.ts +0 -7
  1461. package/src/core/geom/3d/compute_circle_bounding_box.d.ts.map +0 -1
  1462. package/src/core/geom/3d/compute_circle_bounding_box.js +0 -7
  1463. package/src/core/geom/3d/cone/computeConeBoundingBox.d.ts +0 -7
  1464. package/src/core/geom/3d/cone/computeConeBoundingBox.d.ts.map +0 -1
  1465. package/src/core/geom/3d/cone/computeConeBoundingBox.js +0 -7
  1466. package/src/core/geom/3d/cone/computeConePlaneSide.d.ts +0 -7
  1467. package/src/core/geom/3d/cone/computeConePlaneSide.d.ts.map +0 -1
  1468. package/src/core/geom/3d/cone/computeConePlaneSide.js +0 -7
  1469. package/src/core/geom/3d/cone/compute_bounding_cone_of_2_cones.d.ts +0 -7
  1470. package/src/core/geom/3d/cone/compute_bounding_cone_of_2_cones.d.ts.map +0 -1
  1471. package/src/core/geom/3d/cone/compute_bounding_cone_of_2_cones.js +0 -7
  1472. package/src/core/geom/3d/frustum/clipping_volume_matrix4_project.d.ts +0 -7
  1473. package/src/core/geom/3d/frustum/clipping_volume_matrix4_project.d.ts.map +0 -1
  1474. package/src/core/geom/3d/frustum/clipping_volume_matrix4_project.js +0 -7
  1475. package/src/core/geom/3d/frustum/frustum3_computeNearestPointToPoint.d.ts +0 -7
  1476. package/src/core/geom/3d/frustum/frustum3_computeNearestPointToPoint.d.ts.map +0 -1
  1477. package/src/core/geom/3d/frustum/frustum3_computeNearestPointToPoint.js +0 -7
  1478. package/src/core/geom/3d/frustum/frustum_matrix4_project.d.ts +0 -7
  1479. package/src/core/geom/3d/frustum/frustum_matrix4_project.d.ts.map +0 -1
  1480. package/src/core/geom/3d/frustum/frustum_matrix4_project.js +0 -7
  1481. package/src/core/geom/3d/frustum/hexahedron_from_aabb.d.ts +0 -7
  1482. package/src/core/geom/3d/frustum/hexahedron_from_aabb.d.ts.map +0 -1
  1483. package/src/core/geom/3d/frustum/hexahedron_from_aabb.js +0 -7
  1484. package/src/core/geom/3d/frustum/read_three_planes_to_array.d.ts +0 -7
  1485. package/src/core/geom/3d/frustum/read_three_planes_to_array.d.ts.map +0 -1
  1486. package/src/core/geom/3d/frustum/read_three_planes_to_array.js +0 -7
  1487. package/src/core/geom/3d/frustum/slice_frustum_linear_to_points.d.ts +0 -7
  1488. package/src/core/geom/3d/frustum/slice_frustum_linear_to_points.d.ts.map +0 -1
  1489. package/src/core/geom/3d/frustum/slice_frustum_linear_to_points.js +0 -7
  1490. package/src/core/geom/3d/line/line3_closest_points_segment_segment.d.ts +0 -7
  1491. package/src/core/geom/3d/line/line3_closest_points_segment_segment.d.ts.map +0 -1
  1492. package/src/core/geom/3d/line/line3_closest_points_segment_segment.js +0 -7
  1493. package/src/core/geom/3d/line/line3_compute_nearest_point_to_point.d.ts +0 -7
  1494. package/src/core/geom/3d/line/line3_compute_nearest_point_to_point.d.ts.map +0 -1
  1495. package/src/core/geom/3d/line/line3_compute_nearest_point_to_point.js +0 -7
  1496. package/src/core/geom/3d/line/line3_compute_segment_nearest_point_to_aabb3_t.d.ts +0 -7
  1497. package/src/core/geom/3d/line/line3_compute_segment_nearest_point_to_aabb3_t.d.ts.map +0 -1
  1498. package/src/core/geom/3d/line/line3_compute_segment_nearest_point_to_aabb3_t.js +0 -7
  1499. package/src/core/geom/3d/line/line3_compute_segment_nearest_point_to_point_t.d.ts +0 -7
  1500. package/src/core/geom/3d/line/line3_compute_segment_nearest_point_to_point_t.d.ts.map +0 -1
  1501. package/src/core/geom/3d/line/line3_compute_segment_nearest_point_to_point_t.js +0 -7
  1502. package/src/core/geom/3d/mat4/allocate_m4.d.ts +0 -7
  1503. package/src/core/geom/3d/mat4/allocate_m4.d.ts.map +0 -1
  1504. package/src/core/geom/3d/mat4/allocate_m4.js +0 -7
  1505. package/src/core/geom/3d/mat4/apply_mat4_transform_to_direction_v3_array.d.ts +0 -7
  1506. package/src/core/geom/3d/mat4/apply_mat4_transform_to_direction_v3_array.d.ts.map +0 -1
  1507. package/src/core/geom/3d/mat4/apply_mat4_transform_to_direction_v3_array.js +0 -7
  1508. package/src/core/geom/3d/mat4/apply_mat4_transform_to_v3_array.d.ts +0 -7
  1509. package/src/core/geom/3d/mat4/apply_mat4_transform_to_v3_array.d.ts.map +0 -1
  1510. package/src/core/geom/3d/mat4/apply_mat4_transform_to_v3_array.js +0 -7
  1511. package/src/core/geom/3d/mat4/compose_matrix4_array.d.ts +0 -7
  1512. package/src/core/geom/3d/mat4/compose_matrix4_array.d.ts.map +0 -1
  1513. package/src/core/geom/3d/mat4/compose_matrix4_array.js +0 -7
  1514. package/src/core/geom/3d/mat4/decompose_matrix_4_array.d.ts +0 -7
  1515. package/src/core/geom/3d/mat4/decompose_matrix_4_array.d.ts.map +0 -1
  1516. package/src/core/geom/3d/mat4/decompose_matrix_4_array.js +0 -7
  1517. package/src/core/geom/3d/mat4/eulerAnglesFromMatrix.d.ts +0 -7
  1518. package/src/core/geom/3d/mat4/eulerAnglesFromMatrix.d.ts.map +0 -1
  1519. package/src/core/geom/3d/mat4/eulerAnglesFromMatrix.js +0 -7
  1520. package/src/core/geom/3d/mat4/m4_compute_normal_matrix3.d.ts +0 -7
  1521. package/src/core/geom/3d/mat4/m4_compute_normal_matrix3.d.ts.map +0 -1
  1522. package/src/core/geom/3d/mat4/m4_compute_normal_matrix3.js +0 -7
  1523. package/src/core/geom/3d/morton/mortonEncode_LUT.d.ts +0 -7
  1524. package/src/core/geom/3d/morton/mortonEncode_LUT.d.ts.map +0 -1
  1525. package/src/core/geom/3d/morton/mortonEncode_LUT.js +0 -7
  1526. package/src/core/geom/3d/morton/mortonEncode_magicbits.d.ts +0 -7
  1527. package/src/core/geom/3d/morton/mortonEncode_magicbits.d.ts.map +0 -1
  1528. package/src/core/geom/3d/morton/mortonEncode_magicbits.js +0 -7
  1529. package/src/core/geom/3d/normal/hemioct/encode_unit3_hemioct.d.ts +0 -2
  1530. package/src/core/geom/3d/normal/hemioct/encode_unit3_hemioct.d.ts.map +0 -1
  1531. package/src/core/geom/3d/normal/hemioct/encode_unit3_hemioct.js +0 -5
  1532. package/src/core/geom/3d/plane/is_point_within_planes.d.ts +0 -7
  1533. package/src/core/geom/3d/plane/is_point_within_planes.d.ts.map +0 -1
  1534. package/src/core/geom/3d/plane/is_point_within_planes.js +0 -7
  1535. package/src/core/geom/3d/plane/plane3_compute_convex_3_plane_intersection.d.ts +0 -7
  1536. package/src/core/geom/3d/plane/plane3_compute_convex_3_plane_intersection.d.ts.map +0 -1
  1537. package/src/core/geom/3d/plane/plane3_compute_convex_3_plane_intersection.js +0 -7
  1538. package/src/core/geom/3d/plane/plane3_compute_plane_intersection.d.ts +0 -7
  1539. package/src/core/geom/3d/plane/plane3_compute_plane_intersection.d.ts.map +0 -1
  1540. package/src/core/geom/3d/plane/plane3_compute_plane_intersection.js +0 -7
  1541. package/src/core/geom/3d/plane/plane3_intersect_plane.d.ts +0 -7
  1542. package/src/core/geom/3d/plane/plane3_intersect_plane.d.ts.map +0 -1
  1543. package/src/core/geom/3d/plane/plane3_intersect_plane.js +0 -7
  1544. package/src/core/geom/3d/plane/plane3_three_compute_convex_3_plane_intersection.d.ts +0 -7
  1545. package/src/core/geom/3d/plane/plane3_three_compute_convex_3_plane_intersection.d.ts.map +0 -1
  1546. package/src/core/geom/3d/plane/plane3_three_compute_convex_3_plane_intersection.js +0 -7
  1547. package/src/core/geom/3d/quaternion/quat3_createFromAxisAngle.d.ts +0 -7
  1548. package/src/core/geom/3d/quaternion/quat3_createFromAxisAngle.d.ts.map +0 -1
  1549. package/src/core/geom/3d/quaternion/quat3_createFromAxisAngle.js +0 -7
  1550. package/src/core/geom/3d/quaternion/quat_decode_from_uint32.d.ts +0 -7
  1551. package/src/core/geom/3d/quaternion/quat_decode_from_uint32.d.ts.map +0 -1
  1552. package/src/core/geom/3d/quaternion/quat_decode_from_uint32.js +0 -7
  1553. package/src/core/geom/3d/quaternion/quat_encode_to_uint32.d.ts +0 -7
  1554. package/src/core/geom/3d/quaternion/quat_encode_to_uint32.d.ts.map +0 -1
  1555. package/src/core/geom/3d/quaternion/quat_encode_to_uint32.js +0 -7
  1556. package/src/core/geom/3d/ray/ray3_array_compose.d.ts +0 -7
  1557. package/src/core/geom/3d/ray/ray3_array_compose.d.ts.map +0 -1
  1558. package/src/core/geom/3d/ray/ray3_array_compose.js +0 -7
  1559. package/src/core/geom/3d/ray/ray3_compute_nearest_point_to_point.d.ts +0 -7
  1560. package/src/core/geom/3d/ray/ray3_compute_nearest_point_to_point.d.ts.map +0 -1
  1561. package/src/core/geom/3d/ray/ray3_compute_nearest_point_to_point.js +0 -7
  1562. package/src/core/geom/3d/ray/ray3_distance_to_point.d.ts +0 -7
  1563. package/src/core/geom/3d/ray/ray3_distance_to_point.d.ts.map +0 -1
  1564. package/src/core/geom/3d/ray/ray3_distance_to_point.js +0 -7
  1565. package/src/core/geom/3d/ray/ray3_shift_origin_along_direction.d.ts +0 -7
  1566. package/src/core/geom/3d/ray/ray3_shift_origin_along_direction.d.ts.map +0 -1
  1567. package/src/core/geom/3d/ray/ray3_shift_origin_along_direction.js +0 -7
  1568. package/src/core/geom/3d/shape/shape_mesh_from_geometry.d.ts +0 -7
  1569. package/src/core/geom/3d/shape/shape_mesh_from_geometry.d.ts.map +0 -1
  1570. package/src/core/geom/3d/shape/shape_mesh_from_geometry.js +0 -7
  1571. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.d.ts +0 -7
  1572. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.d.ts.map +0 -1
  1573. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.js +0 -7
  1574. package/src/core/geom/3d/sphere/compute_bounding_sphere_of_2_spheres.d.ts +0 -7
  1575. package/src/core/geom/3d/sphere/compute_bounding_sphere_of_2_spheres.d.ts.map +0 -1
  1576. package/src/core/geom/3d/sphere/compute_bounding_sphere_of_2_spheres.js +0 -7
  1577. package/src/core/geom/3d/sphere/harmonics/sh3_rotate_bl.d.ts +0 -7
  1578. package/src/core/geom/3d/sphere/harmonics/sh3_rotate_bl.d.ts.map +0 -1
  1579. package/src/core/geom/3d/sphere/harmonics/sh3_rotate_bl.js +0 -7
  1580. package/src/core/geom/3d/sphere/harmonics/sh_compute_K.d.ts +0 -7
  1581. package/src/core/geom/3d/sphere/harmonics/sh_compute_K.d.ts.map +0 -1
  1582. package/src/core/geom/3d/sphere/harmonics/sh_compute_K.js +0 -7
  1583. package/src/core/geom/3d/sphere/sphere_array_intersects_point.d.ts +0 -7
  1584. package/src/core/geom/3d/sphere/sphere_array_intersects_point.d.ts.map +0 -1
  1585. package/src/core/geom/3d/sphere/sphere_array_intersects_point.js +0 -7
  1586. package/src/core/geom/3d/sphere/sphere_array_intersects_ray.d.ts +0 -7
  1587. package/src/core/geom/3d/sphere/sphere_array_intersects_ray.d.ts.map +0 -1
  1588. package/src/core/geom/3d/sphere/sphere_array_intersects_ray.js +0 -7
  1589. package/src/core/geom/3d/sphere/sphere_intersects_point.d.ts +0 -7
  1590. package/src/core/geom/3d/sphere/sphere_intersects_point.d.ts.map +0 -1
  1591. package/src/core/geom/3d/sphere/sphere_intersects_point.js +0 -7
  1592. package/src/core/geom/3d/sphere/sphere_projected_sphere_radius_sqr.d.ts +0 -7
  1593. package/src/core/geom/3d/sphere/sphere_projected_sphere_radius_sqr.d.ts.map +0 -1
  1594. package/src/core/geom/3d/sphere/sphere_projected_sphere_radius_sqr.js +0 -7
  1595. package/src/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.d.ts +0 -7
  1596. package/src/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.d.ts.map +0 -1
  1597. package/src/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.js +0 -7
  1598. package/src/core/geom/3d/sphere/spherical_from_cartesian.d.ts +0 -7
  1599. package/src/core/geom/3d/sphere/spherical_from_cartesian.d.ts.map +0 -1
  1600. package/src/core/geom/3d/sphere/spherical_from_cartesian.js +0 -7
  1601. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.d.ts +0 -7
  1602. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.d.ts.map +0 -1
  1603. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.js +0 -7
  1604. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_volume.d.ts +0 -7
  1605. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_volume.d.ts.map +0 -1
  1606. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_volume.js +0 -7
  1607. package/src/core/geom/3d/tetrahedra/delaunay/fill_in_a_cavity.d.ts +0 -7
  1608. package/src/core/geom/3d/tetrahedra/delaunay/fill_in_a_cavity.d.ts.map +0 -1
  1609. package/src/core/geom/3d/tetrahedra/delaunay/fill_in_a_cavity.js +0 -7
  1610. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_tet_get_neighbours.d.ts +0 -7
  1611. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_tet_get_neighbours.d.ts.map +0 -1
  1612. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_tet_get_neighbours.js +0 -7
  1613. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.d.ts +0 -7
  1614. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.d.ts.map +0 -1
  1615. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.js +0 -7
  1616. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_kill_only_vert.d.ts +0 -7
  1617. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_kill_only_vert.d.ts.map +0 -1
  1618. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_kill_only_vert.js +0 -7
  1619. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_merge_verts_by_distance.d.ts +0 -7
  1620. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_merge_verts_by_distance.d.ts.map +0 -1
  1621. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_merge_verts_by_distance.js +0 -7
  1622. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.d.ts +0 -7
  1623. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.d.ts.map +0 -1
  1624. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.js +0 -7
  1625. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_kill.d.ts +0 -7
  1626. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_kill.d.ts.map +0 -1
  1627. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_kill.js +0 -7
  1628. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_attached_faces.d.ts +0 -7
  1629. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_attached_faces.d.ts.map +0 -1
  1630. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_attached_faces.js +0 -7
  1631. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_neighbour_faces.d.ts +0 -7
  1632. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_neighbour_faces.d.ts.map +0 -1
  1633. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_neighbour_faces.js +0 -7
  1634. package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.d.ts +0 -7
  1635. package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.d.ts.map +0 -1
  1636. package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.js +0 -7
  1637. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_count_edge_faces.d.ts +0 -8
  1638. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_count_edge_faces.d.ts.map +0 -1
  1639. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_count_edge_faces.js +0 -8
  1640. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.d.ts +0 -7
  1641. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.d.ts.map +0 -1
  1642. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.js +0 -7
  1643. package/src/core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.d.ts +0 -7
  1644. package/src/core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.d.ts.map +0 -1
  1645. package/src/core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.js +0 -7
  1646. package/src/core/geom/3d/triangle/computeTriangleRayIntersection.d.ts +0 -7
  1647. package/src/core/geom/3d/triangle/computeTriangleRayIntersection.d.ts.map +0 -1
  1648. package/src/core/geom/3d/triangle/computeTriangleRayIntersection.js +0 -7
  1649. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentric.d.ts +0 -7
  1650. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentric.d.ts.map +0 -1
  1651. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentric.js +0 -7
  1652. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricEdge.d.ts +0 -7
  1653. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricEdge.d.ts.map +0 -1
  1654. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricEdge.js +0 -7
  1655. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricGeometry.d.ts +0 -7
  1656. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricGeometry.d.ts.map +0 -1
  1657. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricGeometry.js +0 -7
  1658. package/src/core/geom/3d/triangle/compute_triangle_area_3d.d.ts +0 -7
  1659. package/src/core/geom/3d/triangle/compute_triangle_area_3d.d.ts.map +0 -1
  1660. package/src/core/geom/3d/triangle/compute_triangle_area_3d.js +0 -7
  1661. package/src/core/geom/3d/triangle/compute_triangle_normal.d.ts +0 -7
  1662. package/src/core/geom/3d/triangle/compute_triangle_normal.d.ts.map +0 -1
  1663. package/src/core/geom/3d/triangle/compute_triangle_normal.js +0 -7
  1664. package/src/core/geom/3d/triangle/rayTriangleIntersection.d.ts +0 -7
  1665. package/src/core/geom/3d/triangle/rayTriangleIntersection.d.ts.map +0 -1
  1666. package/src/core/geom/3d/triangle/rayTriangleIntersection.js +0 -7
  1667. package/src/core/geom/3d/triangle/triangle3_incenter.d.ts +0 -7
  1668. package/src/core/geom/3d/triangle/triangle3_incenter.d.ts.map +0 -1
  1669. package/src/core/geom/3d/triangle/triangle3_incenter.js +0 -7
  1670. package/src/core/geom/3d/triangle/triangle_compute_plane_side.d.ts +0 -7
  1671. package/src/core/geom/3d/triangle/triangle_compute_plane_side.d.ts.map +0 -1
  1672. package/src/core/geom/3d/triangle/triangle_compute_plane_side.js +0 -7
  1673. package/src/core/geom/3d/triangle/triangle_compute_signed_volume.d.ts +0 -7
  1674. package/src/core/geom/3d/triangle/triangle_compute_signed_volume.d.ts.map +0 -1
  1675. package/src/core/geom/3d/triangle/triangle_compute_signed_volume.js +0 -7
  1676. package/src/core/geom/3d/triangle/triangle_intersects_clipping_volume.d.ts +0 -7
  1677. package/src/core/geom/3d/triangle/triangle_intersects_clipping_volume.d.ts.map +0 -1
  1678. package/src/core/geom/3d/triangle/triangle_intersects_clipping_volume.js +0 -7
  1679. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.d.ts +0 -7
  1680. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.d.ts.map +0 -1
  1681. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.js +0 -7
  1682. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.d.ts +0 -7
  1683. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.d.ts.map +0 -1
  1684. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.js +0 -7
  1685. package/src/core/geom/3d/util/make_justified_point_grid.d.ts +0 -7
  1686. package/src/core/geom/3d/util/make_justified_point_grid.d.ts.map +0 -1
  1687. package/src/core/geom/3d/util/make_justified_point_grid.js +0 -7
  1688. package/src/core/geom/mat3/m3_cm_from_translation.d.ts +0 -7
  1689. package/src/core/geom/mat3/m3_cm_from_translation.d.ts.map +0 -1
  1690. package/src/core/geom/mat3/m3_cm_from_translation.js +0 -7
  1691. package/src/core/geom/mat3/m3_cm_invert.d.ts +0 -7
  1692. package/src/core/geom/mat3/m3_cm_invert.d.ts.map +0 -1
  1693. package/src/core/geom/mat3/m3_cm_invert.js +0 -7
  1694. package/src/core/geom/mat3/m3_make_rotation.d.ts +0 -2
  1695. package/src/core/geom/mat3/m3_make_rotation.d.ts.map +0 -1
  1696. package/src/core/geom/mat3/m3_make_rotation.js +0 -5
  1697. package/src/core/geom/mat3/m3_multiply_vec3.d.ts +0 -7
  1698. package/src/core/geom/mat3/m3_multiply_vec3.d.ts.map +0 -1
  1699. package/src/core/geom/mat3/m3_multiply_vec3.js +0 -7
  1700. package/src/core/geom/packing/computeBoundingSphereOfSpheres.d.ts +0 -7
  1701. package/src/core/geom/packing/computeBoundingSphereOfSpheres.d.ts.map +0 -1
  1702. package/src/core/geom/packing/computeBoundingSphereOfSpheres.js +0 -7
  1703. package/src/core/geom/packing/max-rect/cost/costByBestShortSide.d.ts +0 -7
  1704. package/src/core/geom/packing/max-rect/cost/costByBestShortSide.d.ts.map +0 -1
  1705. package/src/core/geom/packing/max-rect/cost/costByBestShortSide.js +0 -7
  1706. package/src/core/geom/packing/max-rect/cost/costByRemainingArea.d.ts +0 -7
  1707. package/src/core/geom/packing/max-rect/cost/costByRemainingArea.d.ts.map +0 -1
  1708. package/src/core/geom/packing/max-rect/cost/costByRemainingArea.js +0 -7
  1709. package/src/core/geom/packing/max-rect/cutArea.d.ts +0 -7
  1710. package/src/core/geom/packing/max-rect/cutArea.d.ts.map +0 -1
  1711. package/src/core/geom/packing/max-rect/cutArea.js +0 -7
  1712. package/src/core/geom/packing/max-rect/findBestContainer.d.ts +0 -7
  1713. package/src/core/geom/packing/max-rect/findBestContainer.d.ts.map +0 -1
  1714. package/src/core/geom/packing/max-rect/findBestContainer.js +0 -7
  1715. package/src/core/geom/packing/max-rect/packMaxRectangles.d.ts +0 -7
  1716. package/src/core/geom/packing/max-rect/packMaxRectangles.d.ts.map +0 -1
  1717. package/src/core/geom/packing/max-rect/packMaxRectangles.js +0 -7
  1718. package/src/core/geom/packing/max-rect/packOneBox.d.ts +0 -7
  1719. package/src/core/geom/packing/max-rect/packOneBox.d.ts.map +0 -1
  1720. package/src/core/geom/packing/max-rect/packOneBox.js +0 -7
  1721. package/src/core/geom/packing/max-rect/removeRedundantBoxes.d.ts +0 -7
  1722. package/src/core/geom/packing/max-rect/removeRedundantBoxes.d.ts.map +0 -1
  1723. package/src/core/geom/packing/max-rect/removeRedundantBoxes.js +0 -7
  1724. package/src/core/geom/packing/max-rect/removeRedundantBoxesArray.d.ts +0 -7
  1725. package/src/core/geom/packing/max-rect/removeRedundantBoxesArray.d.ts.map +0 -1
  1726. package/src/core/geom/packing/max-rect/removeRedundantBoxesArray.js +0 -7
  1727. package/src/core/geom/random/randomPointInBox.d.ts +0 -7
  1728. package/src/core/geom/random/randomPointInBox.d.ts.map +0 -1
  1729. package/src/core/geom/random/randomPointInBox.js +0 -7
  1730. package/src/core/geom/random/randomPointInCircle.d.ts +0 -7
  1731. package/src/core/geom/random/randomPointInCircle.d.ts.map +0 -1
  1732. package/src/core/geom/random/randomPointInCircle.js +0 -7
  1733. package/src/core/geom/random/randomPointInPoint.d.ts +0 -7
  1734. package/src/core/geom/random/randomPointInPoint.d.ts.map +0 -1
  1735. package/src/core/geom/random/randomPointInPoint.js +0 -7
  1736. package/src/core/geom/random/randomPointInSphere.d.ts +0 -7
  1737. package/src/core/geom/random/randomPointInSphere.d.ts.map +0 -1
  1738. package/src/core/geom/random/randomPointInSphere.js +0 -7
  1739. package/src/core/geom/random/randomPointOnBox.d.ts +0 -7
  1740. package/src/core/geom/random/randomPointOnBox.d.ts.map +0 -1
  1741. package/src/core/geom/random/randomPointOnBox.js +0 -7
  1742. package/src/core/geom/random/randomPointOnSphere.d.ts +0 -7
  1743. package/src/core/geom/random/randomPointOnSphere.d.ts.map +0 -1
  1744. package/src/core/geom/random/randomPointOnSphere.js +0 -7
  1745. package/src/core/geom/vec/vector_copy.d.ts +0 -7
  1746. package/src/core/geom/vec/vector_copy.d.ts.map +0 -1
  1747. package/src/core/geom/vec/vector_copy.js +0 -7
  1748. package/src/core/geom/vec/vector_scale_array.d.ts +0 -7
  1749. package/src/core/geom/vec/vector_scale_array.d.ts.map +0 -1
  1750. package/src/core/geom/vec/vector_scale_array.js +0 -7
  1751. package/src/core/geom/vec3/v3_angle_atan2_between.d.ts +0 -7
  1752. package/src/core/geom/vec3/v3_angle_atan2_between.d.ts.map +0 -1
  1753. package/src/core/geom/vec3/v3_angle_atan2_between.js +0 -7
  1754. package/src/core/geom/vec3/v3_angle_between.d.ts +0 -7
  1755. package/src/core/geom/vec3/v3_angle_between.d.ts.map +0 -1
  1756. package/src/core/geom/vec3/v3_angle_between.js +0 -7
  1757. package/src/core/geom/vec3/v3_angle_cos_between.d.ts +0 -7
  1758. package/src/core/geom/vec3/v3_angle_cos_between.d.ts.map +0 -1
  1759. package/src/core/geom/vec3/v3_angle_cos_between.js +0 -7
  1760. package/src/core/geom/vec3/v3_array_add_in_place.d.ts +0 -7
  1761. package/src/core/geom/vec3/v3_array_add_in_place.d.ts.map +0 -1
  1762. package/src/core/geom/vec3/v3_array_add_in_place.js +0 -7
  1763. package/src/core/geom/vec3/v3_array_centroid.d.ts +0 -7
  1764. package/src/core/geom/vec3/v3_array_centroid.d.ts.map +0 -1
  1765. package/src/core/geom/vec3/v3_array_centroid.js +0 -7
  1766. package/src/core/geom/vec3/v3_array_copy.d.ts +0 -7
  1767. package/src/core/geom/vec3/v3_array_copy.d.ts.map +0 -1
  1768. package/src/core/geom/vec3/v3_array_copy.js +0 -7
  1769. package/src/core/geom/vec3/v3_array_displace_in_direction.d.ts +0 -7
  1770. package/src/core/geom/vec3/v3_array_displace_in_direction.d.ts.map +0 -1
  1771. package/src/core/geom/vec3/v3_array_displace_in_direction.js +0 -7
  1772. package/src/core/geom/vec3/v3_array_equals.d.ts +0 -7
  1773. package/src/core/geom/vec3/v3_array_equals.d.ts.map +0 -1
  1774. package/src/core/geom/vec3/v3_array_equals.js +0 -7
  1775. package/src/core/geom/vec3/v3_array_immediate_add.d.ts +0 -7
  1776. package/src/core/geom/vec3/v3_array_immediate_add.d.ts.map +0 -1
  1777. package/src/core/geom/vec3/v3_array_immediate_add.js +0 -7
  1778. package/src/core/geom/vec3/v3_array_matrix4_rotate.d.ts +0 -7
  1779. package/src/core/geom/vec3/v3_array_matrix4_rotate.d.ts.map +0 -1
  1780. package/src/core/geom/vec3/v3_array_matrix4_rotate.js +0 -7
  1781. package/src/core/geom/vec3/v3_array_normalize.d.ts +0 -7
  1782. package/src/core/geom/vec3/v3_array_normalize.d.ts.map +0 -1
  1783. package/src/core/geom/vec3/v3_array_normalize.js +0 -7
  1784. package/src/core/geom/vec3/v3_array_scale.d.ts +0 -7
  1785. package/src/core/geom/vec3/v3_array_scale.d.ts.map +0 -1
  1786. package/src/core/geom/vec3/v3_array_scale.js +0 -7
  1787. package/src/core/geom/vec3/v3_compute_interior_angle.d.ts +0 -7
  1788. package/src/core/geom/vec3/v3_compute_interior_angle.d.ts.map +0 -1
  1789. package/src/core/geom/vec3/v3_compute_interior_angle.js +0 -7
  1790. package/src/core/geom/vec3/v3_dot_array_array.d.ts +0 -7
  1791. package/src/core/geom/vec3/v3_dot_array_array.d.ts.map +0 -1
  1792. package/src/core/geom/vec3/v3_dot_array_array.js +0 -7
  1793. package/src/core/geom/vec3/v3_matrix4_rotate.d.ts +0 -7
  1794. package/src/core/geom/vec3/v3_matrix4_rotate.d.ts.map +0 -1
  1795. package/src/core/geom/vec3/v3_matrix4_rotate.js +0 -7
  1796. package/src/core/geom/vec3/v3_multiply_scalar.d.ts +0 -7
  1797. package/src/core/geom/vec3/v3_multiply_scalar.d.ts.map +0 -1
  1798. package/src/core/geom/vec3/v3_multiply_scalar.js +0 -7
  1799. package/src/core/geom/vec3/v3_quat3_apply.d.ts +0 -7
  1800. package/src/core/geom/vec3/v3_quat3_apply.d.ts.map +0 -1
  1801. package/src/core/geom/vec3/v3_quat3_apply.js +0 -7
  1802. package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts +0 -7
  1803. package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts.map +0 -1
  1804. package/src/core/geom/vec3/v3_quat3_apply_inverse.js +0 -7
  1805. package/src/core/geom/vec3/v3_triple_cross_product.d.ts +0 -7
  1806. package/src/core/geom/vec3/v3_triple_cross_product.d.ts.map +0 -1
  1807. package/src/core/geom/vec3/v3_triple_cross_product.js +0 -7
  1808. package/src/core/geom/vec4/v4_multiply_mat4.d.ts +0 -7
  1809. package/src/core/geom/vec4/v4_multiply_mat4.d.ts.map +0 -1
  1810. package/src/core/geom/vec4/v4_multiply_mat4.js +0 -7
  1811. package/src/core/math/fabsf.d.ts +0 -6
  1812. package/src/core/math/fabsf.d.ts.map +0 -1
  1813. package/src/core/math/fabsf.js +0 -6
  1814. package/src/core/model/object/optional_equality.d.ts +0 -10
  1815. package/src/core/model/object/optional_equality.d.ts.map +0 -1
  1816. package/src/core/model/object/optional_equality.js +0 -27
  1817. package/src/core/primitives/strings/string_compute_byte_size.d.ts +0 -7
  1818. package/src/core/primitives/strings/string_compute_byte_size.d.ts.map +0 -1
  1819. package/src/core/primitives/strings/string_compute_byte_size.js +0 -21
  1820. package/src/engine/graphics/FrameThrottle.d.ts +0 -2
  1821. package/src/engine/graphics/FrameThrottle.d.ts.map +0 -1
  1822. package/src/engine/graphics/FrameThrottle.js +0 -2
  1823. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.d.ts +0 -2
  1824. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.d.ts.map +0 -1
  1825. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.js +0 -2
  1826. package/src/engine/graphics/texture/isImageBitmap.d.ts +0 -2
  1827. package/src/engine/graphics/texture/isImageBitmap.d.ts.map +0 -1
  1828. package/src/engine/graphics/texture/isImageBitmap.js +0 -2
  1829. package/src/engine/graphics3/AnimationGraphSystem3.d.ts +0 -10
  1830. package/src/engine/graphics3/AnimationGraphSystem3.d.ts.map +0 -1
  1831. package/src/engine/graphics3/AnimationGraphSystem3.js +0 -10
  1832. package/src/engine/graphics3/AnimationSystem3.d.ts +0 -10
  1833. package/src/engine/graphics3/AnimationSystem3.d.ts.map +0 -1
  1834. package/src/engine/graphics3/AnimationSystem3.js +0 -10
  1835. package/src/engine/graphics3/CameraSystem3.d.ts +0 -10
  1836. package/src/engine/graphics3/CameraSystem3.d.ts.map +0 -1
  1837. package/src/engine/graphics3/CameraSystem3.js +0 -10
  1838. package/src/engine/graphics3/DebugDrawSystem3.d.ts +0 -10
  1839. package/src/engine/graphics3/DebugDrawSystem3.d.ts.map +0 -1
  1840. package/src/engine/graphics3/DebugDrawSystem3.js +0 -10
  1841. package/src/engine/graphics3/DecalSystem3.d.ts +0 -10
  1842. package/src/engine/graphics3/DecalSystem3.d.ts.map +0 -1
  1843. package/src/engine/graphics3/DecalSystem3.js +0 -10
  1844. package/src/engine/graphics3/FogOfWarSystem3.d.ts +0 -10
  1845. package/src/engine/graphics3/FogOfWarSystem3.d.ts.map +0 -1
  1846. package/src/engine/graphics3/FogOfWarSystem3.js +0 -10
  1847. package/src/engine/graphics3/GraphicsEngine3.d.ts +0 -10
  1848. package/src/engine/graphics3/GraphicsEngine3.d.ts.map +0 -1
  1849. package/src/engine/graphics3/GraphicsEngine3.js +0 -10
  1850. package/src/engine/graphics3/HighlightSystem.d.ts +0 -19
  1851. package/src/engine/graphics3/HighlightSystem.d.ts.map +0 -1
  1852. package/src/engine/graphics3/HighlightSystem.js +0 -27
  1853. package/src/engine/graphics3/HighlightSystem3.d.ts +0 -13
  1854. package/src/engine/graphics3/HighlightSystem3.d.ts.map +0 -1
  1855. package/src/engine/graphics3/HighlightSystem3.js +0 -15
  1856. package/src/engine/graphics3/LightSystem3.d.ts +0 -10
  1857. package/src/engine/graphics3/LightSystem3.d.ts.map +0 -1
  1858. package/src/engine/graphics3/LightSystem3.js +0 -10
  1859. package/src/engine/graphics3/MeshSystem3.d.ts +0 -10
  1860. package/src/engine/graphics3/MeshSystem3.d.ts.map +0 -1
  1861. package/src/engine/graphics3/MeshSystem3.js +0 -10
  1862. package/src/engine/graphics3/ParticipatingMediaSystem3.d.ts +0 -10
  1863. package/src/engine/graphics3/ParticipatingMediaSystem3.d.ts.map +0 -1
  1864. package/src/engine/graphics3/ParticipatingMediaSystem3.js +0 -10
  1865. package/src/engine/graphics3/PathDisplaySystem3.d.ts +0 -10
  1866. package/src/engine/graphics3/PathDisplaySystem3.d.ts.map +0 -1
  1867. package/src/engine/graphics3/PathDisplaySystem3.js +0 -10
  1868. package/src/engine/graphics3/PickingSystem3.d.ts +0 -10
  1869. package/src/engine/graphics3/PickingSystem3.d.ts.map +0 -1
  1870. package/src/engine/graphics3/PickingSystem3.js +0 -10
  1871. package/src/engine/graphics3/ShadedGeometrySystem3.d.ts +0 -10
  1872. package/src/engine/graphics3/ShadedGeometrySystem3.d.ts.map +0 -1
  1873. package/src/engine/graphics3/ShadedGeometrySystem3.js +0 -10
  1874. package/src/engine/graphics3/TerrainSystem3.d.ts +0 -10
  1875. package/src/engine/graphics3/TerrainSystem3.d.ts.map +0 -1
  1876. package/src/engine/graphics3/TerrainSystem3.js +0 -10
  1877. package/src/engine/graphics3/TooltipComponentSystem3.d.ts +0 -10
  1878. package/src/engine/graphics3/TooltipComponentSystem3.d.ts.map +0 -1
  1879. package/src/engine/graphics3/TooltipComponentSystem3.js +0 -10
  1880. package/src/engine/graphics3/Trail3DSystem3.d.ts +0 -10
  1881. package/src/engine/graphics3/Trail3DSystem3.d.ts.map +0 -1
  1882. package/src/engine/graphics3/Trail3DSystem3.js +0 -10
  1883. package/src/engine/graphics3/VolumetricLightMapSystem3.d.ts +0 -10
  1884. package/src/engine/graphics3/VolumetricLightMapSystem3.d.ts.map +0 -1
  1885. package/src/engine/graphics3/VolumetricLightMapSystem3.js +0 -10
  1886. package/src/engine/graphics3/WaterSystem3.d.ts +0 -10
  1887. package/src/engine/graphics3/WaterSystem3.d.ts.map +0 -1
  1888. package/src/engine/graphics3/WaterSystem3.js +0 -10
  1889. package/src/engine/network/PriorityFetch.d.ts +0 -59
  1890. package/src/engine/network/PriorityFetch.d.ts.map +0 -1
  1891. package/src/engine/network/PriorityFetch.js +0 -193
  1892. package/src/engine/network/convertPathToURL.d.ts +0 -2
  1893. package/src/engine/network/convertPathToURL.d.ts.map +0 -1
  1894. package/src/engine/network/convertPathToURL.js +0 -2
  1895. package/src/format/image/png/crc32.d.ts +0 -2
  1896. package/src/format/image/png/crc32.d.ts.map +0 -1
  1897. package/src/format/image/png/crc32.js +0 -7
  1898. package/src/generation/foliage/config/BranchLevelConfig.d.ts +0 -288
  1899. package/src/generation/foliage/config/BranchLevelConfig.d.ts.map +0 -1
  1900. package/src/generation/foliage/config/BranchLevelConfig.js +0 -536
  1901. package/src/shade/renderer/camera/OrbitalCameraController.d.ts +0 -63
  1902. package/src/shade/renderer/camera/OrbitalCameraController.d.ts.map +0 -1
  1903. package/src/shade/renderer/camera/OrbitalCameraController.js +0 -374
  1904. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_heavy.d.ts +0 -16
  1905. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_heavy.d.ts.map +0 -1
  1906. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_heavy.js +0 -17
  1907. package/src/shade/renderer/geometry/sdf/SDF_BUILD_SETTINGS_STRUCT.js +0 -8
  1908. package/src/shade/renderer/geometry/sdf/SFD_BUILD_WORKGROUP_SIZE.js +0 -1
  1909. package/src/shade/renderer/geometry/sdf/chunk_blas_query_sdf.js +0 -49
  1910. package/src/shade/renderer/geometry/sdf/chunk_blas_query_volume_sign.js +0 -90
  1911. package/src/shade/renderer/geometry/sdf/shader_build_sdf.js +0 -126
  1912. package/src/shade/renderer/light/environment/octahedral_uv_to_direction.d.ts +0 -8
  1913. package/src/shade/renderer/light/environment/octahedral_uv_to_direction.d.ts.map +0 -1
  1914. package/src/shade/renderer/light/environment/octahedral_uv_to_direction.js +0 -10
  1915. package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.js +0 -62
  1916. package/src/shade/renderer/shadow/vsm/VSMMoverTracker.js +0 -153
  1917. package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.js +0 -75
  1918. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.js +0 -32
  1919. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.js +0 -184
  1920. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.js +0 -109
@@ -0,0 +1,2677 @@
1
+ # Probe clipmap GI — proposal, 2026-10-27
2
+
3
+ Status: **revision (b): Alex's review of (a) applied, and his answers on every fork. Nothing is
4
+ built.** Written against `4a3a41928`. Paths are relative to `packages/meep-engine/src/`. No fork is
5
+ open; §15 records how each was settled.
6
+
7
+ ## What changed from (a)
8
+
9
+ Alex reviewed revision (a). Items 1–8 are his; item 9 follows from them.
10
+
11
+ 1. **No triangle work per frame.** Every mesh is cached once as a sparse, NanoVDB-style SDF in size
12
+ classes: 2×2×2 bricks at least, then steps of two bricks per axis (§6.2). World bricks are
13
+ composed from those caches (§7.7). (a) gathered triangles per cell.
14
+ 2. **Material comes from a surface cache of cards**, Unreal's idea, with Lumen's payload: diffuse
15
+ albedo and emissive captured per (geometry, material) pair, and recaptured when the material
16
+ changes (§6.5, §6.6).
17
+ - (a) stored a voxel material lattice, which is expensive.
18
+ - The path tracer's material needs uvs, which an SDF cannot give.
19
+ - Cards holding uvs, with the material evaluated live, were offered as an alternative. Alex chose
20
+ the captured material.
21
+ 3. **A primitive can be absent from the SDF world**: drawn by the camera, invisible to GI, for
22
+ performance (§6.1).
23
+ 4. **Brick providers.** A pass that writes requested bricks plugs in; outputs merge per brick, so the
24
+ representation stays sparse and only bricks that scroll in or change are written. Virtual geometry
25
+ is served by one (§7.6, §7.8).
26
+ 5. **Skinned meshes** use their unskinned representation, with hooks for a dense animated patch later
27
+ (§6.3, §7.7, §17).
28
+ 6. **Pixels pick 2 of the 8 cage probes** by Brick4's weighted reservoir sampling, after a
29
+ visibility-only weight pass; only the two are read (§9.1). (a) evaluated all eight.
30
+ 7. **Rough specular blends the radiance tap with GGX-convolved SH2** (§9.3). (a)'s prefiltered
31
+ radiance levels sit badly with WebGPU's mip limits.
32
+ 8. **`GPUGeometrySDFManager` worked and is correct**: it is the bake's reference, generalised in place
33
+ (§6). The Brixelizer port is a reference, not reused.
34
+ 9. **The field is signed** (D2). (a) chose unsigned because a per-cell triangle gather cannot tell
35
+ inside from outside. A whole-mesh bake can, so (a)'s fork 2 dissolves.
36
+ 10. **(a)'s two other forks were taken as recommended**: a sparse probe cache (D31), and the mover
37
+ list at scene level with a skinned bit (D32).
38
+
39
+ What was asked for:
40
+
41
+ - A real-time GI built on 3-D clipmaps, selected by a new value of `ShadeIndirectLightingMode`, as a
42
+ separate subsystem.
43
+ - Rays hit an SDF. Material comes from a scene representation beside it: voxels in the request, a
44
+ surface cache after the review.
45
+ - The cascades are sparse, NanoVDB-style: fixed-size bricks in an atlas.
46
+ - The SDF is 8-bit, traced with hardware texture filtering.
47
+ - Shading samples a second 3-D clipmap, of probes. Each probe holds octahedral radiance, octahedral
48
+ depth, and SH2 irradiance (in this engine SH2 means L0 + L1, four coefficients).
49
+ - Cascade count, cascade resolution, radiance and depth resolutions and rays per probe are settings.
50
+ They do not change between frames.
51
+ - Existing code (the LPV above all) is reused as far as it goes, and the Enshrouded GI talk is the
52
+ main reference.
53
+ - Performance and simplicity come first.
54
+
55
+ ## 0. Summary
56
+
57
+ **Three cached representations and one sampling step.**
58
+
59
+ 1. **Geometry caches (§6)**, baked once and shared by every instance.
60
+ - A sparse SDF per geometry: 8³-texel bricks on 7³ voxels, signed `r8unorm`, on a grid of
61
+ (2i)×(2j)×(2k) bricks with coarser levels. The evaluator is the nearest point through the BLAS,
62
+ signed by UE 5.4's vote of 98 rays one band long (S3; first `GPUGeometrySDFManager`'s 64-ray vote).
63
+ - Surface cards: axis-aligned cards over depth slabs of the same brick grid, in 8×8-texel pages.
64
+ - The layout belongs to the geometry.
65
+ - The contents belong to each (geometry, material) pair: the material the SDF cannot hold,
66
+ diffuse albedo and emissive, captured through the path tracer's material sampling.
67
+ - They are recaptured when the material's version moves.
68
+ - These bakes and captures are the only place triangles are read.
69
+ 2. **The brick clipmap is the world as rays see it (§7).**
70
+ - `C_b` cascades of `N_b³` cells, one brick a cell on the same lattice. It is traced with one
71
+ hardware trilinear tap a step and a two-level skip in the NanoVDB manner.
72
+ - A cell that scrolled in, or that a change touched, is requested. Every registered provider writes
73
+ its part of the requested bricks, and the parts merge by a per-texel minimum.
74
+ - The mesh provider composes the cached SDFs of the instances overlapping the cell. It reads no
75
+ triangle.
76
+ - Plugins write their own; virtual geometry is the first.
77
+ - Each brick also names, per 2³-texel cell, the scene row whose surface is nearest. That is how a
78
+ hit finds its material.
79
+ 3. **The probe clipmap is what shading samples (§8)**, as in (a).
80
+ - A sparse cache, wanted from the depth buffer. Octahedral radiance `rgba16float`, depth moments
81
+ `rg16float`, SH2 in the engine's YCoCg L1 (`METRO_L1_IRRADIANCE_STRUCT`).
82
+ - A fixed ray budget. Hits are lit by emissive, the sun through an SDF soft shadow, local lights and
83
+ last frame's probes. Their diffuse albedo and emissive come from the cards.
84
+ 4. **Pixels pick two probes (§9).**
85
+ - A visibility-only pass weighs the eight cage probes: trilinear × wrap back face × Chebyshev ×
86
+ crush.
87
+ - Brick4's WRS picks two. Only those two are read: their SH2 for diffuse; for specular, a radiance
88
+ tap blended with GGX-convolved SH2 by roughness, as LPV blends.
89
+
90
+ **What is reused.**
91
+ - `GPUGeometrySDFManager`'s evaluator (`blas_query_sdf`), `ray_query_blas_nearest` and the triangle
92
+ attribute chunks, for the bakes.
93
+ - The clipmap toolkit, `GPUTileAtlas3D`, `OffsetAllocator`, the TLAS and its cooperative box query,
94
+ and the VSM's mover pass (moved to scene level).
95
+ - `GPUResidentMaterialContext` and the path tracer's `sample_material_data`, for card capture.
96
+ - The particle free list; the octahedral codec, skirt and solid-angle chunks; SH2 basis, Metro L1,
97
+ the GGX zonal fit and Chebyshev.
98
+ - LPV's visibility weighting, specular blend, depth two-pass write and pass chain. Brick4's
99
+ reservoir pick and its noise sources.
100
+ - The world light clusters; the deferred resolve and `compute_indirect_specular`; `ShaderSwitch`
101
+ binding by name; the frame-graph helpers.
102
+ - The full map is §4.
103
+
104
+ **What is new.**
105
+ - The sparse mesh SDF storage; card placement, capture and recapture.
106
+ - The brick clipmap's build passes, the provider contract and the mesh provider, and the tracer.
107
+ - The probe lifetime, schedule and update passes; the pick and the sampling chunks; the Metro form of
108
+ the GGX resolve.
109
+ - The `ProbeClipmap` mode value and its settings (§10).
110
+
111
+ **Forks (§15).** None is open. The last two, both from (a), were taken as recommended:
112
+ - probes are a sparse cache, not a dense lattice (D31);
113
+ - the mover pass leaves VSM ownership for scene level (D32).
114
+
115
+ ## 1. What the tree has
116
+
117
+ Audited read-only before designing, by area. The verdict legend is §4's.
118
+
119
+ **Indirect lighting modes and their consumers.**
120
+ - `ShadeIndirectLightingMode` = {IBL 0, Brick4 1, LPV 2}. `INDIRECT_LIGHTING` is
121
+ `ShaderSwitch.enum('indirect lighting', ShadeIndirectLightingMode)`, so a new member joins its
122
+ values by itself.
123
+ - `Renderer#graph_indirect_lighting` (`shade/renderer/Renderer.js:1104-1313`) picks per mode a
124
+ diffuse/specular image-pass pair, or Brick4's fused pass when SSR is off. With SSR on,
125
+ `ssr.denoised` replaces the specular pass.
126
+ - `shader_resolve_indirect_lighting` adds the pair to scene colour. Its contract: diffuse is
127
+ irradiance E with AO multiplied in, specular is radiance before Fresnel.
128
+ - Exactly five chunks choose on the switch (`CodeChunkChoice.from(INDIRECT_LIGHTING)`):
129
+ - `forward_sample_indirect` (AVBOIT, MBOIT);
130
+ - `water_gi_irradiance` / `water_gi_specular`;
131
+ - `ssr_sample_radiance`;
132
+ - `ssr_add_hit_irradiance`;
133
+ - `irradiance_clipmap_gi_sample`, which feeds the particles' irradiance clipmap.
134
+ - Every alternative declares its resources with `CodeChunk.requireResource`. Owners bind the union by
135
+ name. `switched_shaders_declare_bindings.spec.js` audits all variants.
136
+ - **REUSE**: a new value is additive. Every file it touches is listed in §9.7.
137
+
138
+ **The Light Probe Volume (LPV).** Per frame, `GPUProbeAtlas.graph_update` runs this chain:
139
+ 1. `shader_lpv_build_gbuffer`: one jittered ray per octahedral texel through `ray_query_nearest`. A
140
+ miss stores the sky.
141
+ 2. `graph_sample_light_probes`: hits sample the LPV itself for the next bounce, scaled by 0.97.
142
+ 3. `graph_lpv_shade`: every light, with an occlusion ray, then a temporal blend into an `r32uint`
143
+ rgbe9995 atlas with a one-texel border (64² texels, pitch 66).
144
+ 4. `shader_lpv_accumulate_depth` → `shader_lpv_atlas_write_depth`: depth moments in two passes,
145
+ because `rg16float` cannot be a read-write storage texture.
146
+ 5. Borders.
147
+ 6. `graph_lvp_atlas_to_sh` → `graph_reduce_atlas_to_sh` → `graph_lpv_store_sh`: SH2.
148
+
149
+ Shading:
150
+ - `lpv_mask_weights_by_visibility` (`shader/chunk/light/lpv/depth/`) is DDGI's weighting: the wrap
151
+ back-face term `((n·ω+1)/2)² + 0.2`, Chebyshev at a biased point, a crush below 0.2. It runs over the
152
+ four probes of a tetrahedron.
153
+ - `chunk_lpv_sample_light` (`deferred/indirect/`) is the specular this design takes whole.
154
+ - The sample vector is `normalize(mix(r, n, α))`, Lagarde's dominant direction.
155
+ - A radiance-atlas tap along it is blended with `sh2_color_get_radiance_with_GGX` on the same
156
+ vector, by `roughness_to_mip_ratio(roughness)`.
157
+ - The ratio reaches 1, SH alone, at roughness 0.7 (`SPHERE_PROBE_MIP_MAX_ROUGHNESS`).
158
+
159
+ Verdicts:
160
+ - The chain is **GENERALISE**. It is a pass shape this design follows, but it is coupled to
161
+ `lpv_probes`, the tetrahedral mesh and triangle tracing.
162
+ - The weighting is **EXTRACT**: the per-probe term becomes shared.
163
+ - The specular blend is **REUSE**.
164
+ - The depth two-pass is **GENERALISE**.
165
+ - LPV's radiance readers do a manual four-load bilinear with rgbe decode, and the border it paints is
166
+ never read. Here the radiance must be hardware-filterable, which is one reason the atlas is
167
+ `rgba16float` (§8.2).
168
+
169
+ **Brick4.** Its tree and its CPU bake are not applicable. Its sampler is, and (a) missed it:
170
+ - `brick4_node_sample_probes_meta` weighs the eight cage probes without loading them: trilinear × a
171
+ back-face smoothstep.
172
+ - `brick4_probe_meta_pick2` makes the pick:
173
+ - it draws one probe with `sample_discrete_wrs_mat2x4`, the weighted reservoir sampling of
174
+ Fajardo et al.'s *Stochastic Texture Filtering*;
175
+ - it zeroes that probe and draws a second with fresh noise;
176
+ - it renormalises the pair's weights into a blend.
177
+ - Noise comes from two sources:
178
+ - image passes use STBN at (pixel, frame), as `brick4_sample_specular` and
179
+ `shader_brick4_indirect_lighting` do;
180
+ - forward passes use a hash of position, normal and frame, `jitter_from_vectors`, private to
181
+ `chunk_brick4_sample_forward_indirect.js`.
182
+ - The fused pass picks once. It then re-weights the pair separately for diffuse (against the bent
183
+ normal) and for specular (against the specular direction).
184
+ - Brick4's standalone diffuse (`brick4_sample_sh`) still evaluates all eight.
185
+ - Verdict: **EXTRACT** the selection and the forward hash. Brick4 keeps its address mapping.
186
+
187
+ **The irradiance clipmap** (`volumetrics/irradiance_clipmap/`):
188
+ - 6 × 32³ cascades at 0.25 m, Y and CoCg `rgba16float` 3-D atlases on a `GPUTileAtlas3D`.
189
+ - Its own stateless placement (`IrradianceCascadePlacement`) over linear storage, so a one-voxel move
190
+ rebuilds the cascade.
191
+ - Per texel: GI SH from the mode, directional lights through their shadow maps, and world-cluster
192
+ point/spot lights up to `IRRADIANCE_CLIPMAP_LIGHT_BUDGET` = 32.
193
+ - Lit particles are its only consumer.
194
+
195
+ Verdicts: **REUSE** its light and shadow lookups. Its placement is not a model: it duplicates the
196
+ clipmap toolkit (§16).
197
+
198
+ **Clipmap toolkit.**
199
+ - `ClipmapWindowSet` (hysteretic placement, `clamp_corner`, `storage_cell`, `decode`),
200
+ `window_scroll_regions` (at most three disjoint exposed boxes), `quantize_hysteretic`, and
201
+ `clipmap_select_finest` (CPU and WGSL).
202
+ - `CLIPMAP_LEVEL_STRUCT` (32 B; `CLIPMAP_LEVEL_LIMIT` levels), `chunk_clipmap_contains`,
203
+ `chunk_clipmap_storage_coord` (no production user yet), `grid_tile_window_storage` (the fluid's).
204
+ - The fluid's exposed-slab flow is `GPUFluidCascadeStack.record_tick` → `window_scroll_regions` →
205
+ `shader_fluid_cascade_fill`.
206
+ - **REUSE** as is. This is what `GPUClipMap3D`'s deletion (`f2f6bc7b6`) named as its replacement.
207
+
208
+ **Atlases.**
209
+ - `GPUTileAtlas3D`: equal tiles with a border parameter and several synchronised formats. Its doc
210
+ names "a brick SDF atlas" as an intended client.
211
+ - Slots are handed out on the host (`allocate`, `free`), and a grow replaces the texture.
212
+ - **GENERALISE**: a bulk reserve, so the GPU free list owns the slots (§7.10).
213
+ - `OffsetAllocator` (`core/binary/allocator/`) hands out ranges of a linear store. **REUSE** for the
214
+ mesh SDF indirection and the card page tables.
215
+
216
+ **Scene distance fields.**
217
+ - `GPUGeometrySDFManager` (`geometry/sdf/`):
218
+ - Storage: per geometry, a dense 50³ `r32float` tile in a `GPUTileAtlas3D`. The slot is the
219
+ geometry id and is never freed.
220
+ - Build: `shader_build_sdf` evaluates `blas_query_sdf` at every voxel:
221
+ - the exact nearest point through the BLAS (`point_query_blas_nearest`);
222
+ - a sign from 64 Fibonacci rays (`blas_query_volume_sign`), inside past 60% back faces;
223
+ - for open meshes, a wrap of negative distances past 4 voxels.
224
+ - Reach: it is not attached (`GPUGeometryManager.sdf` throws), and no frame reaches its readers
225
+ (`chunk_geometry_sdf_query_distance`, `chunk_sdf_geometry_raymarch`, `chunk_scene_sdf_raymarch`,
226
+ `shader_scene_sdf_debug_viz`). Its spec tests storage, not distances.
227
+ - Alex: it worked, and it is correct. **GENERALISE in place** (§6): the evaluator stays, the
228
+ storage becomes sparse.
229
+ - `CascadedSceneSDF`:
230
+ - One dense `r16float` volume despite the name, built once from 65 scene queries per texel.
231
+ - It is constructed only by an uncalled `Renderer.obtains_scene_sdf`.
232
+ - It is the only precedent in the tree for hardware-filtered SDF sphere tracing
233
+ (`shader_scene_sdf_soft_shadows`). **Not applicable** as a cache.
234
+ - `shadow/sdf/brixelizer/`: a port of FidelityFX Brixelizer's trace side. It was never verified and
235
+ does not compile. Alex: a reference only.
236
+
237
+ **Scene rows.**
238
+ - The entity is the row (`row_of_entity`). `GPUSceneRows.attach_mesh(entity, geometry, material,
239
+ skinned)` gives it a `meshes` row.
240
+ - `ShadedGeometrySystem` calls it for every `ShadedGeometry`, passing
241
+ `ShadedGeometryFlags.Skinned`.
242
+ - It calls it again when `shaded_geometry_announce_change` reports an in-place change.
243
+ - `ShadedGeometryFlags`: InView 1, CastShadow 2, ReceiveShadow 4, DrawMethodLocked 8, Visible 16,
244
+ DeferredBoundsUpdate 32, Skinned 64. Shade reads none of them for meshes, and a row carries no flag
245
+ on the GPU.
246
+ - `MESH_INSTANCE_METADATA_STRUCT` holds geometry, material, node, box, sphere and lightmap chart:
247
+ 68 B of fields in an 80 B row. A `u32` fits without growing it, as `global_flags` did in
248
+ `NODE3D_STRUCT`.
249
+ - Virtual geometry is a `MeshletGeometry` with `isVirtualGeometry`, on the same rows, and its BLAS is
250
+ empty.
251
+ - A skinned row draws a per-instance clone (`GPUMeshSkinningContext.obtain_clone`). The CPU entry
252
+ keeps the source geometry.
253
+ - Signals: `onMeshReleased`, and `for_each_mesh` for walks. Nothing announces a write.
254
+ - **GENERALISE**: a `flags` word, an `SDFWorld` bit carried as `Skinned` is, and `onMeshWritten`
255
+ beside `onMeshReleased` (§6.1).
256
+
257
+ **Scene queries.**
258
+ - The TLAS (`GPUInstancesAccelerationStructure`) is GPU-resident and maintained by the scene context.
259
+ `graph_bvh_build_lbvh` rebuilds it in full whenever a row changes. Its leaves are mesh rows (the
260
+ leaf's `child_2`).
261
+ - BLASes are built on the CPU per geometry over meshlets; skinned clones are refit on the GPU every
262
+ frame (`GPUBLASRefitBatch`).
263
+ - `chunk_bvh_query_aabb_cooperative`: one 64-lane workgroup per box, level-synchronous, ≤ 128 sorted
264
+ candidates, drops counted, two seam functions. Its only user is fluid forcing.
265
+ - `point_query_blas_nearest` and `ray_query_blas_nearest` answer per geometry; the sign vote uses the
266
+ second.
267
+ - Verdicts: **REUSE** the TLAS and the cooperative query for the mesh provider (§7.7). Use the BLAS
268
+ queries in the bakes only (§6.4, §6.5).
269
+
270
+ **Change detection.**
271
+ - `shader_vsm_movers` + `shader_vsm_skinned_movers` append, for every mesh row whose matrix, box,
272
+ geometry or material changed, the union of its box now and before (`VSM_MOVER_LAYOUT`, 4,096
273
+ boxes, overflow counted).
274
+ - Last-seen state is `VSMMoverTracker`.
275
+ - It is a transient inside `graph_vsm_feedback` and exists only while a virtual shadow map is
276
+ registered.
277
+ - **EXTRACT** to scene level (D32), with a bit telling a skinned row's box from a rigid one (§7.4).
278
+
279
+ **Material.**
280
+ - `sample_material_data` (`path_tracer/shader/chunk_sample_material_data.js`) does two things:
281
+ - it interpolates uv, vertex colour, normal and tangent from a triangle and barycentrics;
282
+ - it samples the material: albedo × colour factor × vertex colour, ORM, emissive × factor, opacity.
283
+ - It reads `GPUResidentMaterialContext` (on `GraphicsContext`): the material table
284
+ (`INDIRECT_MATERIAL_STRUCT`) and a 2-D array of 64² texture slots, one level each, sampled by
285
+ `indirect_sample_texture` with each sampler's wrap mode and a stochastic bilinear tap.
286
+ - Its taps and dither draw on the path tracer's random state. Alpha is stochastic: a hit is opaque
287
+ with probability equal to its opacity (`chunk_ray_shaded_query_occluded`, through
288
+ `sample_material_alpha`).
289
+ - `ShadeMaterial.version` moves on every change. `GPUResidentMaterialContext.obtain_material` repacks
290
+ a material whose version moved, on walks it already makes: the scene's drawn list, and the
291
+ manager's materials when the manager's version moves. The single place that happens is
292
+ `#pack_material`.
293
+ - **REUSE** both chunks in card capture, with a seed fixed per texel (§6.5). **GENERALISE** the
294
+ resident context with a signal from `#pack_material` when a material is repacked, which is what
295
+ recapture keys on.
296
+
297
+ **What rays could not see.** vgeo rows are in the TLAS with an empty BLAS, and DynamicMesh has no row.
298
+ Under (b):
299
+ - virtual geometry is written by its provider (§7.8);
300
+ - DynamicMesh stays out by construction: it changes every frame, and a cache of it would be a cache of
301
+ nothing (§17).
302
+
303
+ **Lights at arbitrary world points.**
304
+ - `shade_directional_lights` takes a position only.
305
+ - Shadow maps do not answer off-screen points honestly. CSM reads *lit* outside its view-fitted
306
+ cascades. VSM pages exist only where the main view's depth demanded them, and with none resident a
307
+ point reads lit.
308
+ - Local-light shadows are sampled by direction or projection, so they work anywhere in range. Their
309
+ refresh is scored by on-screen area, and a cleared region reads unshadowed.
310
+ - The world light clusters (`light/world_cluster/`): 8³ cells per cascade, ≤ 128 lights per cell,
311
+ 4,096 candidates. They are keyed by the irradiance clipmap's levels and built inside its
312
+ `graph_update`. **GENERALISE** the keying.
313
+ - Misses: `sample_environment_color` (level 0 of the octahedral environment), `get_ibl_irradiance`,
314
+ `environment_sh`.
315
+
316
+ **Settings.**
317
+ - There is no settings class.
318
+ - The precedent for "rarely changes, reallocate on change" is the shadow knobs: validated setters on
319
+ `Renderer`, pushed every frame into `GPUSceneShadowmapContext`, which rebuilds what was built with
320
+ another value.
321
+ - Sub-objects (`avboit`, `ssr`, `volumetrics`) group a feature's fields.
322
+
323
+ **SH conventions.**
324
+ - `sh2_*` is L0 + L1, ordered `[DC, y, z, x]`.
325
+ - `METRO_L1_IRRADIANCE_STRUCT` is {CoCg vec2f, Y vec4f}, 32 B, its Y in (x, y, z, DC) order.
326
+ - Its `1/(2π)` convention, under which the resolve returns E/π, is pinned by
327
+ `chunk_volumetrics_irradiance_sh.spec.js`.
328
+ - It has a diffuse resolve (`resolve_irradiance_sh_to_diffuse`) and no specular one.
329
+ - `sh2_approximate_GGX_zh` is MJP's fit of the GGX lobe's band-1 zonal factor, `1.6671/(1.6572 + α)`.
330
+ `sh2_color_convolve_with_GGX` and `sh2_color_get_radiance_with_GGX` apply it to RGB SH2; LPV is
331
+ their user.
332
+
333
+ ## 2. What the field ships
334
+
335
+ Ordered by how directly each shapes this design.
336
+
337
+ ### 2.1 Enshrouded (Keen Games) — the main reference
338
+
339
+ Source: Jakub Kolesik, *Realtime Global Illumination in Enshrouded*, Graphics Programming
340
+ Conference 2024 ([video](https://www.youtube.com/watch?v=57F1ezwH7Mk), 50 min; read from its
341
+ captions, so the numbers are as spoken). Timestamps in brackets.
342
+
343
+ **Building blocks** [2:32–4:34]
344
+ - A "spatial cascaded cache": a 32³ world-aligned grid around the player, 12 cascades, 2 m spacing
345
+ at cascade 0, doubling per cascade.
346
+ - Cells are activated by the depth buffer and by a buffer of ray-hit positions.
347
+ - It is capped at 16k live cells, always full, and garbage-collected: a cell that leaves the
348
+ screen loses quality over frames and expires, and is reused if seen again before then.
349
+ - The world as a simplified SDF traced by "SDF rays". Very small objects are absent and medium ones
350
+ appear only at high settings.
351
+ - They had Vulkan ray-tracing prototypes and chose SDF rays to have **one code path on all
352
+ hardware**, scalable by SDF resolution and by which SDFs a tier uses.
353
+ - A BVH sits over the SDFs.
354
+
355
+ **Three probe kinds** [4:34–11:12]
356
+ 1. **Frustum probes.** Cells activated by the depth buffer, pushed out of walls with the SDF, then
357
+ offset toward the camera and along the surface normal.
358
+ - Octahedral radiance 32² (ultra), 16² (mid), 8² (low) with a hand-made border, plus octahedral
359
+ irradiance at 12² or 8².
360
+ - Both are RGB9E5 in a 128×128-probe atlas. Distance is RGBA16F, because the occlusion test
361
+ needed the precision.
362
+ 2. **World-cache probes** at ray hits where no frustum probe exists. Same shaders; 4×4 octahedral
363
+ with no border; SH irradiance; denser, and storing no occlusion.
364
+ - The chain stops there: point lights get three bounces and full GI two.
365
+ 3. **Ambient probes** for fog: 16³ × 8 cascades. They trace nothing and accumulate about 10% of the
366
+ other probes' ray segments.
367
+ - They feed a 32×32-tile froxel volume with 384/256/128 slices, about 50 µs on low-end hardware.
368
+
369
+ **Pipeline** [11:12–19:54]
370
+ - Fully GPU-driven with indirect dispatches.
371
+ - A fixed ray budget: 100k / 250k / 500k rays a frame on low / mid / high (Q&A [45:27]).
372
+ - A new probe asks for 512 rays and decays fast to 16, rising again when it sees change. Requests
373
+ are scaled down to the budget.
374
+ - Rays are batched by a probe-index scan.
375
+ - Ray directions are importance-sampled from each probe's own radiance (a linear CDF walk with a
376
+ rotating start corner), because 16–32 uniform rays a frame left the probes flickering.
377
+ - **Uniform rays every 5th frame** keep the depth moments alive, which importance sampling
378
+ starves.
379
+ - Rays are sorted by position and direction, and hits by kind (terrain, sky, building) to avoid
380
+ shader branches.
381
+ - **Hit shading** [19:23]: emissive from the voxel; directional light with an SDF shadow ray shot
382
+ beforehand; point lights from a "light cache" (a cascaded grid of per-cell light lists) with SDF
383
+ shadows; then GI from the probes.
384
+
385
+ **Temporal and spatial filtering** [20:25–26:33]
386
+ - A moving-average estimator (short and long-term means, variance-driven blend; from the
387
+ *Stochastic All The Things* talk and Ray Tracing Gems) at 5 × u32 per texel, which the talk
388
+ counts as a heavy bandwidth cost.
389
+ - Depth is a per-texel mean and mean² clamped to the probe spacing, tested with Chebyshev and
390
+ filtered in LDS.
391
+ - Ray and history reprojection between neighbouring probes, 4:1, which carries light hundreds of
392
+ metres into caves.
393
+ - Irradiance by a cosine-weighted loop over the rays.
394
+
395
+ **Specular** [27:03]: radiance prefiltered by a cosine-weighted blur and downsample into mip-like
396
+ levels, tuned against a ground-truth mode, then blended with FidelityFX SSSR because characters are
397
+ not in the SDF [33:10].
398
+
399
+ **Sampling** [29:04–31:39]
400
+ - Trilinear over the eight cage probes, but **stochastic**: one probe per frame by weight (trilinear
401
+ × Chebyshev), with stochastic cascade crossing in the overlap.
402
+ - Two screen-space reservoirs, temporally reprojected and spatially filtered.
403
+ - An à-trous denoise, needed mostly for specular.
404
+ - Dead probes are those whose rays sum to under 1 mm, i.e. inside a wall. They are excluded but
405
+ still trace 16 rays a frame.
406
+
407
+ **Lessons stated** [41:19–42:53]: bandwidth dominates (Steam Deck); RGB9E5 everywhere, decoded in
408
+ LDS; fixed buffer sizes; settings for every system. The admitted hole is foliage: trees are not in
409
+ the SDF [49:08].
410
+
411
+ **What this design takes, and what it leaves.**
412
+
413
+ | Enshrouded | Here | Why |
414
+ |---|---|---|
415
+ | SDF rays instead of hardware RT | same (§7) | one path on every WebGPU device; the request |
416
+ | material from the voxel world; normal from the SDF | surface cards holding captured diffuse albedo and emissive (Lumen's payload); normal from the field's gradient (§6.5, §6.6) | the review: voxel attributes are expensive |
417
+ | very small objects absent, medium ones only on high | a per-primitive membership flag (§6.1) and a per-cascade resolution cull (§7.7) | the review; the cull keys on a runtime fact (E4) |
418
+ | a BVH over the SDFs | the TLAS over instance boxes, queried per requested cell (§7.7) | reuse |
419
+ | cascaded cache, depth-buffer activation, expiry | probe clipmap with want → slot → retention (§8.3) | memory follows what is visible, not the grid |
420
+ | octahedral radiance + border; distance with mean/mean² | same, `rgba16float` and `rg16float` with the engine's skirt chunks (§8.2) | hardware bilinear for every consumer tap |
421
+ | irradiance as octahedral 12² (frustum) or SH (world cache) | SH2 YCoCg L1 for every probe | the request; 32 B a probe |
422
+ | fixed ray budget; per-probe requests scaled to it | budget in rays a frame; period follows the live count (§8.5) | same intent, deterministic schedule |
423
+ | importance-sampled directions + every-5th-frame uniform | one jittered ray per texel (stratified), always | no starvation, no second schedule; revisit only on a measured noise problem (§17) |
424
+ | moving-average estimator, 5 u32 per texel | exponential blend over a response time in seconds (§8.8) | DDGI's form; one history; a physical knob |
425
+ | SDF shadow ray per hit for the sun | same (§8.6) | shadow maps answer "lit" off screen (§1) |
426
+ | light cache for point lights | the world light clusters, keyed by this clipmap (§8.7) | reuse |
427
+ | world-cache probes at hits | not in v1 (§17) | a second probe kind; added only if off-screen bounce measures short |
428
+ | stochastic 1-of-8 + reservoirs + denoise | 2 of 8 by Brick4's WRS, resolved by TAA (§9.1, §9.4) | the review; two probe reads, no denoiser |
429
+ | prefiltered radiance levels for specular | the radiance tap blended with GGX-convolved SH2 by roughness (§9.3) | the review: WebGPU's mips; LPV's blend |
430
+ | ambient probes and froxel GI | the existing irradiance clipmap samples this mode's probes (§9.5) | fog has no GI in any mode today |
431
+
432
+ ### 2.2 UE 5.4 Global Distance Field
433
+
434
+ From the local source (`H:/Program Files/Epic Games/UE_5.4/Engine`). The production reference for
435
+ the brick clipmap.
436
+
437
+ **Clipmaps**
438
+ - 4 clipmaps (up to 6) of 252 voxels a side, i.e. 36 pages × 7 voxels.
439
+ - Clip 0 is a ±25 m half-extent at 19.8 cm voxels, doubling per clipmap.
440
+
441
+ **Pages and atlas**
442
+ - **A page is 8³ texels in the atlas with 7 unique voxels**: texel 7 duplicates the next page's
443
+ texel 0, every page computes all 512 itself, and the lookup `offset·8 + frac(uv·36)·7 + 0.5`
444
+ keeps trilinear inside the page. There is no border pass.
445
+ - Atlas: 3-D `R8_UNORM`. Page table: `R32_UINT` with `0xFFFFFFFF` = no page, allocated from a GPU
446
+ free-list stack.
447
+ - Distance is encoded `saturate(d/(2R) + 0.5)` with **R = 4 voxels**.
448
+ - A page is kept iff its centre's distance is within R plus the page radius.
449
+
450
+ **Empty-space skipping**: a dense `R8` coarse mip at a quarter of the resolution, rebuilt by five
451
+ eikonal propagation passes whenever a clipmap updates. Pages are read only where the coarse distance
452
+ is under 4 voxels.
453
+
454
+ **Composition**: from the mesh distance fields of §2.3, culled per tile into lists of up to 511
455
+ objects, with a minimum object radius of max(20 cm, ½ voxel).
456
+
457
+ **Invalidation and budget**
458
+ - Add, remove and transform changes record the old and new boxes, expanded by R. At 1,024 boxes or
459
+ more the clipmap is fully recaptured.
460
+ - 2 clipmaps update a frame, staggered.
461
+ - Scrolling is toroidal and exposes slabs only.
462
+
463
+ **Trace**
464
+ - Starts in the first clipmap containing the point by over half a voxel, clipping the ray to each
465
+ clipmap box shrunk by half a voxel.
466
+ - At most 256 steps a clipmap. A hit is d < ~½ voxel (the "expand"); the minimum step is ½ voxel.
467
+ - The normal is a 6-tap central difference.
468
+
469
+ ### 2.3 UE 5.4 mesh distance fields, composition, and Lumen's surface cache
470
+
471
+ From the local source. The production reference for §6 and §7.7. Paths are under `Engine/`.
472
+
473
+ **Mesh distance fields** (`Source/Runtime/Engine/Public/DistanceFieldAtlas.h`,
474
+ `Source/Developer/MeshUtilities/Private/MeshDistanceFieldUtilities.cpp`)
475
+ - Bricks of 8³ texels with 7 unique on the corner lattice, `G8`, a band of 4, and 3 mips. An empty
476
+ brick is `0xFFFFFFFF` and reads +band.
477
+ - Resolution: 0.2 voxels a centimetre (5 cm) × a per-mesh scale. Mip 0 is capped at 128 voxels a
478
+ side at scale 1, 18 bricks. Mip i has ⌈mip₀ / 2^i⌉ bricks a side and is re-voxelised from the mesh,
479
+ not downsampled.
480
+ - The band is 4 voxel *diagonals*, and the encoding is the global field's `(d + band) / 2band`.
481
+ - A brick is stored unless all its texels saturate at one end, so a brick wholly inside reads +band,
482
+ as here.
483
+ - Sign:
484
+ - Rays are traced only where the unsigned distance is inside the band.
485
+ - There are 98 of them (a 7×7 stratified hemisphere and its mirror), each one band long.
486
+ - The voxel is inside when more than 25% hit back faces. Two-sided triangles never count.
487
+ - Translucent sections, and primitives with `bAffectDistanceFieldLighting` off, are left out: the
488
+ precedent for the membership bit (D25).
489
+
490
+ **Composition** (`Source/Runtime/Renderer/Private/GlobalDistanceField.cpp`,
491
+ `Shaders/Private/DistanceField/GlobalDistanceFieldCompositeObjects.usf`,
492
+ `Shaders/Private/MeshDistanceFieldCommon.ush`)
493
+ - Objects are culled to the clipmap, then to tiles of 4³ pages, then to each page's 4³-voxel tile in
494
+ LDS, 511 a pass. The passes loop, so there is no hard cap.
495
+ - Per object:
496
+ - an early-out when the box distance is already past the running minimum;
497
+ - inside the volume, the mesh SDF scaled by the object's smallest axis scale;
498
+ - outside it, the SDF at the clamped point plus the box distance.
499
+ - The resolution cull is radius > max(20 cm, ½ voxel). Emissive objects are exempt.
500
+ - The mip is not chosen by the clipmap's voxel. A sample walks the resident mips from coarse to fine
501
+ and stops at the first whose distance exceeds a quarter of its band. Mips stream in by distance:
502
+ 3 inside clipmap 1's box, 2 inside clipmap 3's, 1 elsewhere.
503
+ - Mostly-static and movable layers are merged by a minimum: the static/dynamic category E4 refuses.
504
+
505
+ **The object grid** (`Shaders/Private/DistanceField/GlobalDistanceFieldObjectGrid.ush`,
506
+ `Shaders/Private/Lumen/LumenSoftwareRayTracing.ush`)
507
+ - Layout: a page has 4³ cells. Each cell holds the 4 nearest objects as a `uint4`: a 24-bit instance
508
+ index and an 8-bit distance. That is 1 KiB a page.
509
+ - It is filled by its own pass, one thread per cell.
510
+ - At a hit:
511
+ - the lookup point is the hit plus half a voxel along the field's normal;
512
+ - each entry's mesh cards are sampled in turn, until the summed weight reaches 0.9 or an entry is
513
+ empty.
514
+
515
+ **Mesh cards** (`Source/Developer/MeshUtilities/Private/MeshCardRepresentationUtilities.cpp`)
516
+ - Cards are axis-aligned in mesh space, six directions.
517
+ - Surfels:
518
+ - Per column of a 10 cm grid, 32 jittered rays march through successive hits.
519
+ - A hit is kept if it faces the card and follows an empty cell. Its "MinRayZ" is the layer after
520
+ the previous hit.
521
+ - Clustering, per direction:
522
+ - first the outer projection (near plane 0);
523
+ - then, greedily, the near plane that best covers the unassigned surfels. A near plane N sees a
524
+ surfel at layer Z when MinRayZ ≤ N ≤ Z.
525
+ - This is how concave meshes get interior cards.
526
+ - The weakest clusters are dropped down to 12 cards a mesh (32 at most; the runtime lookup is a
527
+ 32-bit mask per direction).
528
+ - A mesh with no card has no fallback.
529
+
530
+ **The surface cache** (`Source/Runtime/Renderer/Private/Lumen/LumenSurfaceCache.cpp`,
531
+ `LumenSceneRendering.cpp`, `LumenSceneCardCapture.cpp`)
532
+ - Layers: 128² physical pages in a 4096² atlas, holding depth `G16`, diffuse albedo `RGBA8` (stored
533
+ as its square root), opacity, normal, emissive `R11G11B10`, and three lighting layers.
534
+ - Card resolution:
535
+ - recomputed from distance at every update, 8 to 2048 texels;
536
+ - a locked distance level always resident, with finer pages paged in by GPU feedback;
537
+ - idle pages kept for 256 frames.
538
+ - Capture:
539
+ - the mesh is rasterised through an ortho camera on the card, at most 300 pages a frame;
540
+ - a recapture follows a resolution change, an explicit `InvalidateLumenSurfaceCache` on the
541
+ primitive, or a slow refresh of the oldest pages;
542
+ - a material change is not tracked.
543
+
544
+ **Sampling at a hit** (`Shaders/Private/Lumen/SurfaceCache/LumenSurfaceCacheSampling.ush`)
545
+ - Cards are selected by the normal's sign per axis, weighted by n², and every card holding the point
546
+ within the bias is blended.
547
+ - Depth test: four depth taps, each weighted by `1 − saturate((|t − depth| − bias)/(¼·bias))` in card
548
+ depth units. For a global-SDF hit the bias is three half-voxels of the hit's clipmap.
549
+ - With no valid card, the hit is opaque black.
550
+
551
+ **Lumen**: probe rays trace the global distance field and are lit by the surface cache's final
552
+ lighting. 5.4 has removed the voxel lighting that earlier versions used for global-SDF hits.
553
+
554
+ ### 2.4 UE 5.4 Lumen world-space radiance cache
555
+
556
+ The production reference for sparse probe allocation.
557
+
558
+ **Clipmaps and allocation**
559
+ - 4 clipmaps of 48³ at 1.04 m (clip 0).
560
+ - The indirection (`R32_UINT`) is cleared and rebuilt every frame: consumers mark the eight probes
561
+ around each sample, and a probe is reused if marked within 8 frames, else freed.
562
+ - 16,384-probe capacity (128² atlas). By the CVar's own description, overflow renders incorrectly.
563
+
564
+ **Probes**
565
+ - 32² equal-area octahedral `R11G11B10F` radiance plus `R16F` hit distance.
566
+
567
+ **Tracing**
568
+ - A budget of 300 probes × cost per frame. Never-traced probes go first, then priority by how long
569
+ since each was traced relative to its use.
570
+ - **No history blend and no jitter**: a retrace overwrites.
571
+ - 256–4,096 rays per probe, against the global distance field only; hits are lit by the surface
572
+ cache.
573
+
574
+ **Sampling**
575
+ - Eight-probe trilinear with sphere parallax.
576
+ - Visibility weighting (Chebyshev³ × `((n·ω+1)/2)² + 0.2`) is used only in the off-by-default
577
+ irradiance mode.
578
+
579
+ Lumen can overwrite on every retrace because its screen probes filter downstream. Here consumers
580
+ sample the probes directly, so the blend stays (§14, D11).
581
+
582
+ ### 2.5 AMD FidelityFX Brixelizer and Brixelizer GI
583
+
584
+ From the FidelityFX SDK manual and source (v1.1.4) and the GDC 2024 talk. The port in
585
+ `shadow/sdf/brixelizer/` is a reference only.
586
+
587
+ **The field**
588
+ - Cascades of 64³ voxels (up to 24), each voxel holding at most one brick through a 1 MiB brick map.
589
+ The toroidal wrap is `(voxel + offset) & 63`.
590
+ - Bricks are 8³ samples spanning one voxel (7 intervals, shared samples, no apron) in a 512³ R8
591
+ atlas: 2^18 bricks, 128 MB.
592
+ - The manual calls them **unsigned** distance fields; the stored value saturates at one voxel.
593
+ - Two-level per-cascade AABB trees (4³ fan-out) skip empty space.
594
+
595
+ **The build**
596
+ - Triangles are referenced into every voxel their box overlaps. Each writes exact distances into
597
+ its box's brixels through 32-bit `InterlockedMin`, then a 12-sweep eikonal fill runs per brick.
598
+ - *Static* cascades persist under invalidation jobs; *dynamic* cascades are rebuilt every frame,
599
+ merged by a per-brixel min. That is the static/dynamic category this engine refuses (E4).
600
+ - The per-triangle scatter is the footprint-dependent cost E3 refuses.
601
+
602
+ **Brixelizer GI**
603
+ - The SDF carries no material, so its radiance cache is fed only by reprojecting previous frames.
604
+ - Screen probes 8×8 octahedral, a per-brick SH2 cache, about 2 ms at 4K at half scale on an RX 7900
605
+ XTX.
606
+
607
+ What this design keeps from it: the per-texel min as the merge of independent writers (§7.6), here
608
+ between providers rather than between static and dynamic cascades.
609
+
610
+ ### 2.6 DDGI
611
+
612
+ Majercik et al., JCGT 2019 and 2021, and the RTXGI SDK.
613
+
614
+ **2019 paper**
615
+ - Irradiance `R11G11B10F` at 8×8 octahedral per probe; distance and distance² `RG16F` at 16×16;
616
+ one-texel gutters.
617
+ - Hysteresis 0.85–0.98 across its results.
618
+ - 64–128 rays a probe a frame.
619
+ - Distance texels gathered with a cosine power (50 in RTXGI).
620
+ - Leak control: Chebyshev visibility, a shading point offset along the normal and toward the eye,
621
+ the wrap back-face weight `((n·ω+1)/2)² + 0.2`, and crushing of small weights.
622
+ `lpv_mask_weights_by_visibility` already is this.
623
+ - 1–2 m spacing for human-scale scenes.
624
+ - 6 ms at 1080p on an RTX 2080 Ti for its teaser scene.
625
+
626
+ **2021 additions**
627
+ - Probe states and relocation out of geometry.
628
+ - A back-face hit writes irradiance 0 and shortens its depth by 80%.
629
+ - A per-texel convergence boost: a change over 25% drops the hysteresis by 0.15; over 80%, to 0.
630
+ - Scrolling volumes clear only the plane that wraps.
631
+
632
+ **RTXGI defaults**
633
+ - 256 rays; hysteresis 0.97.
634
+ - Normal bias 0.1 and view bias 0.1, in world units.
635
+ - Back-face threshold 0.25 for the fixed classification rays (0.1 for random rays); minimum
636
+ front-face distance 1.0.
637
+ - Relocation clamped to 45% of a cell.
638
+ - A probe every 2–3 m recommended.
639
+
640
+ ### 2.7 Godot 4 SDFGI, and the HDDAGI draft
641
+
642
+ **SDFGI** (4.3 source and docs)
643
+ - Up to 8 cascades of 128³ cells, Y at 75%.
644
+ - Voxelized albedo, emission and facing at half size.
645
+ - The SDF is built by jump flood from solid voxels and stored **unsigned** in R8 as `(1 + cells)/255`.
646
+ - Probes: 17³ per cascade, 8 cells apart, *all updated every frame*, 16 rays by default; L3 SH in a
647
+ 30-frame history ring.
648
+ - Its documented limits: visible cascade shifts; convergence time; an SDF that updates only when the
649
+ camera crosses cascades, so moved doors give stale GI; dynamic meshes contribute nothing; leaks;
650
+ one of the engine's most demanding GI options.
651
+
652
+ **HDDAGI** (reduz, PR #86267, an open draft never merged; revived as #119869 in May 2026)
653
+ - Replaces the full-cascade jump flood with HDDA over local updates.
654
+ - Claims 2.43 → 0.93 ms on a GTX 1650, unaffected by camera motion.
655
+
656
+ The lesson taken here: **never rebuild a whole cascade, and never update every probe every frame.**
657
+ §7.4 rebuilds only exposed and changed cells; §8.5 traces only wanted probes, within a budget.
658
+
659
+ ### 2.8 kajiya's irradiance cache
660
+
661
+ Embark Studios' research renderer.
662
+ - 12 sparse 32³ clipmaps over a dense indirection, with a 65,536-entry pool. Entries are allocated
663
+ on demand and freed a few frames after their last use.
664
+ - Each entry is a 4×4 octahedral set of temporal reservoirs, 4 texels refreshed a frame, convolved
665
+ to L1 SH.
666
+ - Usually under 16k entries, about 0.55 ms on an RX 6800 XT.
667
+ - It is queried only at ray hits: a cache behind a screen-space solver, not the shading
668
+ representation. That is why it can be so small.
669
+
670
+ ### 2.9 Specular from two SH bands
671
+
672
+ - **The GGX lobe as a zonal kernel.** Convolving radiance SH with a radially symmetric lobe scales
673
+ each band by the lobe's zonal factor. MJP's *SHforHLSL* fits GGX's band-1 factor as
674
+ `1.6671/(1.6572 + α)`: about 1 at α = 0, and 0.63 at α = 1, near the clamped cosine's 2/3. The
675
+ tree has the fit as `sh2_approximate_GGX_zh`.
676
+ - **Dominant direction.** Lagarde and de Rousiers (*Moving Frostbite to PBR*, 2014) bend the lookup
677
+ from the reflection vector toward the normal as roughness grows. LPV and Brick4 both do this.
678
+ - **Luma and chroma.** Metro Exodus (GTC 2019) stores luma as L0 + L1 and chroma as a constant, and
679
+ rescales chroma by the ratio of directional to mean luma at resolve. The same ratio carries over to
680
+ a GGX resolve (§9.3).
681
+ - **The blend.** Two bands cannot hold a sharp lobe, and a single radiance tap cannot hold a wide
682
+ one. LPV blends the two by `roughness_to_mip_ratio`, Frostbite's roughness-to-mip curve.
683
+
684
+ ### 2.10 What wins on performance and simplicity
685
+
686
+ | Component | Chosen | Over | Because |
687
+ |---|---|---|---|
688
+ | Brick layout | UE page: 8³ texels, 7 voxels, corner lattice | 8³ + apron (10³) | no border pass; 512 B a brick; Brixelizer agrees |
689
+ | Distance | signed `r8unorm` over ±4 voxels, ½-voxel hit | unsigned shell, (a) | whole-mesh bakes know the sign; relocation and back faces follow from it; the ½-voxel hit keeps thin walls (D2) |
690
+ | Empty space | 4³-cell occupancy count + cell entry (HDDA) | UE's coarse eikonal mip; Brixelizer's AABB trees | incremental, toroidal, no propagation passes and no tree build |
691
+ | World build | composed from cached per-mesh SDFs, as UE composes | triangles per cell, (a); per-triangle scatter (Brixelizer); raster voxelize (Godot) | no triangle is read per frame; cost follows the instances in a cell |
692
+ | Mesh SDF | sparse bricks in size classes, with levels | `GPUGeometrySDFManager`'s dense tiles | the review; memory follows the surface |
693
+ | Material | cards holding diffuse albedo and emissive captured per (geometry, material), recaptured when the material's version moves | the voxel lattice, (a); cards holding uvs with the material evaluated live | the review: no material work at a hit (§15) |
694
+ | Probe residency | sparse cache from the screen | dense lattice | 10× less memory and work at the same lattice (§11) |
695
+ | Rays | one jittered ray per texel | importance sampling | no starvation, no extra schedule, no CDF |
696
+ | Temporal | exponential over a response time | moving-average estimator | one history, 8 B a texel |
697
+ | Pixel sampling | 2 of 8 by WRS | all eight, (a); 1 of 8 + reservoirs + denoise (Enshrouded) | the review; two probe reads, no denoiser |
698
+ | Specular | radiance tap ⊕ GGX-convolved SH2 | prefiltered levels | the review; LPV's blend |
699
+
700
+ ## 3. Requirements
701
+
702
+ **From the request (R)**
703
+ 1. A new `ShadeIndirectLightingMode` value selects a separate subsystem.
704
+ 2. Rays hit an SDF. Material comes from a scene representation beside it (R11).
705
+ 3. The scene clipmap is sparse: fixed-size bricks in an atlas.
706
+ 4. The SDF is 8-bit and traced with hardware filtering.
707
+ 5. Shading samples a 3-D clipmap of probes: radiance and depth octahedral, irradiance SH2.
708
+ 6. Cascade count, cascade resolution, radiance and depth resolutions and rays per probe are settings.
709
+ A change reallocates; nothing changes per frame.
710
+ 7. Maximal reuse; the LPV is an explicit source.
711
+ 8. Enshrouded is the main reference.
712
+ 9. SotA first, prioritising performance and simplicity.
713
+
714
+ **From the review of (a) (R)**
715
+ 10. No triangle work per frame: meshes are cached as SDFs, NanoVDB-style, in size classes of 2×2×2
716
+ bricks and up in steps of two bricks per axis.
717
+ 11. Material comes from a surface cache in Unreal's manner, not from voxels: diffuse albedo and
718
+ emissive captured per (geometry, material), recaptured on a material change.
719
+ 12. A primitive can be absent from the SDF world.
720
+ 13. Providers write requested bricks; their outputs merge per brick; virtual geometry is served by
721
+ one.
722
+ 14. Skinned meshes use their unskinned representation now, with hooks and TODOs for a dense patch.
723
+ 15. Pixels pick 2 of 8 probes by Brick4's WRS, after visibility-only weights.
724
+ 16. Rough specular blends radiance with GGX-convolved SH2.
725
+ 17. `GPUGeometrySDFManager` is the reference for the bake; the Brixelizer port is not reused.
726
+
727
+ **From the engine's rules (E)**
728
+ 1. **Work follows the live count.** Dispatches are indirect over device counts; capacity sizes memory
729
+ only.
730
+ 2. **Bounded per-thread loops**, with budgets in tens. Each is stated with what is lost past it.
731
+ 3. **Gather per bin.** No thread's cost follows an element's footprint.
732
+ 4. **No static/dynamic category.** A row's treatment follows facts re-observed each frame, such as
733
+ "changed this frame" and its size against the voxel.
734
+ 5. **The CPU does O(changes)** and never passes over GPU-resident state.
735
+ 6. **GPU consumers sample on the GPU**, at their own resolution.
736
+ 7. **Separate passes for separate cost profiles.** Share data, not shaders.
737
+ 8. **Shader switches, not overrides or template codegen**; concrete modules.
738
+ 9. **Physical knobs in world units and seconds.** Caps are safety nets, stated as chosen numbers.
739
+ 10. **The scalable path first.** A small-n fast path keys on the runtime count.
740
+ 11. **No allocation in per-frame host code.**
741
+ 12. **Tests on all four tiers.** No mocks, hooks or `.each`; a fix is red then green.
742
+
743
+ ## 4. The reuse map
744
+
745
+ Verdicts:
746
+ - **REUSE**: as is.
747
+ - **GENERALISE**: the piece grows a parameter, and its clients move onto it.
748
+ - **EXTRACT**: the piece becomes shared, and its current owner migrates.
749
+ - **COMPOSE**: built from existing pieces.
750
+ - **NEW**: written generic.
751
+
752
+ ### 4.1 Host side
753
+
754
+ | Need | Engine machinery | Verdict |
755
+ |---|---|---|
756
+ | Mesh SDF bake, cache lifetime | `GPUGeometrySDFManager` | **GENERALISE in place**: sparse bricks in size classes with levels, `r8unorm`, cards, a budgeted bake queue (§6) |
757
+ | Mesh SDF indirection, card page tables | `OffsetAllocator` | **REUSE** |
758
+ | Window placement, nesting, exposed slabs | `ClipmapWindowSet`, `quantize_hysteretic`, `window_scroll_regions` (`core/geom/clipmap/`) | **REUSE** for both clipmaps |
759
+ | Exposed-slab flow | `GPUFluidCascadeStack.record_tick` → `window_scroll_regions` → fill pass | **REUSE as pattern**; the brick and probe passes are their own kernels |
760
+ | World and mesh brick atlases | `GPUTileAtlas3D` (r8unorm, content 8³, border 0) | **GENERALISE**: `reserve(capacity)` grows the footprint without the host handing out slots; the GPU free list owns them |
761
+ | Card pages; probe radiance and depth atlases (2-D) | `GPUProbeAtlas`'s tile placement (`index_to_grid2d`, width at `maxTextureDimension2D`, growth in rows) | **EXTRACT** a format- and tile-parameterised 2-D tile atlas; LPV keeps its 66-texel pitch on it |
762
+ | Free slot stacks | the particle pool (`shader_particle_init_free_list`, `dead[--DEAD]`) | **EXTRACT** the init pass and the pop/push chunk into `gpu_primitive/`; particles migrate |
763
+ | Growth on demand | the vgeo high-water pattern; `GPUDatabaseReadback` | **REUSE**: failures counted on the device, read back, capacity doubled, never shrunk |
764
+ | Changed world boxes | `shader_vsm_movers`, `shader_vsm_skinned_movers`, `VSMMoverTracker`, `VSM_MOVER_LAYOUT` | **EXTRACT** to a scene-level mover list with a skinned bit; VSM and this mode read it (D32) |
765
+ | SDF membership | `ShadedGeometryFlags`; `ShadedGeometrySystem` → `attach_mesh`; the row's tail padding | **GENERALISE**: an `SDFWorld` bit forwarded as `Skinned` is, mirrored into a row `flags` word (§6.1) |
766
+ | Row change stream | `GPUSceneRows.onMeshReleased` | **GENERALISE**: `onMeshWritten` beside it |
767
+ | Skinned source geometry | the rows' entry keeps the source; `GPUMeshSkinningContext.obtain_clone` | **REUSE**: a clone's SDF header aliases its source's (the hook, §6.3) |
768
+ | Material slot means; material changes | `GPUResidentMaterialContext` (`#pack_material`); `ShadeMaterial.version` | **GENERALISE**: a mean per texture slot when the slot is written (§6.6), and a signal when a material is repacked, which recapture keys on (§6.5) |
769
+ | Settings | the shadow knobs' validate → push → rebuild-on-mismatch; the `avboit` / `ssr` sub-objects | **REUSE as pattern**: `ProbeClipmapSettings` (§10) |
770
+ | Mode plumbing | `INDIRECT_LIGHTING`, `ShaderSwitchSet`, `#graph_indirect_lighting` | **REUSE**: additive (§9.7) |
771
+ | Frame graph | `graph_compute_pass`, `graph_compute_indirect_pass`, `graph_import_texture` / `_buffer`, `IndirectComputeCommandBuildPass`, `build_indirect_compute_dispatch_command` | **REUSE** |
772
+ | Profiling and stats | `GPUProfileSession`, `graph_record_stat` | **REUSE** |
773
+
774
+ ### 4.2 WGSL
775
+
776
+ | Need | Engine chunk | Verdict |
777
+ |---|---|---|
778
+ | Exact distance and sign at a point | `blas_query_sdf`, `point_query_blas_nearest`, `blas_query_volume_sign` | **REUSE** in the bake. S3 replaced the vote with UE's, `blas_query_band_sdf` over the BLAS's point and ray queries, and deleted the other two |
779
+ | A ray against one geometry | `ray_query_blas_nearest` | **REUSE** in card capture |
780
+ | The triangle at a hit | `geometry_read_triangle_vertices` | **REUSE** in card capture |
781
+ | Material at a triangle hit | `sample_material_data`, `sample_material_alpha` | **REUSE** in card capture, with a seed fixed per texel |
782
+ | Clipmap levels, finest level, blend weight | `CLIPMAP_LEVEL_STRUCT`, `clipmap_select_finest`, `chunk_clipmap_contains` | **REUSE** |
783
+ | Toroidal storage coordinate | `chunk_clipmap_storage_coord` (no production user) | **REUSE**: it gets its first users |
784
+ | Folded indirect dispatch | `chunk_folded_workgroup_index` | **REUSE** |
785
+ | Instances overlapping a box | `chunk_bvh_query_aabb_cooperative` (TLAS seam) | **REUSE**: second user |
786
+ | Mesh and node rows | `scene_read_mesh`, the scene database access chunks, `NODE3D_STRUCT` | **REUSE** |
787
+ | Octahedral direction codec | `uv_octahedral_unit_encode` / `_decode` (the one WGSL pair) | **REUSE** |
788
+ | Octahedral skirt for hardware bilinear | `texture_octahedral_skirt_texel_uv`, `texture_octahedral_skirt_uv` | **REUSE** (the environment map's, not LPV's unread border) |
789
+ | Texel solid angle | `octahedral_solid_angle` | **REUSE** |
790
+ | SH2 basis; L1 storage and diffuse resolve | `sh2_basis_at`; `convert_to_irradiance_sh`, `resolve_irradiance_sh_to_diffuse`, `get_color_from_irradiance_sh`, `METRO_L1_IRRADIANCE_STRUCT` | **REUSE** |
791
+ | GGX zonal factor | `sh2_approximate_GGX_zh` | **REUSE**; its Metro-form resolve is NEW (§9.3) |
792
+ | Specular blend and sample vector | `chunk_lpv_sample_light`'s mix by `roughness_to_mip_ratio`; `normalize(mix(r, n, α))` | **REUSE** |
793
+ | Chebyshev bound | `compute_chebyshev_weight` | **REUSE** |
794
+ | Probe weight (wrap back face, crush) | inside `lpv_mask_weights_by_visibility` | **EXTRACT** a per-probe `probe_visibility_weight`; LPV migrates |
795
+ | Pick 2 of 8 | `sample_discrete_wrs_mat2x4`; the selection inside `brick4_probe_meta_pick2` | **REUSE**; **EXTRACT** `pick2_wrs_mat2x4`, Brick4 keeps its address mapping |
796
+ | Noise | `chunk_stbn_sample_vec2`; `jitter_from_vectors` (private to Brick4's forward chunk) | **REUSE**; **EXTRACT** the hash |
797
+ | Directional lights | `directional_lights_iteration_mask`, the light database records | **REUSE** |
798
+ | Local lights at a world point | `world_light_cluster_metadata_by_texel`, `irradiance_clipmap_get_point_light_info_by_index` / `_spot_…`, `volumetrics_point_light_shadow` / `_spot_…` | **GENERALISE** the cluster keying from `IRRADIANCE_CLIPMAP_STRUCT` to a `CLIPMAP_LEVEL_ARRAY`; the light and shadow chunks **REUSE** |
799
+ | Sky for misses; final fallback | `sample_environment_color`, `get_ibl_irradiance` | **REUSE** |
800
+ | Specular split at a pixel | `compute_indirect_specular`, `tSplitSum`, inside the deferred resolve | **REUSE** |
801
+ | SDF soft-shadow penumbra | inside `shader_scene_sdf_soft_shadows` | **EXTRACT** the estimator as a pure chunk; the dense-volume shader keeps calling it. Not done (S3e): its classic estimate cannot meet §12's oracle, and the brick clipmap's is Quílez's two-sided one (§7.9) |
802
+ | Appends | `chunk_collection_u32_append` | **REUSE** |
803
+ | Parallax toward a probe's hit | LPV's iterative correction in `lpv_sample_light` | **GENERALISE** to take a depth-moment reader (§9.3) |
804
+
805
+ ### 4.3 Writing what does not exist
806
+
807
+ | Need | Verdict |
808
+ |---|---|
809
+ | Mesh SDF classify, evaluate and store passes; card placement, capture and recapture; the bake and capture queues | **NEW**, inside `GPUGeometrySDFManager`, which owns every cache's storage |
810
+ | The (geometry, material) pair bookkeeping and the row → card set table | **NEW**, on the GI, which decides what is requested |
811
+ | `mesh_sdf_sample`, `mesh_card_surface` | **NEW**, emulator-testable pure chunks |
812
+ | World brick clear, store, scroll, mover marking, coarse occupancy passes; the provider contract | **NEW** |
813
+ | `MeshSDFBrickProvider` | **NEW**, written against the same contract as any plugin |
814
+ | `brick_clipmap_trace`, `brick_clipmap_distance`, `brick_clipmap_object`, `brick_clipmap_soft_shadow` | **NEW**, emulator-testable pure chunks over seam readers |
815
+ | Probe retire, want, admit, schedule, trace, shade, accumulate, publish passes | **NEW**; the chain follows LPV's (trace → shade with feedback → temporal → border → SH) |
816
+ | `probe_clipmap_pick`, `probe_clipmap_sample_irradiance` / `_radiance` / `_sh` | **NEW**, on the extracted weight and pick |
817
+ | `resolve_irradiance_sh_to_specular` | **NEW**, beside the diffuse resolve in `l1i/` |
818
+ | `ProbeClipmapSettings`, `GPUBrickClipmap`, `GPUProbeClipmap`, `GPUProbeClipmapGI`, `BrickProvider` | **NEW** |
819
+ | A triangle voxelizer, and (a)'s per-cell triangle gather | **not written**: the caches replace both |
820
+
821
+ ## 5. Architecture
822
+
823
+ **Geometry caches** belong to `GPUGeometrySDFManager` on the geometry manager. They outlive the mode,
824
+ and any future SDF reader can use them.
825
+
826
+ **Per view**, one `GPUProbeClipmapGI`. It owns a `GPUBrickClipmap` and a `GPUProbeClipmap`, both
827
+ anchored on the view's camera, and a list of providers with the mesh provider first. It allocates on
828
+ the first frame rendered in the mode, and destroys on leaving the mode, on a settings change and with
829
+ the renderer. There is one graph scope a frame, after the G-buffer and the shadow maps and before
830
+ volumetrics:
831
+
832
+ ```
833
+ host: place brick + probe windows; scroll boxes per moved cascade (≤ 3 each)
834
+ read back last frame's failure counts → grow capacity (rare)
835
+ bake queue: ≤ mesh_sdf_bake_budget bricks a frame, only while caches fill
836
+
837
+ geometry caches (once per geometry): classify ─► evaluate ─► store ─► place cards ─► capture
838
+ │ mesh brick atlas + indirection, card pages
839
+ scene mover list (EXTRACTed, read by VSM too) + GI invalidation list
840
+ │
841
+ brick: scroll ─► movers ─► take ─► clear ─► providers (mesh, vgeo, …) ─► free ─► store ─► coarse
842
+ (pending ring, ≤ brick_build_budget a frame)
843
+ │ brick map, SDF atlas, object cells, occupancy
844
+ probe: retire ─► want (depth) ─► admit ─► schedule ─┐
845
+ ▼
846
+ trace (+ sun soft shadow) ─► shade ─► accumulate ─► publish
847
+ (rays = trace list × rays_per_probe ≤ ray_budget)
848
+ │ indirection, states, records (SH2),
849
+ │ radiance + depth atlases
850
+ pixels: weigh 8 (visibility only) ─► WRS pick 2 ─► SH2 diffuse; radiance ⊕ GGX-SH2 specular
851
+ consumers: deferred diffuse / fused pass, AVBOIT + MBOIT, water, SSR, irradiance clipmap
852
+ ```
853
+
854
+ Every dispatch is sized by a live count (E1):
855
+ - an indirect command over a count an earlier pass wrote on the device;
856
+ - or a count the host knows exactly: the scroll boxes' cells, one thread per 8×8 screen tile for
857
+ `want`, one per occupancy block for `coarse` (≤ `C_b·(N_b/4)³`), and the bake's queued bricks.
858
+
859
+ Nothing is sized by a capacity. Persistent resources are imported every frame and written as side
860
+ effects, so a frame that has no reader for them culls nothing that has to persist.
861
+
862
+ ## 6. Geometry caches
863
+
864
+ ### 6.1 What is cached, and for which rows
865
+
866
+ **A row is in the SDF world** when both hold:
867
+ - its `ShadedGeometry` carries `ShadedGeometryFlags.SDFWorld`, a new bit (128), on by default as
868
+ `CastShadow` is;
869
+ - its material is not `TransparencyMode.Transparent`. Glass does not occlude GI rays; this is (a)'s
870
+ rule, now applied at the row.
871
+
872
+ How the bit travels:
873
+ - `ShadedGeometrySystem` forwards it to `attach_mesh`, as it forwards `Skinned`. A change goes
874
+ through `shaded_geometry_announce_change` and re-attaches, as a material change does.
875
+ - `GPUSceneRows` mirrors it into a new `flags` word of the `meshes` row: bit 0, `MESH_FLAG_SDF_WORLD`.
876
+ The word sits in the row's tail padding, so the row stays 80 B.
877
+ - A row outside the SDF world is drawn by the camera and invisible to every GI ray. It occludes
878
+ nothing, emits nothing into GI and bounces nothing. That is the point of the bit: performance.
879
+
880
+ **A geometry is cached** when at least one row in the SDF world draws it and it is not virtual.
881
+ - Virtual geometry has its own provider (§7.8).
882
+ - DynamicMesh has no row, so it is absent by construction.
883
+
884
+ **What is cached, and keyed by what**:
885
+ - per geometry: the sparse SDF (§6.2–6.4) and the card layout (§6.5). Every instance and every
886
+ material shares them.
887
+ - per (geometry, material) pair: a card set, the captured contents of that layout (§6.5). Every
888
+ instance drawing the pair shares it.
889
+ - A material change recaptures that material's card sets and rebuilds nothing else.
890
+
891
+ **Ownership and lifetime.** `GPUGeometrySDFManager`, generalised in place, owns the storage of all
892
+ three and runs the bakes and captures. Its evaluator stays; its dense tiles go.
893
+ - A geometry and a pair are requested on the first `onMeshWritten` of a row in the SDF world that
894
+ draws them. The event is new, beside `onMeshReleased`.
895
+ - The GI keeps row counts per geometry and per pair on the CPU, updated by the two events
896
+ (O(changes), E5). A row that changes material moves one count to another.
897
+ - At zero rows a pair's card set is freed, and with the geometry's last row its SDF and layout go
898
+ too. A geometry or pair that comes back is baked or captured again.
899
+ - Triangles are read only by the bake, once per geometry, and by capture, once per pair and again per
900
+ material change.
901
+
902
+ ### 6.2 Grid and size classes
903
+
904
+ - **Voxel.** v = `mesh_sdf_voxel_size`, in the geometry's local units. The default 0.125 is the
905
+ world's finest voxel, so a mesh at unit scale is as fine as cascade 0.
906
+ - **Grid box.** The geometry's bounds grown by R = 4v on every side, so the band fits.
907
+ - **Bricks per axis**: `b_a = max(2, 2·⌈E_a / 14v⌉)`, with E_a the grid box's extent on axis a. The
908
+ spare voxels pad both sides evenly.
909
+ - These are Alex's size classes: 2×2×2 bricks at least, then steps of two bricks per axis,
910
+ independently.
911
+ - Even counts make the first coarser level exact, and the minimum leaves a one-brick level.
912
+ - **Safety net.** `b_a ≤ mesh_sdf_max_bricks` (default 18, i.e. 126 voxels: UE's per-mesh cap at
913
+ unit scale, §2.3). Past it, v grows for that geometry until the longest axis fits. Such a geometry
914
+ is coarser than asked, and the bake counts it.
915
+ - The cap also bounds a geometry's level-0 indirection to 18³ entries, 23 KiB.
916
+ - At the default voxel it reaches 15.75 m before a mesh coarsens.
917
+ - **Levels.** Level k has voxel v·2^k and ⌈b_a / 2^k⌉ bricks per axis, down to one brick per axis:
918
+ L = 1 + ⌈log₂ max_a b_a⌉, from 2 to 6 levels. A coarse cascade samples a coarse level (§7.7).
919
+
920
+ ### 6.3 Encoding and storage
921
+
922
+ - **Value**: signed, in UE's encoding: `e = saturate(d/(2R) + 0.5)`, R = 4 voxels of the level, in
923
+ `r8unorm`. One LSB is 8/255 = 0.031 voxel.
924
+ - **Bricks**: 8³ texels on the corners of 7³ voxels, the world's lattice (§7.2). Every geometry and
925
+ level shares one `r8unorm` `GPUTileAtlas3D`, the mesh brick atlas. Slots come from the extracted GPU
926
+ free list.
927
+ - **Indirection**: per level, one `u32` per brick: a slot, or EMPTY on one side of the surface. An
928
+ EMPTY brick has no texel within the band: EMPTY (`0x80000000`) reads +R, EMPTY inside
929
+ (`0x80000001`) reads −R. All levels of all geometries share one storage buffer; ranges come from
930
+ `OffsetAllocator`.
931
+ - Amended in S2 (2026-10-27). EMPTY first read +R on both sides. More than a band inside a solid,
932
+ a band brick below zero then met an EMPTY brick at +R, and the two read as a surface that is not
933
+ there: on Sponza, card captures and the scene march stopped on it. Alex chose the sign.
934
+ - Amended in S3 (2026-10-27), when Alex chose UE 5.4's vote (§6.4). A texel with no surface within
935
+ the band casts no ray and reads +R, so a brick with none is outside and the bake writes EMPTY
936
+ alone. EMPTY inside stays in the format and its readers; no mesh bake writes it.
937
+ - As built (S2), the same buffer is the bake's arena. It holds the bake's counters at word 0, the
938
+ frame's log and tallies, and each geometry's count of bricks still to settle, one word before
939
+ its first entry. The ring's buffer carries the frame's staging.
940
+ - That keeps evaluate at ten storage buffers, beside the five a BLAS query reads, within
941
+ `SHADE_DEVICE_FLOOR`. Classify and evaluate first bound 12 and 14.
942
+ - **Header**: `MESH_SDF_STRUCT`, 64 B per geometry id. It holds:
943
+ - grid origin and v;
944
+ - brick counts and level count;
945
+ - the levels' indirection offsets;
946
+ - the card layout's offset (§6.5);
947
+ - a state: requested, baking, resident.
948
+ - **Deep interiors** read −R (amended in S2): a solid is below zero all through, and its surface is
949
+ its one zero crossing. UE's mesh distance fields are instead a signed shell as deep as the band,
950
+ and read +R past it.
951
+ - `GPUGeometrySDFManager`'s wrap of negative distances past 4 voxels existed so that an open mesh's
952
+ false inside could not run away. The wrap is dropped (D27).
953
+ - With EMPTY signed, the band no longer bounds a false inside: an open mesh reads −R as far as its
954
+ vote calls inside. **Measured on Sponza** (S2): its geometry 102 is an open box around the
955
+ building — a bottom and four outer walls, wound outward, no top. From the building's air more than
956
+ 60% of the vote's rays meet its faces from behind (57 to 61 of 64), so that air is inside it, and
957
+ all of it reads −R, the courtyard included. With EMPTY at +R the same vote put a false floor R above the floor. At every
958
+ point the vote calls inside, at least 3 of the 64 rays leave through the open top and meet
959
+ nothing; from inside a closed mesh none does. Put to Alex.
960
+ - Amended in S3 (2026-10-27): with UE's vote, deep interiors read +R again, past a signed shell.
961
+ Measured on Sponza, over the 7 geometries checked in S2: UE's vote calls outside 401,141 texels
962
+ the 64-ray vote had inside and more than R/2 deep, 382,809 of them in nearly closed geometry 2.
963
+ 102's false inside is a floor 0.338 m deep, where the 64-ray vote filled the building's air to
964
+ 9.56 m. A ray from deeper than the shell inside a solid can stop where the vote's sign flips,
965
+ about R/2 in, as a ray down the courtyard stops on 102's false floor. Alex chose this with the
966
+ measurement before him (`ue-vote-measurement-2026-10-27.md`, in the shared notes).
967
+ - A probe inside a solid reads −R, and its rays hit at their first step (§7.2, §8.4).
968
+ - **Skinned (the hook).** A skinned row draws a clone geometry id.
969
+ - The clone's header is an alias: it names its source's id, and readers follow it once. It is
970
+ written when `obtain_clone` makes the clone, so it tracks the source through baking to resident.
971
+ - The bind pose stands at the row's node.
972
+ - TODO: a dense patch rebuilt from the deformed vertices replaces the alias (§17).
973
+ - Until then, a character whose pose strays far from its bind pose is better left out of the SDF
974
+ world. Enshrouded keeps characters out entirely.
975
+
976
+ ### 6.4 The bake
977
+
978
+ Geometries go through a host queue in request order. Each runs four steps:
979
+ 1. **classify**: one thread per (level, brick).
980
+ - It finds the exact unsigned distance from the brick's centre to the mesh with
981
+ `point_query_blas_nearest`: one BLAS query a brick.
982
+ - If that distance, less the brick's half-diagonal (6.06 voxels), is at least R, no texel can be in
983
+ the band, and the brick is EMPTY.
984
+ - Then **sign** (amended in S2): a 64-lane workgroup per classified brick. A brick classify dropped
985
+ casts the 64-ray vote from its centre, a ray a lane, and its last lane writes EMPTY or EMPTY
986
+ inside. A kept brick's workgroup leaves at once.
987
+ - Amended in S3 (2026-10-27): sign is gone. UE's vote casts no ray where the surface is not
988
+ within the band, so classify settles a brick it drops as EMPTY, as before S2.
989
+ - Classify first cast the vote itself, a thread's 64 rays one after another. It then cost
990
+ 1,250 µs at the median on the 4090 against 89 µs without the vote, and 2,835 µs on the iGPU,
991
+ 28 ms at worst. As its own pass, sign costs 56 µs at the median on the 4090 (761 µs at p90,
992
+ 919 µs at worst), and classify is back to its 89 µs. On the iGPU sign costs 1,832 µs at the
993
+ median, 6.1 ms at p90 and 31 ms at worst, against the serial vote's 2,835 µs, 4.5 ms and 28 ms:
994
+ there the cost is the vote's rays either way, all in the frame that admits a large geometry,
995
+ and they are not budgeted.
996
+ 2. **evaluate**: a thread per texel of each surviving brick, eight 64-lane workgroups a brick, as the
997
+ dense build maps them.
998
+ - Each texel is `blas_query_sdf`, as the dense build evaluates it: exact nearest point plus the
999
+ 64-ray vote at 60%.
1000
+ - Amended in S3 (2026-10-27): each texel is `blas_query_band_sdf`, UE 5.4's vote (§2.3). It
1001
+ takes the nearest point within the band, and only there casts 98 rays one band long, in UE's
1002
+ directions; the texel is inside past 25% back faces.
1003
+ - A field is two-sided while one of its holders' materials draws both sides. Then no face is a
1004
+ back face, and it casts no ray at all. A change of its holders' side bakes it again at the
1005
+ next bake, so holds that move within a frame bake nothing.
1006
+ - A brick whose texels are all at |d| ≥ R is EMPTY after all, on the side most of its texels are.
1007
+ Under UE's vote such a texel cast no ray and reads +R, so the brick is EMPTY (S3).
1008
+ - Amended in S2 (2026-10-27). This revision first had one 64-lane workgroup per brick, eight
1009
+ texels a lane. A lane then runs its eight texels' votes one after another, and a single brick
1010
+ cost more than the 1 ms budget (see **Budget**).
1011
+ 3. **store**: a slot is popped and 512 bytes written.
1012
+ - As built, the frame's take hands out no more bricks than the free list has slots, so no pop
1013
+ fails.
1014
+ - A take held back by the slots logs itself starved. The host then doubles the atlas and the free
1015
+ list, and the held bricks wait on the ring for a later frame. This replaces counting failed pops.
1016
+ 4. **cards**: the layout's placement (§6.5). Capture runs per pair once the layout exists.
1017
+
1018
+ **Budget.** At most `mesh_sdf_bake_budget` bricks are evaluated a frame.
1019
+ - A brick costs 512 × (1 + 64) ≈ 33k BLAS queries, and what that takes follows its geometry's tree.
1020
+ Under UE's vote (S3) it is at most 512 × (1 + 98), and only texels with the surface within the band
1021
+ cast rays, each one band long.
1022
+ - This is a time knob like `shadow_update_budget`. Its default, **23**, is set by measurement against
1023
+ 1 ms a frame on the 4090.
1024
+
1025
+ The mapping, measured in S2 on Sponza's largest geometry (6,722 bricks, 2,211 triangles), over its
1026
+ first N bricks with timestamp queries. All three write the same bytes.
1027
+ - *8 a lane*: one 64-lane workgroup a brick, eight texels a lane (this revision's first).
1028
+ - *1 a thread*: a thread a texel (as built).
1029
+ - *1 ray a lane*: a workgroup a texel, a vote ray a lane.
1030
+
1031
+ | bricks | 4090: 8 a lane | 4090: 1 a thread | 4090: 1 ray a lane | iGPU: 8 a lane | iGPU: 1 a thread | iGPU: 1 ray a lane |
1032
+ |---:|---:|---:|---:|---:|---:|---:|
1033
+ | 1 | 1,208 µs | 103 µs | 36 µs | 1,705 µs | 806 µs | 1,566 µs |
1034
+ | 8 | 1,564 µs | 142 µs | 142 µs | 3,481 µs | 2,107 µs | 9,062 µs |
1035
+ | 64 | 2,009 µs | 234 µs | 2,374 µs | 14,425 µs | 12,690 µs | 72,844 µs |
1036
+ | 512 | 4,212 µs | 2,169 µs | 23,201 µs | — | — | — |
1037
+
1038
+ **The default.** Measured over Sponza's whole fill, with budgets from 16 to 192 cycled in blocks of
1039
+ frames in one process, so that each saw every stretch of the fill.
1040
+ - Sponza has 103 geometries, all coarsened by the cap. Its glTF merges each material's copies into
1041
+ one mesh that spans the building.
1042
+ - On the 4090, evaluate costs 798 µs plus 8.6 µs a brick at the median, which reaches 1 ms at 23
1043
+ bricks.
1044
+ - At 23, the whole fill's evaluate costs 840 µs a frame at the median, 1.66 ms at p90 and 5.3 ms at
1045
+ worst. Every geometry is resident after 5,712 frames of baking.
1046
+ - On the AMD iGPU, 23 bricks cost 26 ms a frame at the median and 79 ms at worst. No budget fits
1047
+ 1 ms there: one brick costs 2.3 ms. A frame of 2,048 bricks outlasted the 2 s TDR and lost the
1048
+ device.
1049
+
1050
+ **UE's vote differs** (§2.3). It casts 98 rays, each only one band long, and counts back faces past
1051
+ 25%, never on two-sided triangles. The bake keeps `GPUGeometrySDFManager`'s vote (64 unbounded rays,
1052
+ 60%), which Alex has confirmed correct. If the bake measures slow, UE's band-length rays are the first
1053
+ lever, since a ray that stops at the band is far cheaper than one that crosses the mesh. That changes
1054
+ which points vote inside, so it would be measured against the current vote first. It is not needed to
1055
+ meet the 4090's 1 ms. Whether the iGPU's cost above calls for it is put to Alex.
1056
+
1057
+ **Adopted in S3 (2026-10-27).** Measured against the 64-ray vote (`ue-vote-measurement-2026-10-27.md`,
1058
+ in the shared notes):
1059
+ - the 4090's evaluate is the same at the median, 559 + 5.58 µs a brick against 568 + 5.54;
1060
+ - the iGPU's is 16–19% less a frame;
1061
+ - sign's 5.0 ms over Sponza's fill is gone.
1062
+
1063
+ Alex chose it.
1064
+
1065
+ **Completion.** The header turns resident, and the GI invalidates the world boxes of the geometry's
1066
+ rows in the SDF world (§7.4). The CPU knows those rows from its bookkeeping (§6.1). Each box is the
1067
+ row's geometry box under its entity's `Transform64`, projected as `GPUSceneRows.compute_world_bounds`
1068
+ projects one.
1069
+
1070
+ ### 6.5 Surface cards
1071
+
1072
+ **Placement** runs on the bake's level-0 occupancy once the geometry is resident: five passes a
1073
+ geometry, as built in S2 (below). It is UE's surfel clustering (§2.3) at brick granularity.
1074
+ - The directions are ±X, ±Y, ±Z of local space.
1075
+ - Along a direction δ, a column is a line of bricks.
1076
+ - A **run start** is an occupied brick at layer z whose predecessor along δ is empty or outside the
1077
+ grid. Its m is the layer after the previous run's end (0 for the first run), which is UE's MinRayZ.
1078
+ - A card (δ, [k₀, k₁)) looks along δ through brick layers k₀ to k₁ − 1.
1079
+ - In each column it sees the first surface after layer k₀.
1080
+ - It covers a run start (z, m) when m ≤ k₀ ≤ z < k₁: nothing occupied lies between its near face
1081
+ and the run.
1082
+ - The search:
1083
+ - Each direction starts with one card over the whole grid, its outer projection. This covers each
1084
+ column's first run.
1085
+ - Each further card splits a slab of some direction at the layer that newly covers the most run
1086
+ starts. The split's far part covers from its own near face whatever the near part loses, so
1087
+ coverage never shrinks.
1088
+ - It stops when every run start is covered, or at 32 cards a geometry, UE's ceiling (its default is
1089
+ 12). A run start left uncovered reads the material mean (§6.6).
1090
+ - A convex mesh gets six cards; a room or an atrium gets interior slabs.
1091
+
1092
+ **The layout**, per geometry.
1093
+ - A card's texels are the brick grid projected along δ at level-0 resolution: one 8×8-texel page per
1094
+ column, on the corner lattice of the bricks' faces.
1095
+ - A page exists only where the slab holds an occupied brick in that column. The layout records which
1096
+ columns those are.
1097
+
1098
+ **Card sets**, one per (geometry, material) pair: the layout's contents for that material.
1099
+ - Per card, a page table: one `u32` per column of the card, naming its page. As built, the tables
1100
+ are the layout's, shared by every card set of the geometry, and a card set's pages are a run of
1101
+ atlas tiles from `OffsetAllocator`, in the layout's page order (below).
1102
+ - A header: on the device the geometry, the material's resident id, the first tile and the emissive
1103
+ scale s_e; on the host the material version captured and a state (waiting for its layout,
1104
+ capturing, resident).
1105
+ - Pages live in the extracted 2-D tile atlas as two `rgba8unorm` planes:
1106
+ - √(diffuse albedo), and depth;
1107
+ - emissive / s_e, and a channel kept at 0.
1108
+ - **Diffuse albedo** is albedo × (1 − metalness), Lumen's diffuse colour. It is stored as its square
1109
+ root, as UE stores it, which spends the 8 bits where dark albedos need them.
1110
+ - **Emissive** is divided by s_e, the largest component of the material's emissive factor. The
1111
+ resident emissive textures are 8-bit, so emissive never exceeds s_e, and 8 bits under that scale
1112
+ lose nothing the source had.
1113
+ - **Depth** is the surface's distance from the slab's near face over the slab's depth, mapped onto
1114
+ [1/255, 1]. A texel whose ray found nothing in the slab stores 0.
1115
+ - A texel costs 8 B and a page 512 B, the size of one SDF brick.
1116
+
1117
+ **The row → card set table**: one `u32` per `meshes` row, written by the GI on `onMeshWritten` from
1118
+ the row's pair.
1119
+ - It holds `GPU_DATABASE_NULL` for a row with no card set: a virtual geometry, or a pair still
1120
+ capturing.
1121
+ - A skinned row's pair names the source geometry, which its CPU entry keeps.
1122
+
1123
+ **Capture**, one thread per page texel of a pair:
1124
+ 1. A ray in local space starts at the slab's near face and runs along δ, with t ≤ the slab's depth,
1125
+ through `ray_query_blas_nearest`.
1126
+ 2. Alpha is treated as the path tracer treats it. A hit is opaque with probability equal to its
1127
+ opacity (`sample_material_alpha`), drawn from the texel's fixed seed.
1128
+ - A transparent draw continues the ray past the hit, at most 4 times (chosen). Past that the texel
1129
+ is empty.
1130
+ 3. At the opaque hit, `sample_material_data` runs with the material's resident row and an identity
1131
+ instance transform (the card is in local space).
1132
+ - Its random state is seeded from (pair, texel), which fixes its stochastic bilinear tap and its
1133
+ dither.
1134
+ - A recapture of an unchanged material therefore writes the same bytes.
1135
+ 4. The texel stores √(albedo × (1 − metalness)), depth, and emissive / s_e.
1136
+
1137
+ **Recapture.**
1138
+ - `GPUResidentMaterialContext` signals when it repacks a material whose version moved (§4.1). The GI
1139
+ keeps the reverse map from a material to its pairs and queues each for recapture: O(changes), E5.
1140
+ - A recapture rewrites the pair's pages in place, since the layout is the geometry's and has not
1141
+ changed. Until then, the pair's hits read the previous capture.
1142
+ - A material that changes every frame stays queued, and its GI lags by the queue's wait. The budget
1143
+ bounds what that costs. UE has the same lag, and does not notice a material change by itself
1144
+ (§2.3).
1145
+
1146
+ **Budget.** At most `card_capture_budget` pages a frame: new pairs first, then recaptures in the
1147
+ order queued.
1148
+ - A page costs 64 texels × (a ray, up to 4 alpha draws, a material sample).
1149
+ - This is a time knob. Its default, 16,384 pages, is derived against 1 ms a frame on the RTX 4090, as
1150
+ the bake's is.
1151
+ - Sponza's 103 card sets (154,138 pages) were recaptured with the budgets interleaved frame by frame
1152
+ in one process. 16,384 pages cost 0.33, 0.43 and 0.87 ms at the median in three runs, and
1153
+ 32,768 went past 1 ms in all three: the cost turns steeply between the two.
1154
+ - The runs shared the 4090 with another load of 40–73%, which is in the medians. The least loaded
1155
+ frames cost 0.11 ms at 16,384.
1156
+ - At the default Sponza's cards are captured in 10 frames.
1157
+ - On the AMD iGPU (RDNA2) a page costs 0.78 µs. 16,384 pages cost 33.5 ms at the median, and about
1158
+ 1,290 fit 1 ms (1,024 cost 0.80 ms).
1159
+
1160
+ **As built in S2.**
1161
+ - Placement is five passes a geometry, each sized by a count the host knows or by the merge's
1162
+ dispatch:
1163
+ - histogram, a thread a column of the six directions: run starts by (m, z);
1164
+ - split, a thread a direction: its 2-D prefix sums, then its greedy splits by gain;
1165
+ - merge, one thread: the six directions' splits taken by gain, the global greedy; the card records;
1166
+ the page pass's dispatch;
1167
+ - pages, a thread a column of every card;
1168
+ - log.
1169
+ - Placement runs in a range sized for any layout of the grid. Its log record gives the columns and
1170
+ pages it took. On that readback the geometry gets a range of exactly that size, and the next bake
1171
+ copies the layout into it and gives the placement's range back.
1172
+ - The layout is then its header, the records, the column tables and the page list:
1173
+ 131 + columns + pages words.
1174
+ - At most 7 geometries are placed a frame, ⌊1 ms / 140 µs⌋ on the 4090.
1175
+ - A recapture writes the record, s_e included, at its first page. A recapture longer than a frame
1176
+ reads its pages not yet recaptured under the new s_e until it finishes.
1177
+ - Measured over Sponza's fill (103 geometries, one material each):
1178
+ - 12 cards a geometry at the median, 26 at most, none at the ceiling;
1179
+ - 1,322 pages a geometry at the median, 154,138 in all, 79 MB of atlas; the layouts 391,055 words,
1180
+ 1.5 MB.
1181
+ - Placement costs 140 µs a geometry at the median on the 4090, and 220 µs on the iGPU. The split pass
1182
+ is most of it, 76 µs and 130 µs: its six threads walk up to 26 steps over every layer each, 2.3 ms
1183
+ at worst on the 4090.
1184
+
1185
+ ### 6.6 Material at a hit
1186
+
1187
+ `mesh_card_surface(p, n, row) -> surface`:
1188
+ 1. The row → card set table gives the card set. If it is null, go to step 6. The row's node gives
1189
+ `global`. Move p and n into local space, with the inverse taken on demand as the scene's other
1190
+ readers take it.
1191
+ 2. Take the directions that face the surface. For each axis a with n_a ≠ 0, the cards look along
1192
+ −sign(n_a)·e_a, with weight n_a², as UE weighs them.
1193
+ 3. Scan each such direction's cards, which are sorted by near layer and number at most 32 in all. A
1194
+ card passes when both hold:
1195
+ - its slab holds p's depth within the tolerance τ;
1196
+ - its nearest texel's stored depth is within τ of p's depth.
1197
+ Otherwise the card sees something in front of p.
1198
+
1199
+ τ is 1.5 voxels of the hit's cascade, in local units, plus one LSB of the slab. That is UE's bias
1200
+ for a global-SDF hit, three half-voxels of its clipmap (§2.3). A hit is only as exact as its
1201
+ cascade, so the tolerance must grow with it.
1202
+ 4. Within a direction, the passing card nearest the surface serves.
1203
+ 5. Each serving card gives its nearest texel, and the texels are blended by n_a², as UE blends every
1204
+ card that passes:
1205
+ - diffuse albedo, Σ w·(stored)² / Σ w;
1206
+ - emissive, Σ w·stored·s_e / Σ w.
1207
+ - One texel a card is enough: UE's four depth-weighted taps per card smooth what a probe's many
1208
+ rays average anyway.
1209
+ 6. With no passing card, or no card set (a virtual geometry, a plugin's object, a pair still
1210
+ capturing), the hit takes the **material mean**:
1211
+ - diffuse: the colour factor × the albedo slot's mean × (1 − the metallic factor × the ORM slot's
1212
+ mean metalness);
1213
+ - emissive: the emissive factor × the emissive slot's mean.
1214
+ `GPUResidentMaterialContext` computes a slot's mean when it writes the slot: one reduction per
1215
+ upload (§4.1).
1216
+ - UE has no such fallback: a hit no card sees is opaque black. Here it keeps the bounce's energy
1217
+ roughly right.
1218
+
1219
+ Cost per hit:
1220
+ - one table entry, one row and one node read;
1221
+ - for each facing direction, a scan of its cards with a page and two texel loads per candidate;
1222
+ - no material evaluation.
1223
+
1224
+ As built in S2, `mesh_card_surface(card_set, p, n, tolerance)` takes the card set and p and n in
1225
+ local space: steps 2–5. The table lookup and the move to local space are the caller's: the
1226
+ MeshCards debug view's now, the hit shading's in S4. The material mean (step 6) comes with S4.
1227
+
1228
+ **As built (S4d, 2026-10-28)**:
1229
+ - **Steps 1 and 6** are `probe/chunk_probe_clipmap_hit_surface.js`, around `mesh_card_surface`. The
1230
+ row's node moves the hit into local space by `mat4_inverse`, the normal by the transpose of the
1231
+ node's linear part, and the tolerance by the transform's mean scale, the cube root of its
1232
+ determinant. Row 0 names no object and is black.
1233
+ - **The texture slots' means** are `material/resident/shader_resident_texture_means.js`, two passes
1234
+ `GPUResidentMaterialContext.build_textures` records after it writes the slots: a lane a row of a
1235
+ slot's 64, then a thread a slot over its rows. No thread reads more than 64 values. The means are
1236
+ stored as the atlas stores texels, so an albedo's is premultiplied by its coverage and `rgb / a` is
1237
+ the mean colour of what the slot covers. They live in `buffer_texture_means`, which doubles when the
1238
+ slots outgrow it.
1239
+ - The four layout constants moved out of the material context into
1240
+ `RESIDENT_MATERIAL_TEXTURE_LAYOUT.js`, which the passes and their readers share.
1241
+ - On the device, Sponza: 70 slots, each mean within 7.5e-7 of the atlas read back and averaged on
1242
+ the CPU, on both GPUs.
1243
+
1244
+ ## 7. The brick clipmap
1245
+
1246
+ ### 7.1 Cascades
1247
+
1248
+ - `C_b` cascades (`brick_cascade_count`, default 6), each a window of `N_b³` cells
1249
+ (`brick_cascade_resolution`, a power of two, default 32).
1250
+ - A cell is one brick of 7 voxels a side. The voxel is `h_c = h₀·2^c` (`brick_voxel_size` = h₀,
1251
+ default 0.125 m).
1252
+ - At the defaults, a cell is 0.875 m at cascade 0, and the windows span 28, 56, 112, 224, 448 and
1253
+ 896 m.
1254
+ - h₀ = s₀/8 puts eight voxels across one probe cell at the probe defaults (§8.1).
1255
+ - **Placement** is `ClipmapWindowSet` (size `N_b`, step 1, hysteresis 0.1 cells, the fluid's
1256
+ value), coarsest first. Each child is held inside its parent by `clamp_corner` with a one-parent-
1257
+ cell margin, so a ray leaving cascade c is inside c + 1.
1258
+ - As built (S3): the fluid's `FluidCascadePlacement` already composed these with a jump that
1259
+ re-places the stack, and is generalised into `ClipmapCascadePlacement` (`core/geom/clipmap/`)
1260
+ with the step, hysteresis and margin as options. The fluid keeps its own.
1261
+ - **Storage wraps**: a cell sits in storage cell `cell mod N_b` (a mask, since `N_b` is a power of
1262
+ two). Cascades stack along z of one texture.
1263
+
1264
+ ### 7.2 Brick layout and encoding
1265
+
1266
+ - **Lattice.** 8³ texels sit on the corners of the brick's 7³ voxels. Texel `t` is at voxel
1267
+ `7·cell + t`; texel 7 duplicates the next brick's texel 0, and every brick computes all 512 of its
1268
+ own.
1269
+ - **Lookup.** The atlas texel coordinate is `slot_origin + 0.5 + (p − cell_min)/h`, with the local
1270
+ part in [0, 7]. Hardware trilinear never reads a neighbouring slot, and there is no border pass.
1271
+ This is the UE page, and the mesh bricks use the same lattice (§6.3).
1272
+ - **Value.** Signed, `e = saturate(d/(2R) + 0.5)` with R = 4 voxels of the cascade, decoded
1273
+ `d = 2R·(e − 0.5)`.
1274
+ - One LSB is 0.031 voxel, UE's precision.
1275
+ - `r8unorm` storage writes need `texture-formats-tier1`, which is on `SHADE_DEVICE_FLOOR`.
1276
+ - **Hit.** A ray hits when d < ½ voxel of its cascade (UE's surface expand), so a wall thinner than a
1277
+ voxel stays a hit.
1278
+ - **Normal.** The field's gradient, which points out of the solid.
1279
+ - **Inside.** A ray that starts inside a solid reads a negative distance at its first step and hits
1280
+ there at once. §8.4 counts it as a back face.
1281
+ - **Filter precision.** RDNA2 rounds bilinear weights to 1/256 (measured in the octahedral skirt
1282
+ work). Neighbouring texels differ by at most one voxel (|∇d| ≤ 1), so the weight error is at most
1283
+ 1/256 voxel per axis, about 1/128 of the hit threshold.
1284
+
1285
+ ### 7.3 Storage
1286
+
1287
+ **Brick map**: `r32uint`, `N_b × N_b × N_b·C_b`. Each entry is one of:
1288
+ - `0xFFFFFFFF`, **UNKNOWN**: not classified since entering the window. The engine's null.
1289
+ - `0x80000000`, **EMPTY**: no surface within one voxel of the cell, outside.
1290
+ - `0x80000001`, **EMPTY inside** (S3): the same, inside a solid, on the side most of its staged
1291
+ texels are on, as a mesh brick's EMPTY is (§6.3). A ray that starts in one hits at once (§7.2).
1292
+ - a slot index.
1293
+ - Between free and store only, `0x80000002` marks a cell that needs a brick and holds no slot yet.
1294
+
1295
+ **Occupancy**: `r32uint`, `(N_b/4)³` blocks per cascade, stacked. The value is the count of the
1296
+ cells among a block's 64 that a ray must read: bricks, UNKNOWN and EMPTY inside. 0 means the tracer
1297
+ may skip the whole block.
1298
+ - As built (S3): blocks are in storage space, as the map is. A window whose corner is not a
1299
+ multiple of 4 puts cells of both its ends in one block, so a ray clamps a block it skips to the
1300
+ window. The window's step stays one cell.
1301
+
1302
+ **SDF atlas**: the `GPUTileAtlas3D` above, usage `TEXTURE_BINDING | STORAGE_BINDING`, sampled with
1303
+ a linear clamp sampler.
1304
+
1305
+ **Object cells**: a storage buffer, 64 `u32` per slot. Entry i is the `meshes` row whose surface is
1306
+ nearest in the brick's i-th 2³-texel cell.
1307
+ - 0 means none: row 0 is the scene root and never a mesh.
1308
+ - 256 B a slot, against (a)'s 1 KiB material lattice.
1309
+
1310
+ ### 7.4 What is built each frame
1311
+
1312
+ **Pending cells** live in a persistent FIFO ring of *storage* cell keys (cascade + storage index,
1313
+ one word). A per-storage-cell pending bit keeps any key from appearing twice.
1314
+ - A taken key builds whatever world cell its storage slot holds at that moment, decoded from the
1315
+ current window. A cell that scrolled out while queued is therefore never built, and the cell that
1316
+ replaced it is.
1317
+ - The ring never holds a stale entry, and it holds every key at most once: `C_b·N_b³` words, 768 KiB
1318
+ at the defaults.
1319
+ - As built (S3): the ring's capacity is the power of two at or past `C_b·N_b³`, 1 MiB at the
1320
+ defaults, because its head and tail run on through the u32 wrap and a power of two divides it.
1321
+ - A key's pending bit clears in free, once the key is off the ring and built, so a mover may
1322
+ queue it again.
1323
+
1324
+ The ring is fed by three passes:
1325
+ - **scroll** (one thread per exposed cell, a count the host knows from its scroll boxes):
1326
+ - the storage cell's old entry, if a slot, is pushed to the free list (the cell it belonged to has
1327
+ left the window);
1328
+ - the entry becomes UNKNOWN;
1329
+ - the key is queued unless already pending.
1330
+ - **movers** (one thread per (occupancy block, box) pair):
1331
+ - The boxes are:
1332
+ - the scene mover list's, except boxes flagged skinned, because skinned rows stand in bind pose
1333
+ (the hook: a dense patch reads them, §6.3);
1334
+ - the GI's invalidation list: boxes the host writes on bake completions (§6.4) and on SDF
1335
+ membership changes it sees through `onMeshWritten`, and boxes providers append on the device
1336
+ (§7.6).
1337
+ - Every box is expanded by that cascade's R.
1338
+ - The resolution cull: a box whose diagonal is under half a voxel of the cascade is skipped there.
1339
+ - An overlapping pair tests the block's 64 cells (bounded) and queues the overlapped ones.
1340
+ - The pair count is blocks × boxes: it follows the box count and never a box's footprint (E3).
1341
+ - Past 1,024 boxes (UE's full-recapture threshold), or a list past its capacity, every key of every
1342
+ cascade is re-queued instead: one pass over the keys rather than millions of pairs.
1343
+ - As built (S3d):
1344
+ - The movers' command, one thread, reads the scene list's count and the host's row count and
1345
+ writes either the pair dispatch or the full re-queue's, into a buffer of its own that the
1346
+ movers and the re-queue only read.
1347
+ - A pair skips a pose-only box (bind pose, the hook). Otherwise it tests its block's 64 cells
1348
+ against the box grown by the cascade's band, each cell's world position decoded from the
1349
+ window.
1350
+ - A row's box is read from the `meshes` table on the device. The host's list comes from the GI's
1351
+ holds: rows drawing a geometry whose bake completed, and rows whose SDF membership changed.
1352
+ They are rows as the tables address them, `row_of_entity`, not entities.
1353
+ - Entities were what the first device run listed. Every completion rebuilt its neighbour's
1354
+ box, and the cells inside Sponza's hull were never rebuilt. Once that was fixed, a build
1355
+ made under caches turning resident is the same, cell by cell, as one made after they are
1356
+ all resident.
1357
+ - A fresh clipmap skips the movers: its scroll has queued every cell. On the iGPU, the first
1358
+ frame's joins and movers, about 200 boxes the size of Sponza, had cost 35.8 ms for nothing.
1359
+ - Measured on Sponza: the movers cost 3 µs at the median on the 4090 (25 µs at p90, 524 µs at
1360
+ worst), and 1.6 µs on the iGPU (0.85 ms at worst). An idle frame of the whole build is now
1361
+ 19–20 µs on the 4090 and 13–14 µs on the iGPU.
1362
+ - **take** (one thread): `n = min(count, brick_build_budget)` keys leave the ring, each with a build
1363
+ slot 0..n−1, and the indirect commands are written.
1364
+ - As built (S3): no more than the free list's slots, as the mesh bake's take is (§6.4). Every cell
1365
+ taken may need a slot, so no pop of store's fails. A take held back counts itself starved,
1366
+ and the host grows the capacity on the readback. That replaces counting failed pops and
1367
+ re-queueing their cells.
1368
+ - The commands, with the taken keys' first and count, go into a buffer of their own that every
1369
+ later pass binds read-only and dispatches through. A dispatch that writes a buffer cannot use
1370
+ it as its indirect command, and free and store write the free count (the device's validation
1371
+ refused the first build, which kept them in one buffer).
1372
+
1373
+ ### 7.5 The build
1374
+
1375
+ - **clear**: one thread per staging word. Distance bytes become 255 (+R) and objects 0.
1376
+ - **providers**: in registration order, each its own indirect passes over the taken keys (§7.6).
1377
+ - **free**: one thread per taken key.
1378
+ - `needs_brick` holds when some staged texel has |d| < 1 voxel. Every point of the cell is within
1379
+ √3/2 voxel of a texel and |∇d| ≤ 1, so a surface crossing the cell always qualifies.
1380
+ - If not, and the entry is a slot, the slot is pushed and the entry becomes EMPTY.
1381
+ - As built (S3): a workgroup a taken cell, eight texels a lane. Its last lane decides, so that
1382
+ nothing waits on a barrier. A cell that needs no brick becomes EMPTY on the side most of its
1383
+ 512 texels are on. One that needs a brick and holds no slot is marked for store.
1384
+ - **store**: one workgroup per cell that needs a brick.
1385
+ - The slot is the existing one, or one popped by lane 0.
1386
+ - A failed pop leaves the entry UNKNOWN, counts the failure for growth, and re-queues the cell.
1387
+ - Otherwise the 512 staged bytes go into the atlas tile and the 64 objects into the object cells.
1388
+ - As built (S3): a workgroup a taken cell. Lane 0 pops for a marked cell, writes the entry, and
1389
+ hands the slot to the other lanes through `workgroupUniformLoad`. Take's bound keeps every
1390
+ pop from failing.
1391
+ - **coarse**: one thread per occupancy block of every cascade touched this frame. It counts the
1392
+ block's non-EMPTY cells.
1393
+ - As built (S3): a 64-lane workgroup per taken cell recounts that cell's block, a lane a cell,
1394
+ sized by take's count. Scroll marks each block it exposes as all to read until its cells are
1395
+ built, since a ray must not skip a cell it should read from the next cascade out. A first
1396
+ version counted every block of every cascade each frame: 31 µs a frame on the iGPU with
1397
+ nothing to build.
1398
+ - Measured on Sponza with no provider yet, so every cell builds EMPTY. On the 4090 the first
1399
+ frame costs 332 µs, scrolling all 196,608 cells in 52 µs, and a frame of the fill (4,096
1400
+ cells) 31–42 µs. An idle frame costs 10–14 µs, the floor of five passes. On the iGPU the
1401
+ first frame costs 3.45 ms, a fill frame 545–562 µs, an idle one 7–19 µs. In the fill a block
1402
+ is recounted by each of its taken cells, about 140 µs of the iGPU's frame. Store's first
1403
+ dispatch costs 249 µs on the 4090 and 2.06 ms on the iGPU, once.
1404
+
1405
+ Frees run before pops (separate dispatches), because a stack under concurrent push and pop is not
1406
+ safe. The staging is 768 B a build slot: 3 MiB at the default budget.
1407
+
1408
+ ### 7.6 The provider contract
1409
+
1410
+ This is the plugin system.
1411
+
1412
+ **Host interface.**
1413
+ - A `BrickProvider` has one method, `graph_write_bricks(graph, ctx)`.
1414
+ - `GPUProbeClipmapGI.add_provider(provider)` and `remove_provider(provider)` manage the list.
1415
+ - The mesh provider is registered first and is written against the same contract as any plugin.
1416
+ - `ctx` holds:
1417
+ - the taken keys, with their count on the device;
1418
+ - the brick levels uniform;
1419
+ - the staging: distance bytes and objects;
1420
+ - the scene database and the TLAS;
1421
+ - the invalidation append list.
1422
+
1423
+ **The contract.**
1424
+ 1. **Ownership.** A workgroup owns whole taken cells: within a pass no two threads touch the same
1425
+ staged word, and there are no atomics.
1426
+ 2. **Distance.** Per texel, `staged = min(staged, q(d))`, where q is the shared encoding of §7.2.
1427
+ - q is monotone, so the minimum of the bytes is the byte of the minimum.
1428
+ - The order of providers cannot change the result.
1429
+ 3. **Object.** Per 2³ cell, the provider's row at its own nearest texel replaces the staged object
1430
+ when the provider's cell minimum is below the staged cell minimum (taken from the staged bytes
1431
+ before its own merge). Ties keep the staged object.
1432
+ 4. **Safety.** A provider may under-estimate distance, which only slows steps. It never
1433
+ over-estimates, which would tunnel.
1434
+ 5. **Objects are `meshes` rows**, so a hit finds its material through the row (§6.6). A provider that
1435
+ cannot name a row writes 0, and its hits take the material of no row: zero albedo, counted.
1436
+ 6. **Invalidation.** When a provider's data for a region changes (streaming, an edit), it appends that
1437
+ world box to the invalidation list, and next frame's movers queue the cells.
1438
+
1439
+ A provider sees every taken key. One with nothing in a cell writes nothing and pays only its own
1440
+ early-out.
1441
+
1442
+ ### 7.7 The mesh provider
1443
+
1444
+ `MeshSDFBrickProvider` runs one 64-lane workgroup per taken key.
1445
+
1446
+ **Gather.** A TLAS cooperative query with box = cell ⊕ R_c. The leaf accept takes a row when all of
1447
+ these hold:
1448
+ - `MESH_FLAG_SDF_WORLD` is set;
1449
+ - its geometry's header is resident (a skinned clone resolves through the alias, the hook);
1450
+ - the resolution cull passes: box diagonal ≥ ½ voxel of the cascade.
1451
+ - UE uses max(20 cm, ½ voxel) and exempts emissive objects.
1452
+ - Here an emissive object under the cull is out of that cascade. The ½-voxel hit would fatten it
1453
+ into a lamp a voxel wide, and at cascade 5 that is 4 m.
1454
+ - the geometry is not virtual (a virtual geometry has no header).
1455
+
1456
+ **Per instance**, up to 64 in LDS:
1457
+ - the inverse of `node.global`, and the instance's world box;
1458
+ - σ, the smallest axis scale. It is exact for uniform scale and an under-estimate otherwise (contract
1459
+ 4). UE scales the same way;
1460
+ - the level `k = clamp(⌊log₂(h_c / (σ·v))⌋, 0, L − 1)`, the coarsest level no coarser than the
1461
+ cascade.
1462
+ - Inside the clamp, its voxel is within a factor of two of the cascade's, and its band
1463
+ (4·σ·v·2^k) reaches past half the cascade's (4·h_c).
1464
+ - Past a level's band a sample under-estimates (contract 4). That only slows steps, and it can only
1465
+ keep `needs_brick` true, never make it false.
1466
+ - At the clamps: an instance scaled up past the cascade's voxel samples level 0, coarser than
1467
+ asked. A small geometry at a far cascade samples its one-brick level.
1468
+ - Past 64 instances, the rest are dropped and counted; a dropped instance can leave a hole. UE loops
1469
+ its LDS passes instead and has no cap, at the price of an unbounded loop. The cap is chosen: coarse
1470
+ cascades are where it binds, since a 28 m cell at cascade 5 holds every instance over the 2 m cull.
1471
+ The LDS is 64 × 64 B.
1472
+
1473
+ **512 texels**, eight a lane: the minimum over instances of `σ·mesh_sdf_sample(header, k, M⁻¹·p)`,
1474
+ with the argmin row.
1475
+ - First the box test, UE's early-out: an instance whose box lies farther than the texel's running
1476
+ minimum is skipped. At coarse cascades most of the 64 are only this test.
1477
+ - `mesh_sdf_sample`:
1478
+ - outside the grid box, the distance to the box plus R. This is a true lower bound: the surface lies
1479
+ inside the bounds, which lie at least R inside the box. UE instead adds the box distance to the
1480
+ SDF at the clamped point;
1481
+ - in an EMPTY brick, ±R by its side (§6.3);
1482
+ - in a slot, one hardware trilinear tap of the mesh brick atlas.
1483
+ - Per 2³ cell, the argmin row of the cell's nearest texel. Then the merge (contract 2 and 3).
1484
+
1485
+ **Cost.** Per texel, at most 64 box tests, plus one 3×4 transform, one indirection load and one tap
1486
+ for each instance the box test lets through. It follows the instances in the cell, never a triangle
1487
+ count (E3), and no triangle is read.
1488
+
1489
+ **As built (S3c).**
1490
+ - The box test skips an instance whose box lies farther than the running minimum, or than zero
1491
+ when the minimum is inside a solid. So a deeper overlapping instance is still sampled, and the
1492
+ minimum does not depend on the order of the instances. Under non-uniform scale it can skip an
1493
+ instance whose under-estimated sample would have been lower; the result still never
1494
+ over-estimates (contract 4).
1495
+ - Objects: a 2³ cell's four lanes fold their texels into workgroup atomics, and the last of them
1496
+ decides, so that no lane waits on another.
1497
+ - One word holds the nearest texel's byte and its row, the lowest row on a tie.
1498
+ - Rows fit in 24 bits; a row past them names no object (contract 5).
1499
+ - The kernel's barriers keep it off the emulator, as the cooperative query is kept. Its parts are
1500
+ tier-2 pure chunks: the leaf filter, the instance, the texel, the object bid. The texel is held to
1501
+ the analytic distance of two scaled spheres within the field's error, and to the least of what
1502
+ each instance reads alone. The glue is checked on the device.
1503
+ - Measured on Sponza (S3c), the bricks made again once every cache was resident:
1504
+ - The 4090: the provider costs 58 µs at the median a frame of 4,096 cells, 166 µs at p90, 315 µs
1505
+ at worst; a frame of the fill totals 80–350 µs.
1506
+ - The iGPU: 1.06 ms, 2.1 ms and 6.1 ms; a frame of the fill 1.6–6.7 ms.
1507
+ - All 196,608 cells are built in 48 frames, 5,315 of them with a brick (5,311 on the iGPU, whose
1508
+ bilinear weights round to 1/256), within the initial capacity of 12,288.
1509
+ - 58 instances were dropped past 64 in a cell, the gather itself dropping nothing.
1510
+ - With EMPTY signed (§6.3) the building's air reads inside its open hull (geometry 102), so the
1511
+ courtyard is solid in the world bricks too; put to Alex.
1512
+
1513
+ **TODO hook (skinned).** The leaf accept, where a clone resolves to its source's header, is where a
1514
+ dense animated patch takes over later.
1515
+
1516
+ ### 7.8 The virtual geometry provider
1517
+
1518
+ S7, its own stage. vgeo rows are mesh rows with a virtual geometry: their BLAS is empty and they have
1519
+ no cache. The provider, per taken key:
1520
+ 1. **Gather**: the mesh provider's TLAS query, accepting vgeo rows in the SDF world only.
1521
+ 2. **Cut**: a box cut of each instance's cluster DAG. It takes clusters whose error is under ½·h_c
1522
+ and whose bounds overlap cell ⊕ R. This is the §4 traversal of `VIRTUAL_GEOMETRY_DESIGN.md`, with
1523
+ an error bound in world units in place of the pixel threshold.
1524
+ - Where children are not resident, the resident ancestor serves, and a want is recorded.
1525
+ - When the finer pages arrive, the provider appends the cell's box to the invalidation list
1526
+ (contract 6).
1527
+ 3. **Distance**: 512 texels per cell against the cut's triangles, up to 256 in LDS (chosen; past it,
1528
+ dropped and counted).
1529
+ - The sign comes from the nearest triangle's orientation.
1530
+ - A texel it cannot sign is written unsigned. That is positive, so the ½-voxel hit still catches
1531
+ the surface.
1532
+ 4. **Objects**: the vgeo row. Hits take the material mean (§6.6) until vgeo has cards, which belong to
1533
+ its own plan.
1534
+
1535
+ Triangle work here happens per requested cell (scroll-ins and changes), never per frame. It is bounded
1536
+ by the cut error: at error ½·h_c, a cell's triangles number on the order of its surface in voxels.
1537
+
1538
+ ### 7.9 Tracing
1539
+
1540
+ `brick_clipmap_trace(origin, direction, t_min, t_max)` is a pure chunk over seam readers, so the
1541
+ emulator can run it against CPU-built bricks (§12).
1542
+
1543
+ - **Start**: the finest cascade whose window holds the origin by ½ voxel.
1544
+ - **Loop**, at most 64 steps (chosen):
1545
+ - **Window**: if `p = o + t·d` leaves the window shrunk by ½ voxel, move to the next cascade; past
1546
+ the last cascade the ray is a MISS.
1547
+ - **Block**: an occupancy of 0 advances t to the block's exit (slab test).
1548
+ - **Entry**:
1549
+ - UNKNOWN continues in the next cascade from the current t. Unbuilt space is read from the
1550
+ parent, not passed through.
1551
+ - EMPTY advances to the cell's exit.
1552
+ - A slot reads d. If d < ½ voxel the ray HITs; otherwise `t += max(d, ½ voxel)` (UE's minimum
1553
+ step).
1554
+ - **Hit**: position, cascade and slot. The normal is a 4-tap tetrahedral gradient, its taps clamped
1555
+ to the brick's [0, 7] (UE uses 6).
1556
+ - **Unresolved**: a ray whose budget is spent is returned as unresolved, and its caller discards the
1557
+ sample (§8.8).
1558
+ - **Per step**: one occupancy load, one entry load, and one atlas sample inside bricks.
1559
+
1560
+ Three more chunks:
1561
+ - `brick_clipmap_distance(p)` is the finest cascade's signed sample at p, with an EMPTY cell read as
1562
+ ≥ R. It is for probe relocation.
1563
+ - `brick_clipmap_object(hit)` reads the object cell of the texel nearest to the hit moved ½ voxel
1564
+ along the normal, onto the ray's side. With a thin wall's two faces inside one voxel, this picks the
1565
+ face the ray hit. UE offsets its object lookup the same way.
1566
+ - `brick_clipmap_soft_shadow(origin, direction, sin_angle)` is the same march. It returns the
1567
+ classic penumbra estimate: the minimum over its steps of `d / (t·sin θ)`, clamped to [0, 1].
1568
+ - The estimate is extracted from `shader_scene_sdf_soft_shadows`.
1569
+ - θ is the light's angular radius from its record (`disk_radius`), a physical quantity, not a
1570
+ softness knob.
1571
+
1572
+ **As built (S3e)**, `brick/chunk_brick_clipmap_trace.js`:
1573
+ - The cascade count is a parameter of each chunk: `brick_clipmap_trace(origin, direction, t_min,
1574
+ t_max, cascade_count)`, with `direction` unit length so that `t` is a distance.
1575
+ - They read `brick_levels`, the map and the occupancy as sampled `u32` textures, the atlas through
1576
+ the mesh bricks' sampler, and `brick_objects`.
1577
+ - The hit carries its kind (hit, miss, unresolved), `t`, cascade, slot, position, normal, the
1578
+ field where it stands, and its cell's corner.
1579
+ - A step past the hit's threshold is `d` itself, at least half a voxel, so UE's minimum step needs
1580
+ no `max`.
1581
+ - EMPTY inside is a hit where the march stands. Its field reads −R and its normal is along the
1582
+ ray, so §8.4's gradient rule counts it as a back face with no case of its own.
1583
+ - A skipped block is clamped to the window at both ends (§7.3). Past the window's far edge the
1584
+ ray goes on in the next cascade from there, never from the block's storage end.
1585
+ - `brick_clipmap_distance`: in a point no window holds, or one only UNKNOWN cells cover, it reads R
1586
+ of the coarsest cascade.
1587
+ - `brick_clipmap_object` moves the hit along the normal, out of the solid. A front face's normal
1588
+ faces the ray, and a back face is counted, never shaded (§8.4), so the ray's side needs no test.
1589
+ - Tier 2, `brick_clipmap_trace.spec.js`, on spheres, boxes and planes built into bricks on the CPU
1590
+ the way the build makes them:
1591
+ - every hit lies within half a voxel and one LSB of the surface, with its normal;
1592
+ - skipping blocks finds the same hits as a march that reads every block;
1593
+ - a skip stops at either edge of a window whose corner is not a multiple of 4;
1594
+ - UNKNOWN cells defer to the parent;
1595
+ - a ray through empty space crosses four 16-cell windows within its 64 steps, which it could not
1596
+ cell by cell;
1597
+ - a ray grazing a plane between half a voxel and one spends its steps unresolved;
1598
+ - a wall thinner than a voxel is hit, and each of its faces reports its own row.
1599
+ - Mutants: 31 of 32 killed. The survivor, the start's half-voxel inset, is equivalent: without it
1600
+ the loop's window test moves the ray on at its first step.
1601
+ - `brick_clipmap_soft_shadow` is not built yet. §12's oracle cannot be met by the estimate above,
1602
+ and that is put to Alex. At a sphere's edge, where the ray to the light's centre grazes it, half the
1603
+ disk shows. The classic estimate reads 0 there, so its penumbra lies wholly outside the geometric
1604
+ shadow, and it is 0.55 from the analytic fraction at worst. Quilez's two-sided estimate marches on
1605
+ into the occluder, clamps the minimum to [−1, 1] and maps it through `¼(1 + x)²(2 − x)`; it is
1606
+ 0.085 from it at worst (θ = 0.05 rad, a unit sphere 10 units away).
1607
+
1608
+ **As built (S3e's soft shadow, 2026-10-28)**: Alex asked for quality where its cost is a fair trade, and
1609
+ left the estimator to the measurement. It is Quílez's two-sided estimate.
1610
+ - `brick_clipmap_soft_shadow(origin, direction, t_min, t_max, sin_angle, cascade_count)` walks the
1611
+ tracer's march, which both now share (`brick_clipmap_march`). A step passes empty space or changes
1612
+ cascade, leaves the last window, or stands in a cell to read.
1613
+ - In each brick it reads the clearance: the field less the tracer's half-voxel expand, so that a wall
1614
+ thinner than a voxel shadows as it is hit.
1615
+ - The least of the clearance over `t·sin θ` goes below zero inside the occluder. The march goes on
1616
+ into it, half a voxel a step, until the least reaches −1.
1617
+ - Clamped to [−1, 1], the least maps through `¼(1 + x)²(2 − x)`.
1618
+ - EMPTY inside is dark. An EMPTY cell or a skipped block adds nothing: its clearance is at least a
1619
+ voxel, wider than a sun's cone within its cascade's range.
1620
+ - **Quality**, on the CPU, against the analytic disk past the surface the tracer hits. 12 cases of θ
1621
+ (the sun's 0.0047 to 0.05 rad), radius and distance, each marched as the tracer marches:
1622
+
1623
+ | estimate | mean error | worst error | at the edge (0.5) |
1624
+ |---|---:|---:|---:|
1625
+ | classic, one-sided (above; `shader_scene_sdf_soft_shadows`) | 0.129 | 0.566 | 0 |
1626
+ | the engine's `scene_sdf_soft_shadow`, with Aaltonen's triangulation | 0.330 | 1.0 | 0 |
1627
+ | **two-sided** | **0.0145** | **0.099** | 0.5 ± 0.022 |
1628
+
1629
+ Aaltonen's triangulation breaks under the expand: a step can more than double the clearance, and
1630
+ its square root's argument goes negative.
1631
+ - **Cost**, paired against the one-sided estimate: the sun's shadow rays on Sponza, from random origins
1632
+ about the camera.
1633
+ - On the 4090 it is the same within its noise (1M rays: 725 against 755 µs). On the iGPU it is 33–36%
1634
+ more: 8.9 against 6.7 ms for 131,072 rays, 68.2 against 50.1 ms for 1M.
1635
+ - For a 0.05 rad light it costs 24% / 59% more.
1636
+ - The cost is the inner penumbra's rays, which the one-sided estimate stops dark and this one
1637
+ marches on. Stepping by the field's depth inside the occluder did not change it.
1638
+ - **What it buys** on Sponza: 8.7% of the sun's rays, which the one-sided estimate reads as umbra, see
1639
+ part of the sun. The mean visibility is 0.584 against 0.560.
1640
+ - The tracer through the shared march costs 2.9% more on the iGPU, paired, with the same hits. The
1641
+ alternative was a second copy of the traversal.
1642
+ - Tier 2:
1643
+ - past a sphere, within 0.1 of the analytic disk (0.043 measured), and half at the edge within 0.1
1644
+ (0.512);
1645
+ - dark under its middle, lit well clear of it;
1646
+ - a wall thinner than a voxel hides the sun;
1647
+ - a ray inside a solid, in a brick or EMPTY inside, is dark;
1648
+ - one past `t_max` or out of every window is lit.
1649
+ - Mutants: 13 of 15 killed.
1650
+ - A linear map in place of `¼(1 + x)²(2 − x)` survives within the oracle's tolerance. On the CPU its
1651
+ mean error is 35% more, and its worst no more.
1652
+ - Never stopping in the umbra is equivalent: the least only falls.
1653
+
1654
+ **As built (S3f)**: `ProbeClipmapDebugView.BrickClipmap` traces each pixel's camera ray through the
1655
+ world's bricks (`debug/graph_probe_clipmap_debug_brick_clipmap.js`).
1656
+ - A hit shows the field's normal, tinted warmer the coarser its cascade; a back face is red, and a
1657
+ ray whose steps ran out magenta.
1658
+ - `GPUBrickClipmap.write_bindings` hands a reader what the tracer's chunks read, as the geometry
1659
+ caches' does.
1660
+
1661
+ Measured on Sponza with its caches resident, at the defaults: 6 cascades of 32³, 0.125 m voxels,
1662
+ 4,096 cells a frame. The numbers are for the RTX 4090 / the AMD iGPU.
1663
+ - **Build**: a fresh clipmap builds in 48 frames, 196,608 cells at 4,096 a frame.
1664
+ - It holds 7,171 bricks, 5,147 of them in cascade 0. No cell is UNKNOWN and none is EMPTY inside,
1665
+ the same on both GPUs.
1666
+ - Under the 64-ray vote, S3d's fresh build held 5,315 bricks and 2,564 cells EMPTY inside.
1667
+ UE's vote leaves deep interiors at +R, and their shells add cells with a surface.
1668
+ - A frame of the fill costs 145 µs / 1.63 ms at the median and 411 µs / 6.8 ms at worst, 7.2 /
1669
+ 106 ms in all. The mesh provider is most of it, 104 µs / 1.08 ms at the median.
1670
+ - **Idle**: 22 µs / 15 µs a frame.
1671
+ - **Walking** 13.4 m through the building at 3.35 m/s, the build keeps up: nothing is queued at any
1672
+ fourth frame. A frame costs 27 / 15 µs at the median and 125 µs / 1.56 ms at worst.
1673
+ - **Trace, coherent**: the debug view at 1280×720, a ray a pixel, costs 63–88 µs / 9.3 ms. The Mesh
1674
+ SDF view of the same pixels costs 1.7–2.1 ms / 160–189 ms.
1675
+ - **Trace, incoherent**, as probes cast rays: random origins in a 28 m box about the camera, uniform
1676
+ directions.
1677
+ - 131,072 rays, the default `ray_budget`, cost 165–215 µs / 6.9–7.0 ms to the clipmap's edge, and
1678
+ 165–195 µs / 3.1–3.2 ms within 8 m.
1679
+ - 1,048,576 rays cost 650–725 µs / 54 ms, about 1.5 G / 19 M rays a second.
1680
+ - 0.6–0.7% of them run out of their 64 steps unresolved; within 8 m, 0.01%. 3.6–4.7% start inside
1681
+ a solid and meet a back face.
1682
+
1683
+ ### 7.10 Capacity and growth
1684
+
1685
+ - **Initial capacity** is `2·N_b²·C_b` bricks (12,288 at the defaults): a ground plane through every
1686
+ cascade, two cells thick.
1687
+ - **Growth**: failures are counted on the device and read back. On a non-zero reading the host
1688
+ doubles capacity (as built in S3, the count is take's starved takes, §7.4):
1689
+ - `GPUTileAtlas3D.reserve`, which adds layers and widens past `maxTextureDimension3D`, copying
1690
+ texels;
1691
+ - the object cells, reallocated with a copy;
1692
+ - the free list, extended by the new slot range.
1693
+ - The mesh brick atlas and the card pages grow the same way.
1694
+ - Nothing shrinks, in the manner of the vgeo descent bound.
1695
+ - **Ceiling**: the atlas's `capacity_limit` (256³ slots at 2048) and the adapter's
1696
+ `maxStorageBufferBindingSize`.
1697
+
1698
+ ## 8. The probe clipmap
1699
+
1700
+ ### 8.1 Cascades and lattice
1701
+
1702
+ - `C_p` cascades (`probe_cascade_count`, default 5) of `N_p³` lattice points
1703
+ (`probe_cascade_resolution`, a power of two, default 32).
1704
+ - Spacing is `s_c = s₀·2^c` (`probe_spacing` = s₀, default 1 m), so the windows span 32 to 512 m.
1705
+ - **Probes sit at the world-aligned lattice points `s_c·i`.** A point uses cascade c's cage, the
1706
+ eight corners of `floor(p/s_c)`, when the whole cage is in the window.
1707
+ - **Placement and nesting** are the bricks' (§7.1). The brick clipmap's 896 m outer window is wider
1708
+ than the probes' 512 m, so rays from the outermost probes travel at least 192 m before they read
1709
+ as sky.
1710
+ - **Cascade choice and blend** use `clipmap_select_finest` over the probe levels, with a blend
1711
+ skirt of 2 cells: one cell of the coarser cascade, the distance over which the spacing doubles.
1712
+
1713
+ ### 8.2 Storage
1714
+
1715
+ | Resource | Layout |
1716
+ |---|---|
1717
+ | Indirection | `r32uint`, `N_p × N_p × N_p·C_p`, toroidal; slot or `0xFFFFFFFF` |
1718
+ | States | storage buffer, one `u32` a slot: NEW / ALIVE / DEAD and the update count. Its own array, so the pick reads 4 B and not a record (§9.1) |
1719
+ | Records | storage buffer, 64 B a slot: cascade and world cell (3 × 21-bit signed, two words), wanted frame, traced time (s), relocation offset (3 × f16), back-face fraction, SH2 as `METRO_L1_IRRADIANCE_STRUCT` (32 B) |
1720
+ | Radiance | 2-D `rgba16float` atlas; a slot's tile is `(n_r + 2)²`: the octahedral map plus a one-texel skirt. One level only (§9.3). Slots are placed by `index_to_grid2d`, as in `lpv_atlas_patch_texel_coord` |
1721
+ | Depth | 2-D `rg16float` atlas, tile `(n_d + 2)²`. Moments of `min(t, √3·s_c)/s_c`: normalised by spacing, so every cascade has the same precision, and clamped at the cage diagonal, past which a hit cannot occlude anything the cage shades |
1722
+ | Wanted bits | `N_p³·C_p` bits, cleared each frame |
1723
+ | Lists | active (double-buffered), wanted, trace (≤ U, §8.5) |
1724
+ | Free list | the extracted slot stack (§4.1) |
1725
+
1726
+ `n_r` is `radiance_resolution` (default 16) and `n_d` is `depth_resolution` (default 8). Both are
1727
+ powers of two and independent.
1728
+
1729
+ **Why `rgba16float` and not LPV's `r32uint` rgbe9995.** Every consumer reads radiance with one
1730
+ hardware bilinear tap per probe. LPV's packed format forces four loads plus decodes and a manual
1731
+ bilinear. The memory measurement on the AMD iGPU found manual octahedral sampling 12× slower than
1732
+ hardware taps.
1733
+
1734
+ The price: a texture cannot be read and written in one dispatch without `texture-formats-tier2`, so
1735
+ the update is two passes (§8.8). That is LPV's own answer for its depth atlas.
1736
+
1737
+ ### 8.3 Lifetime
1738
+
1739
+ Per frame, in this order:
1740
+
1741
+ 1. **retire** (thread per active probe). A probe is freed when either holds:
1742
+ - its world cell is no longer in its cascade's window (`clipmap_contains` against the current
1743
+ corner);
1744
+ - it was last wanted more than `retention_time` ago (default 1 s).
1745
+
1746
+ Freeing it means:
1747
+ - its slot is pushed;
1748
+ - its indirection entry is cleared if it still names this slot.
1749
+ The rest are re-appended to the active list.
1750
+ - Running this before `want` means a scroll needs no pass of its own: the vacated storage cells
1751
+ are emptied before any newly exposed cell can claim them.
1752
+ 2. **want** (thread per 8×8-pixel tile; 32,400 at 1080p).
1753
+ - One pixel per tile per frame, chosen by STBN. Its world position comes from depth and its
1754
+ normal from the G-buffer; sky pixels are skipped.
1755
+ - The biased point (§9.1) picks cascade c. The eight cage cells of c, and of c + 1 inside the
1756
+ blend skirt, are `atomicOr`'d into the wanted bits. A bit that was clear appends its cell to the
1757
+ wanted list.
1758
+ - At a cascade's outer edge a probe cell projects to `H / (N_p·tan(fov/2))` pixels: 58 px at
1759
+ 1080p and 60°, 19 px at 120°. A tile size of 8 therefore samples every cell several times a
1760
+ frame.
1761
+ 3. **admit** (thread per wanted cell).
1762
+ - An EMPTY entry pops a slot (a failure is counted), writes a NEW state, a record and the
1763
+ indirection entry, and appends to the active list.
1764
+ - An existing probe refreshes its wanted frame.
1765
+
1766
+ Consumers weight a NEW probe at zero until its first update.
1767
+
1768
+ **As built (S4a, 2026-10-28)**, `probe/`: `GPUProbeClipmap` places the windows, keeps the storage, and
1769
+ records the frame's lifetime as one graph pass: retire, want, admit's command, admit, schedule.
1770
+ - **The levels uniform holds the cage windows**: the lattice window's corner, a size of `N_p − 1`, the
1771
+ cascade's spacing. `clipmap_select_finest` over it answers the finest cascade whose whole cage holds a
1772
+ point (§8.1). Retire tests a probe's point against the lattice window, one point wider.
1773
+ - **The record is plain fields**, 64 B as §8.2 sized it: the cell as `vec3<i32>`, the cascade, the
1774
+ wanted time, the traced time, the back-face fraction, the Metro L1 struct. §8.2's three 21-bit cells
1775
+ and a cascade are 66 bits, which two words do not hold. (S4a kept the relocation offset here; S4b
1776
+ moved it into the state.)
1777
+ - **"Wanted this frame" is the wanted bit**, which the frame clears. Retention reads a **wanted time**,
1778
+ seconds since the clipmap's first frame on the caller's clock: the renderer's wall clock, since the
1779
+ probes are a cache of the lighting, not part of the simulation (its `time_delta_seconds` is 0 by
1780
+ default).
1781
+ - **The indirection is filled with none on the first frame**, a thread a texel: a new `r32uint` texture
1782
+ reads 0, which is a slot.
1783
+ - **Want skips a cage the bias moves out of its window**: its points would alias storage cells other
1784
+ points hold. In the skirt the next cascade's cage is wanted on its own.
1785
+ - **Want claims each cage once a workgroup.** A workgroup's 64 tiles want a few cages between them, so
1786
+ the first lane to want a cage claims it in a 256-slot table in workgroup memory and sets its bits; the
1787
+ rest want it through that lane. Storage wraps by the power-of-two mask, not by the Euclidean mod, an
1788
+ integer division on the iGPU.
1789
+ - Measured on Sponza at 1280×720, paired in the same frames: on the iGPU want took 343 µs as first
1790
+ written, 264 with the mask alone, 317 with the claims alone, and **117** with both. On the 4090:
1791
+ 32.8, 29.7, 9.2 and **7.2** µs.
1792
+ - What it cost as first written, on the iGPU: 105 µs of loads, selection and keys, 140 of the bits'
1793
+ atomics, 90 of the appends.
1794
+ - **The lifetime a frame**, p50 on Sponza at 1280×720 with about 770 probes live: on the 4090 about 24
1795
+ µs (retire 7, want 7, admit 5, the two commands 2 each); on the iGPU about 129 µs (want 117, retire 6,
1796
+ admit 4).
1797
+ - **On the device** (one-offs on both GPUs): free plus live is the capacity, every live probe has one
1798
+ indirection entry and no two share one, a walk through the building admits and scrolls without
1799
+ starving, and the probes a turn to the sky leaves unwanted go after the retention time.
1800
+ - Commands: admit's command (one thread) sizes admit over the wanted list, and schedule (one thread)
1801
+ sizes the next frame's retire over the frame's active list; S4b gives schedule the period and the
1802
+ trace list. Every dispatch is indirect over a device count, or want's screen tiles.
1803
+ - **Extracted**: `chunk_folded_dispatch` (`gpu_primitive/indirect/`), the folded command the
1804
+ one-thread passes write; the brick take, the brick movers' command and the fluid forcing's command
1805
+ migrated onto it.
1806
+ - Capacity at the defaults: 16,384 slots. Growth doubles on a pop the free list could not serve.
1807
+ - Tier 2, `probe_clipmap_lifetime.spec.js`, two cascades of 8³ points on the emulator:
1808
+ - a pixel wants its cage, and admit gives each point one NEW probe there, named by its entry;
1809
+ - in the skirt the next cascade's cage too, biased by its own spacing;
1810
+ - the bias moves a cage across a cell face, and out of its window;
1811
+ - the sky and a point no window holds want nothing; two tiles' shared points are admitted once;
1812
+ - a probe wanted again keeps its slot; one unwanted keeps it for the retention time, then gives it
1813
+ back;
1814
+ - a probe whose point leaves its window gives its slot back before the point the move exposed in that
1815
+ storage cell claims it; one at the window's far lattice point stays;
1816
+ - a pop the free list cannot serve is counted;
1817
+ - admit's and schedule's commands cover their lists.
1818
+ - a lane's two cages are claimed apart though their least points share a storage cell.
1819
+ - Mutants: 29 of 29 killed.
1820
+ - Tier 3, `GPUProbeClipmap.spec.js`: the first frame's fills and the passes' order, sizes and commands;
1821
+ the cage windows; the clock; the capacity; growth; destroy.
1822
+
1823
+ ### 8.4 Relocation and classification
1824
+
1825
+ **Relocation**, at the start of every update:
1826
+ - With q the lattice point and d = `brick_clipmap_distance(q)`: while d < d_min,
1827
+ `q += ∇d·(d_min − d)`, at most 3 times. The field is signed, so a probe inside the band is pushed
1828
+ out.
1829
+ - The offset is clamped to 0.45·s_c, RTXGI's 45%. The probe stays in its own Voronoi cell, and the
1830
+ cage stays the lattice's.
1831
+ - d_min = ¼·s_c.
1832
+ - As built (S4b): see §8.5's as-built note; relocation's offset lives in the state's second word.
1833
+ - RTXGI's minimum front-face distance is 1.0 m at its recommended 2–3 m spacing, about a third of
1834
+ a cell. Lumen offsets only below 0.05 of a cell.
1835
+ - A quarter keeps a probe well clear of the 0.1·s_c receiver bias (§9.1) and of the ½-voxel
1836
+ expand its own rays start beside.
1837
+
1838
+ **Classification**: DEAD when more than 25% of an update's rays hit back faces. That is RTXGI's
1839
+ threshold for its fixed classification rays, and UE's mesh-SDF sign vote uses the same fraction.
1840
+ Every update's rays cover the whole sphere, one per texel, which is what the fixed-ray threshold
1841
+ assumes.
1842
+ - A back face is a hit whose field gradient points along the ray: the ray came from inside a solid.
1843
+ A ray that starts inside one hits at its first step (§7.2).
1844
+ - A probe deeper than the band reads +R and is not relocated, but its rays reach the band from
1845
+ inside, as back faces.
1846
+ - A DEAD probe weighs zero and is traced once every 8 periods, so it notices when the scene changes.
1847
+
1848
+ ### 8.5 Scheduling
1849
+
1850
+ - At most `U = floor(ray_budget / rays_per_probe)` probes update a frame (512 at the defaults).
1851
+ - **schedule** (one thread): `P_w` = probes wanted this frame, and `T = max(1, ceil(P_w / U))`. T
1852
+ frames is the period, so it follows the live count.
1853
+ - Then one thread per active probe. A probe is **due** if it was wanted this frame and any of these
1854
+ holds:
1855
+ - it is NEW;
1856
+ - `(frame + h(slot)) mod T == 0`;
1857
+ - it is DEAD and `(frame + h(slot)) mod 8T == 0`.
1858
+ - NEW probes append first, as their own dispatch; the rest fill the trace list up to U.
1859
+ - Every wanted probe is retraced every T frames. With 8,000 wanted probes that is T = 16: 0.27 s at
1860
+ 60 fps.
1861
+ - A camera cut that admits more than U new probes spreads them over frames. The stale ones simply
1862
+ wait a period.
1863
+
1864
+ **As built (S4b, 2026-10-28)**:
1865
+ - **The state is two words**: the kind and updates, then where relocation moved the probe, three
1866
+ 10-bit two's-complement fields of 0.45 of its spacing (a step under a thousandth of it, zero at the
1867
+ lattice point). §9.1's pick needs every corner probe's position for its wrap term and its depth tap,
1868
+ and §8.2's 4-byte state left the offset in the 64-byte record: a corner is now one 8-byte load.
1869
+ - **Schedule** (one thread) sets T from the wanted list's count, and writes the command over the
1870
+ frame's active list that the due passes dispatch through, and the next frame's retire.
1871
+ - **Due** runs twice over the active list: NEW probes, then ALIVE ones on their turn and DEAD ones on
1872
+ theirs in eight periods. "Wanted this frame" is the point's wanted bit. A probe's turn is
1873
+ `(frame + lowbias32(slot)) mod T`. Past U the list's count goes on rising and nothing is written; the
1874
+ update's command clamps to U.
1875
+ - **Relocate** is its own pass over the trace list, a thread a probe, in a second graph pass that reads
1876
+ the brick clipmap's last write of the frame (`GPUBrickClipmap.graph_update` now returns it), so it
1877
+ orders after the build. The field's gradient is the new `brick_clipmap_gradient`: four taps of
1878
+ `brick_clipmap_distance` a voxel across, zero where the field is flat.
1879
+ - **On the device**, Sponza at 1280×720 with the caches baked:
1880
+ - relocation moved 450 of 769 live probes on the 4090 (430 of 746 on the iGPU), some to the limit;
1881
+ wanted probes are the cages of visible surfaces, so most sit within a quarter cell of one;
1882
+ - T = 2 for 646 wanted at U = 512; nothing starved;
1883
+ - schedule, the two due passes and the update's command: about 11 µs on the 4090, 8 on the iGPU;
1884
+ - relocate: 24.6 µs on the 4090 and 23.4 on the iGPU for 512 probes. The same on both, so it is
1885
+ latency-bound: three dependent steps of five field reads, over a launch of eight workgroups.
1886
+ - Emulator fixed alongside: `extractBits` on `i32` now sign-extends (WGSL §17.9); it had zero-extended
1887
+ both types, and the offset's decode depends on it.
1888
+ - Tier 2: `probe_clipmap_schedule.spec.js` (the period, NEW first, unwanted never due, the turns, the
1889
+ bound, the commands), `probe_clipmap_relocate.spec.js` (free space, a face, inside a solid, a
1890
+ concave corner, the limit, a flat field, the cascade's own clearance), `chunk_probe_clipmap.spec.js`
1891
+ (the offset's encoding), and the gradient in `brick_clipmap_trace.spec.js`.
1892
+ - Mutants: 19 of 21 killed. The two survivors are equivalent on the fields the specs build: the early
1893
+ exit where the field is flat, and the gradient's flatness threshold on fields exactly flat.
1894
+
1895
+ ### 8.6 Rays
1896
+
1897
+ **trace**: one thread per ray, `trace_count × rays_per_probe` rays.
1898
+ - **Texel**: R = `rays_per_probe`.
1899
+ - R ≥ n_r²: R/n_r² rays per texel.
1900
+ - R < n_r²: the texels `(update·R + k)` under a fixed bit-reversal permutation of the n_r²
1901
+ texels, so each update covers a spread subset.
1902
+ - **Direction**: `uv_octahedral_unit_decode((texel + ξ)/n_r)`, with ξ from STBN at (slot, update
1903
+ count). This is one stratified jittered ray per texel, LPV's own pattern.
1904
+ - **Origin and range**: the relocated probe, with t_min = one voxel of the brick cascade there.
1905
+ - **Sun**: after `brick_clipmap_trace`, a hit traces `brick_clipmap_soft_shadow` toward each
1906
+ directional light that casts shadows, up to 2 (a chosen cap; further lights are unshadowed at
1907
+ hits).
1908
+ - The shadow ray starts one voxel off the hit along the field's normal, outside the ½-voxel expand.
1909
+ - This is the same pass because it is the same cost profile, an SDF march (E7).
1910
+ - **Output**: a hit record {t, or MISS / UNRESOLVED; cascade; slot; normal; back-face bit; sun
1911
+ visibilities}.
1912
+
1913
+ **As built (S4c, 2026-10-28)**, `probe/shader_probe_clipmap_trace.js`:
1914
+ - **The ray record** is 28 B (`PROBE_RAY_STRUCT`) since S4d: `t`; the direction and the hit's
1915
+ normal,
1916
+ each octahedral in two unorm16; the `meshes` row of the hit's surface, from `brick_clipmap_object`;
1917
+ the flags (kind, back face, the hit's cascade); and the light, three half floats. Trace writes the
1918
+ direct irradiance there and shade writes the radiance over it. The hit's position is the probe's
1919
+ origin plus `t` along the direction, which shading recomputes. (S4c's record held the two suns'
1920
+ visibility in place of the light; S4d moved E_dir into the trace, below.)
1921
+ - **The texel mapping** is `chunk_probe_clipmap_ray_texel`, both ways (a ray's texel, a texel's rays),
1922
+ so accumulation finds each texel's rays without a scatter. The bit-reversed subset repeats every
1923
+ n_r²/R updates, which keeps its product in range.
1924
+ - **The noise** is STBN at the texel moved by the slot's hash, so neighbouring probes do not jitter
1925
+ alike, and at the update count.
1926
+ - **The origin** is the lattice point plus the state's offset; t_min one voxel of the brick cascade
1927
+ there; t_max the coarsest window's diagonal. Since S4d relocation writes it, `vec4(origin,
1928
+ spacing)`
1929
+ at the probe's place in the trace list (`probe_origins`), at the offset as encoded, and the update's
1930
+ passes after it read it there.
1931
+ - **Back faces** follow the gradient rule as written. Of a probe inside a solid, a ray heading out
1932
+ through the nearer face is one; a ray nearly along the solid's faces can read as a front face, but
1933
+ classification's share stays well past a quarter (over half for a probe in a slab, in the spec).
1934
+ - **A surface turned from a light marches no shadow toward it**: the light gives it `max(0, n·l)`,
1935
+ zero there. The light keeps its place among the shadowed, so which lights are shadowed does not turn
1936
+ on the surface's orientation.
1937
+ - **E_dir is the trace's** since S4d: Σ colour·max(0, n·l)·visibility over every directional light,
1938
+ the first two that cast shadows by their soft shadow, at a front-face hit. The trace reads the lights
1939
+ already, and shade would have needed the light table as an eleventh storage buffer (below).
1940
+ - **On the device**, Sponza at 1280×720 with the caches baked, 131,072 rays a frame (U = 512 × R = 256):
1941
+ 96% hit, 3.4% miss, 0.2% unresolved, 2.5% back faces; the mean hit at 2.6 m; 13% of the sun seen at
1942
+ front-face hits.
1943
+
1944
+ | | AMD iGPU, p50 | RTX 4090, p10 |
1945
+ |---|---:|---:|
1946
+ | trace, as built | 7.9 ms | 355 µs |
1947
+ | without the sun's shadow | 4.2 ms | 62 µs |
1948
+ | the march alone, no lights, no object | 3.9 ms | 57 µs |
1949
+
1950
+ - The facing test saved 4–7% of the shadow: most hits are on walls nearly parallel to Sponza's high
1951
+ sun, whose shadow rays graze the wall they leave.
1952
+ - On the 4090 the pass's p50 swung between runs, to 2–4 ms on some, while the same frame's twin
1953
+ without the shadow held at 60 µs. Not explained yet; S4g measures it on a quiet machine.
1954
+ - **At the default ray budget the update's rays cost about 8 ms a frame on the iGPU.** Reported with
1955
+ S4's timings: `ray_budget` is the knob (§10), and the cost is linear in it.
1956
+ - Tier 2, `probe_clipmap_trace.spec.js`, over bricks built from analytic fields:
1957
+ - a ray a texel, every texel once; more rays a texel each, each inside it; fewer, a spread subset
1958
+ that a run of updates covers;
1959
+ - a miss out of every window; a hit at a sphere within half a voxel, with its row;
1960
+ - a ray from inside a solid hits at its first step, a back face out through the nearer face; from
1961
+ past the band, always; a probe beside a solid sees only front faces;
1962
+ - the sun whole under an open sky, none under a roof; only the first two shadowed lights traced; no
1963
+ shadow from a back face or from a surface turned from the light;
1964
+ - neighbouring probes jitter apart; a probe within half a voxel of a surface steps off it; the ray
1965
+ starts at the relocated probe; the rays of a probe past U are not traced.
1966
+ - Mutants: 18 of 18 killed.
1967
+
1968
+ ### 8.7 Hit shading
1969
+
1970
+ **shade**: one thread per ray.
1971
+
1972
+ | Ray | Radiance |
1973
+ |---|---|
1974
+ | MISS | `sample_environment_color` along d |
1975
+ | UNRESOLVED | no sample |
1976
+ | back face | 0, counted for classification; its depth sample is 0.2·t (DDGI 2021's 80% shortening), so the probe reads as occluded that way |
1977
+ | HIT | `L = emissive + ρ_d·E/π`, with E = E_dir + E_loc + E_ind |
1978
+
1979
+ The surface comes from `brick_clipmap_object` and `mesh_card_surface` (§6.6): diffuse albedo ρ_d and
1980
+ emissive.
1981
+
1982
+ The three irradiance terms of a HIT:
1983
+ - **E_dir** is Σ colour·max(0, n·l)·visibility over `directional_lights_iteration_mask`.
1984
+ - **E_loc** comes from the world light clusters at the hit, generalised to this mode's brick levels
1985
+ so that every hit position has a cell.
1986
+ - At most 32 lights, `IRRADIANCE_CLIPMAP_LIGHT_BUDGET`'s value. Past that, lights are dropped.
1987
+ - Each light goes through `irradiance_clipmap_get_{point,spot}_light_info_by_index`, with shadow
1988
+ from `volumetrics_{point,spot}_light_shadow`.
1989
+ - A light whose shadow map is cleared lights hits unshadowed, which is a stated limit.
1990
+ - **E_ind** is this mode's own diffuse sampling (§9.2) at the hit, with last frame's SH: the next
1991
+ bounce.
1992
+ - Its pick takes the ray's own STBN sample as noise; the probe blend averages it.
1993
+ - Where no probe exists, the bounce is **zero**, not the environment. A hit behind the camera in a
1994
+ cave must not bring daylight in.
1995
+ - LPV's 0.97 factor is dropped: albedo below 1 already bounds the series.
1996
+
1997
+ **Hits are diffuse only**, as Lumen's surface cache lights diffusely (D7).
1998
+ - The cards hold diffuse albedo and emissive: the payload Alex chose.
1999
+ - A metal's diffuse albedo is zero, so a metal bounces nothing but its emissive. That is Lumen's
2000
+ limitation too.
2001
+
2002
+ **As built (S4d, 2026-10-28)**, `probe/shader_probe_clipmap_shade.js`, a thread a ray after trace
2003
+ through the same command:
2004
+ - **Its radiance goes over the ray's light**, three half floats: no buffer of its own. With one, shade
2005
+ would bind eleven storage buffers, past the ten a stage has (§12): the rays, the origins, the trace
2006
+ list, the scene database, the texture means, the SDF headers and indirection, the card sets, the card
2007
+ rows, and the radiance. In place it binds nine.
2008
+ - A miss takes `sample_environment_color` along its direction; a front-face hit `emissive +
2009
+ ρ_d·E_dir/π`, its surface from `probe_clipmap_hit_surface` (§6.6) at its cascade's voxel; an
2010
+ unresolved ray and a back face zero. Radiance is held to the largest half float, so a bright sky
2011
+ cannot write an infinity that a zero weight turns into a NaN.
2012
+ - **The depth samples are accumulation's**: they follow from t, the kind and the spacing, which
2013
+ accumulation reads anyway.
2014
+ - E_loc and E_ind join E at S5 (§13).
2015
+ - On the device, Sponza: 93–94% of the 131,072 rays are front-face hits. Cards serve 88.2% of them;
2016
+ the material mean serves the other 11.8%, rows whose card set does not see the point. No hit
2017
+ lacked a card set or an object. Misses see a black environment, as the harness's scene sets none.
2018
+ 87% of front-face hits come back black: they are in the sun's shadow, and E_loc and E_ind come at
2019
+ S5.
2020
+
2021
+ | | AMD iGPU, p50 | RTX 4090, p50 |
2022
+ |---|---:|---:|
2023
+ | shade, as built | 3.27 ms | 45 µs |
2024
+ | every hit on its material's mean, no card read | 224 µs | |
2025
+ | the shell: the record, the decode, a miss's sky | 207 µs | |
2026
+
2027
+ - **The card lookup is 93% of the pass on the iGPU.** `mesh_card_surface` reads every card
2028
+ record's direction for each facing axis, up to 96 records a hit, and a page and two texels for
2029
+ each candidate.
2030
+ - **So the layout's header names each direction's first card** (`MESH_CARD_LAYOUT_DIRECTION_FIRST`,
2031
+ six words the merge writes, the records being direction by direction already), and the scan reads
2032
+ its direction's run alone. Measured interleaved against the old scan, first and second alternating
2033
+ frame by frame, 120 frames, p50: iGPU 1.64 ms against 3.29 ms, 4090 26.6 µs against 42 µs.
2034
+ - Tier 2: `probe_clipmap_shade.spec.js` (misses by direction, the material mean lit by E/π, nothing
2035
+ from an unresolved ray or a back face, row 0 black, the half-float cap, the rays past U); the card
2036
+ branch in `mesh_cards_capture.spec.js`, through a node twice the size, turned and moved, at hits
2037
+ within 1.25 voxels of the surface and past the tolerance; the means in
2038
+ `shader_resident_texture_means.spec.js` against means taken on the CPU, across rows, columns and
2039
+ layers of slots.
2040
+ - Mutants: 43 of 44 killed. The survivor removes the means' dispatches, which the software device
2041
+ cannot see on the texture build's own encoder; the device check reads the means back against the
2042
+ atlas.
2043
+
2044
+ ### 8.8 Update
2045
+
2046
+ **accumulate**: one workgroup per traced probe.
2047
+ - **Blend weight**: α = 1 on the first update. After that, α = max(1/(n+1), 1 − e^(−Δt/τ)), with Δt
2048
+ the seconds since the probe's previous update and τ = `response_time` (default 0.5 s).
2049
+ - DDGI's 0.97 a frame at 60 fps is τ = 0.55 s.
2050
+ - **Radiance**: each texel hit this update takes the mean of its rays, blended with its history.
2051
+ The history is read from the atlas through a sampled binding.
2052
+ - **Depth**: each depth texel takes the moments of the rays landing in it (a miss counts as √3),
2053
+ blended the same way.
2054
+ - Texels without a ray keep their history; so does an unresolved ray's texel.
2055
+ - **The transient holds the probe's whole maps**, new texels and kept ones: n_r² × 8 B + n_d² × 4 B
2056
+ per traced probe, 1.2 MiB for U = 512. `publish` cannot read the atlas it writes, and it needs
2057
+ every texel to rebuild the skirts.
2058
+ - **SH2**: Σ over all n_r² texels (new or kept) of `radiance × sh2_basis_at × octahedral_solid_angle`.
2059
+ The reduction is a subgroup sum plus one LDS pass, stored through `convert_to_irradiance_sh`. There
2060
+ is one temporal state, the radiance; the SH follows it.
2061
+ - **Classification**: the back-face fraction updates the state (§8.4).
2062
+ - **Stall bound**: a blended value stops moving when α·|Δ| is under half a half-float ULP. That is
2063
+ within 0.5 ULP/α of its target: about 0.1% at T = 16, and 1.6% when probes update every frame.
2064
+ - Measured on the 4090, `rgba16float` render-target writes truncate toward zero. Whether storage
2065
+ writes do is unmeasured; if they do, this bias is one-sided. §12 measures it.
2066
+
2067
+ **publish**: one workgroup per traced probe. It rewrites the probe's whole tiles from the transient
2068
+ through storage bindings, with their one-texel skirts (`texture_octahedral_skirt_texel_uv` names each
2069
+ skirt texel's fold twin).
2070
+
2071
+ **As built (S4e, 2026-10-28)**: four passes after shade, each a thread an element, through commands the
2072
+ update's command writes. **The one-workgroup-a-probe design above is not what was built.** The emulator
2073
+ runs a workgroup's lanes one after another and treats a barrier as a no-op, and its subgroup sum
2074
+ returns the lane's own value, so a reduction across a workgroup cannot be tested there. Every pass is
2075
+ a per-invocation function instead. Each is tier 2 whole, and no thread's loop runs past 64.
2076
+ - **accumulate** (`probe/shader_probe_clipmap_accumulate.js`): a thread a texel of the n_r² radiance
2077
+ and n_d² depth maps. It gathers its rays through `probe_clipmap_texel_ray` and writes the probe's
2078
+ maps (`probe_maps`, `probe_clipmap_maps_words` = 3·n_r² + n_d² words a probe): rgba as half floats,
2079
+ then the texel's resolved and back-face rays, then the depth moments.
2080
+ - **α is a texel's, not the probe's**: max(1/(a+1), 1 − e^(−Δt·p/τ)), where a is the texel's count of
2081
+ the updates that reached it, kept in the radiance's alpha and capped at 255, and p the updates
2082
+ between a texel's rays (n_r²/R below a ray a texel). Below a ray a texel, a texel's first ray is
2083
+ then taken whole whenever it comes, which the probe's count would get wrong. Depth blends by the
2084
+ probe's α.
2085
+ - **A new probe's history is its slot's last owner's**: on its first update a texel no ray reached is
2086
+ cleared, radiance to nothing and depth to a miss's moments (√3, 3).
2087
+ - Depth samples, in spacings: a miss √3, a back face 0.2·t, a hit t, each held to √3. A depth texel
2088
+ gathers R/n_d² rays, so the GI refuses R > 64·n_d².
2089
+ - **the projection** (`probe/shader_probe_clipmap_project.js`): a thread a row of a probe's radiance
2090
+ map sums its texels as `convert_to_irradiance_sh(L, ω)·dω/(2π)` and its rays' counts; then a thread a
2091
+ probe sums its rows into the record's SH, its back-face share, its time, and its state: dead past a
2092
+ quarter, alive at or below, its kind kept by an update with no ray resolved, its update counted.
2093
+ - **publish** (`probe/shader_probe_clipmap_publish.js`): a thread a texel of the probe's two tiles,
2094
+ skirts included, each skirt texel its fold twin's (`texture_octahedral_wrap_texel_coordinates`), the
2095
+ atlases stored into and nothing else.
2096
+ - On the device, Sponza: after the caches bake and 60–90 still frames, 742–769 live probes, every
2097
+ one updated (about 300 updates on the 4090, 112 on the iGPU). 13 are dead, the back-face share's
2098
+ p50 is 0.8% and its p90 3.5–3.9%, and no SH is not finite. Irradiance resolved facing the six
2099
+ axes, E/π: p50 0.0003–0.0004, p90 0.045–0.046, max 0.38, the same on both GPUs. Most of their rays
2100
+ hit surfaces in the sun's shadow (87%, §8.7), and the sun is the only light until S5.
2101
+
2102
+ | p50 | AMD iGPU | RTX 4090 |
2103
+ |---|---:|---:|
2104
+ | accumulate | 163 µs | 8.2 µs |
2105
+ | the projection's rows | 295 µs | 7.2 µs |
2106
+ | the probes' projection | 15.8 µs | 12.3 µs |
2107
+ | publish | 189 µs | 6.1 µs |
2108
+
2109
+ The rows are most of it on the iGPU. They work out each texel's solid angle and SH afresh, for
2110
+ every probe.
2111
+ - Tier 2: `probe_clipmap_accumulate.spec.js` (a first update whole, α's two terms and the count's cap,
2112
+ the time between a texel's rays, unresolved rays and back faces, a new probe's clearing, depth by
2113
+ kind in spacings, a finer depth map, U), `probe_clipmap_project.spec.js` (a constant radiance and a
2114
+ lit hemisphere against the engine's own resolve, the dead threshold, a blind update, U),
2115
+ `probe_clipmap_publish.spec.js` (both tiles' skirts against the fold, nothing else written).
2116
+ - Mutants: 33 of 33 killed, five of them by tests added for them: a new probe's depth cleared, each
2117
+ texel's solid angle against one integrated from the decode, and the three launches the update's
2118
+ command adds.
2119
+
2120
+ ## 9. Sampling
2121
+
2122
+ ### 9.1 The pick: `probe_clipmap_pick(position, normal, view_direction, ξ) -> pick`
2123
+
2124
+ 1. `clipmap_select_finest` gives cascade c and the blend weight b toward c + 1.
2125
+ 2. **Biased point**: `p_b = p + (0.8·n + 0.2·v)·0.1·s_c`.
2126
+ - The mix is LPV's `mix(normal, view_direction, 0.2)`.
2127
+ - The length is a chosen value between the precedents: RTXGI's defaults are 0.1 m along each of n
2128
+ and v at a recommended 2–3 m spacing, and LPV's is 0.05 of its probe span. It is a tuned order of
2129
+ magnitude in both, not a derivation, and the leak cases of §12 check it.
2130
+ 3. **Weigh the eight corners of `floor(p_b/s_c)`, visibility only.** Per corner:
2131
+ - the indirection entry, then the state word: missing, NEW or DEAD probes weigh 0;
2132
+ - one bilinear depth tap toward p_b at distance `|p_b − probe|/s_c`;
2133
+ - weight = trilinear × `probe_visibility_weight`: the wrap back face, Chebyshev from the tap, and
2134
+ the crush.
2135
+
2136
+ No SH and no radiance is read here.
2137
+ 4. **Pick two**, the extracted `pick2_wrs_mat2x4`, which is Brick4's selection:
2138
+ - one draw of `sample_discrete_wrs_mat2x4` over the eight weights with ξ₀;
2139
+ - the drawn weight is zeroed, and a second draw is made with ξ₁;
2140
+ - blend t = w₂ / (w₁ + w₂).
2141
+ - A single non-zero weight is drawn twice, at t = 0.
2142
+ 5. **In the blend skirt**, steps 3–4 run for c + 1 as well, and the two picks are lerped by b: four
2143
+ probes there, and no noise across the cascade boundary.
2144
+ 6. **Σ w = 0** tries the next cascade. With none left, the fallback is the caller's:
2145
+ - pixel consumers take `get_ibl_irradiance(n)`;
2146
+ - hit shading takes zero (§8.7).
2147
+ A pixel's probes are wanted, admitted, traced and published in the same frame before shading reads
2148
+ them. A pixel reaches the fallback only when NEW probes overflow U (a camera cut), or when it has
2149
+ no depth of its own (a transparent surface in open air).
2150
+
2151
+ Per pixel and cascade the visibility pass makes 8 indirection loads, 8 state words and 8 bilinear
2152
+ depth taps. Then the pick reads two probes: two SH records and, for specular, two radiance taps. (a)
2153
+ read eight 64 B records and resolved eight SH.
2154
+
2155
+ ### 9.2 Diffuse: `probe_clipmap_sample_irradiance(position, normal, view_direction, ξ) -> E`
2156
+
2157
+ - The two picked records' Metro L1 structs are mixed by t, then resolved once with
2158
+ `resolve_irradiance_sh_to_diffuse(SH, n)`. Brick4 likewise mixes its SH before evaluating.
2159
+ - The resolve returns E/π by its convention. The pass multiplies by π, because the resolve pass takes
2160
+ irradiance E.
2161
+
2162
+ ### 9.3 Specular: `probe_clipmap_sample_radiance(position, normal, view_direction, roughness, ξ) -> L`
2163
+
2164
+ The two probes of the same pick are used. Per Brick4's fused pass, the pair's blend is re-weighted for
2165
+ this lobe: the wrap term is taken against the sample vector instead of the normal, and the pick itself
2166
+ is shared.
2167
+ - **Sample vector**: `s = normalize(mix(r, n, α))`, with r the reflection of the view direction and
2168
+ α = roughness². This is LPV's and Brick4's.
2169
+ - **Radiance**: one hardware bilinear tap per probe along s, after a one-step parallax. The reflected
2170
+ ray is intersected with a sphere around the probe whose radius is the probe's mean depth along s.
2171
+ That is Lumen's sphere parallax, with the radius taken from the probe's own depth instead of a
2172
+ constant. The two taps are blended by the re-weighted t.
2173
+ - **GGX-convolved SH2**: `resolve_irradiance_sh_to_specular(SH, s, α)`, NEW in `l1i/`, on the mixed SH.
2174
+ It is the diffuse resolve with the GGX zonal factor `g₁(α)` from `sh2_approximate_GGX_zh` in place
2175
+ of the clamped cosine's 2/3:
2176
+ - `Y = max(0, 2π·(0.28209·Y_w + g₁(α)·0.48860·(Y_xyz · s)))`;
2177
+ - chroma rescaled by the ratio of directional to mean luma, as the diffuse resolve rescales it;
2178
+ - at g₁ = 2/3 it is exactly the diffuse resolve, and constant radiance L returns L for every α.
2179
+ Both are spec invariants.
2180
+ - **Blend**: `L = mix(radiance, sh_ggx, roughness_to_mip_ratio(roughness))`, `chunk_lpv_sample_light`'s
2181
+ blend. It is SH alone from roughness 0.7.
2182
+ - Output: radiance before Fresnel, per the resolve's contract.
2183
+
2184
+ **Why no prefiltered levels** (Alex's point). An atlas's hardware mips mix neighbouring tiles. Levels
2185
+ per probe would be manual strips, with their own skirts and their own downsample pass, written one mip
2186
+ per storage binding. Two SH bands hold the rough end of the lobe well, and a single tap holds the
2187
+ smooth end.
2188
+
2189
+ ### 9.4 Noise and its resolve
2190
+
2191
+ - Image passes take ξ from STBN at (pixel, frame), `chunk_stbn_sample_vec2`, as Brick4 does.
2192
+ - Forward passes and the irradiance clipmap take the extracted `jitter_from_vectors(position, normal)`,
2193
+ a position-and-normal hash with the frame index.
2194
+ - The pick's variance follows how much the eight probes disagree, which is largest across light
2195
+ boundaries. TAA resolves it, as it resolves Brick4's specular.
2196
+ - §12 measures the frame-to-frame change on an orbit and a dolly against the eight-probe evaluation,
2197
+ as a one-off.
2198
+
2199
+ ### 9.5 The five switch alternatives
2200
+
2201
+ | Choice | This mode |
2202
+ |---|---|
2203
+ | `forward_sample_indirect(p, v, n, roughness, &radiance, &irradiance)` | one pick (hash noise); irradiance from §9.2, radiance from §9.3 (environment until S6) |
2204
+ | `water_gi_irradiance(p, n)` / `water_gi_specular(p, n, v, roughness)` | §9.2 with v = n, since the irradiance call has no view direction / §9.3 (environment until S6); hash noise |
2205
+ | `ssr_sample_radiance(p, n, v, roughness, coord)` | §9.3 with STBN at coord (environment until S6) |
2206
+ | `ssr_add_hit_irradiance(&result, confidence, p, hit_vs, hit_n, coord)` | LPV's body with §9.2: albedo·E/π at the hit when confidence > 0.05 |
2207
+ | `irradiance_clipmap_gi_sample(p) -> array<vec3f,4>` | `probe_clipmap_sample_sh(p)` × `INDIRECT_LIGHT_INTENSITY`: the pick without the back-face term (there is no normal), returned as RGB SH2 |
2208
+
2209
+ Each alternative declares `PROBE_CLIPMAP_RESOURCES` with `requireResource`:
2210
+ - the levels uniform;
2211
+ - the indirection texture;
2212
+ - the states and records buffers;
2213
+ - the depth atlas;
2214
+ - the radiance atlas (from S6);
2215
+ - a linear sampler.
2216
+
2217
+ Union bindings were measured free in stage 2 of the switch proposal (p50 1.000).
2218
+
2219
+ ### 9.6 Deferred
2220
+
2221
+ A new case in `#graph_indirect_lighting`, shaped like Brick4's:
2222
+ - **SSR off**: a fused image pass, `shader_probe_clipmap_indirect_lighting`. It picks once and
2223
+ re-weights the pair for each lobe, as Brick4's fused pass does: one cost profile, the same two
2224
+ probes.
2225
+ - **SSR on**: `shader_probe_clipmap_diffuse` plus SSR, whose fallback is this mode's
2226
+ `ssr_sample_radiance`.
2227
+
2228
+ Until S6, specular is `shader_specular_IBL`, as LPV mode does today.
2229
+
2230
+ ### 9.7 Every file the change touches
2231
+
2232
+ The new mode value:
2233
+ - **Definition**: `ShadeIndirectLightingMode.js`.
2234
+ - **The five choice files** of §9.5, and the resource sets:
2235
+ - `shader_avboit_draw.js` and/or `SHADING_LIGHT_RESOURCE_GROUP.js`;
2236
+ - `shader_oit_resolve_moments.js`;
2237
+ - `water/shader_water.js`;
2238
+ - `ssr_resolve_shader.js`;
2239
+ - `shader_irradiance_clipmap_build.js`.
2240
+ - **Owners**: `graph_rasterize_meshes_transparent_avboit.js`, `graph_rasterize_meshes_transparent_oit.js`,
2241
+ `GPUWaterRenderer.js`, `SSR.js`, and `GPUViewVolumetrics.js` → `GPUIrradianceClipmap.js`.
2242
+ - **`Renderer.js`**: the switch at 1138, the hand-offs at 1266-1267 and 2791, the per-frame update
2243
+ (beside `update_lpv`), `enquirePipelines`, `destroy` and `indicate_view_change`.
2244
+ - **Specs that encode per-mode facts**: `indirect_lighting_consumers.spec.js`, `SSR.spec.js` and
2245
+ `graph_build_froxel_gi.spec.js`.
2246
+
2247
+ The caches, the membership bit and the extractions:
2248
+ - `engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js` (the `SDFWorld` bit) and
2249
+ `engine/graphics3/ShadedGeometrySystem.js` (forwarding it).
2250
+ - `scene/rows/GPUSceneRows.js` (the bit, the `flags` word, `onMeshWritten`) and
2251
+ `scene/MESH_INSTANCE_METADATA_STRUCT.js`.
2252
+ - `geometry/sdf/GPUGeometrySDFManager.js`, `shader_build_sdf.js` and its spec, and the four readers of
2253
+ the dense tiles, ported to `mesh_sdf_sample`.
2254
+ - `material/resident/GPUResidentMaterialContext.js`: slot means, and the repack signal.
2255
+ - Brick4's `chunk_brick4_probe_meta_pick2.js` and `chunk_brick4_sample_forward_indirect.js` (the pick
2256
+ and the hash, extracted).
2257
+ - `shader/chunk/spherical_harmonics/l1i/` (the specular resolve).
2258
+
2259
+ ## 10. Settings
2260
+
2261
+ `renderer.probe_clipmap`, a `ProbeClipmapSettings`: plain validated fields, pushed every frame, on
2262
+ the shadow knobs' pattern.
2263
+ - **Structural fields** (the cascade counts and resolutions, the voxel size, the spacing, the
2264
+ radiance and depth resolutions): a change destroys and rebuilds the instance, and the caches warm
2265
+ up again.
2266
+ - **The mesh cache fields** (`mesh_sdf_voxel_size`, `mesh_sdf_max_bricks`): a change rebakes every
2267
+ cached geometry.
2268
+ - **Budgets and times** (`brick_build_budget`, `mesh_sdf_bake_budget`, `card_capture_budget`,
2269
+ `rays_per_probe`, `ray_budget`, `response_time`, `retention_time`): uniforms and transient sizes, so
2270
+ they take effect the next frame without a rebuild.
2271
+
2272
+ | Setting | Default | Range | Changes |
2273
+ |---|---|---|---|
2274
+ | `brick_cascade_count` | 6 | 1–8 | brick map depth, initial capacity |
2275
+ | `brick_cascade_resolution` | 32 | 16, 32, 64 | cells per axis per cascade |
2276
+ | `brick_voxel_size` | 0.125 m | > 0 | finest voxel; every cascade doubles it |
2277
+ | `brick_build_budget` | 4,096 | ≥ 64 | cells written a frame (a time knob, as `shadow_update_budget` is) |
2278
+ | `mesh_sdf_voxel_size` | 0.125 | > 0 | mesh voxel, in the geometry's local units |
2279
+ | `mesh_sdf_max_bricks` | 18 | even, 2–64 | bricks per axis before the voxel grows (a safety net; UE's per-mesh cap); 64 bounds the levels a thread walks |
2280
+ | `mesh_sdf_bake_budget` | 23 | 1–8,191 | bricks evaluated a frame while caches fill (a time knob; derived in §6.4) |
2281
+ | `card_capture_budget` | 16,384 | 1 – 65,535 | card pages captured a frame, new pairs first, then recaptures (a time knob; derived in S2, §6.5) |
2282
+ | `probe_cascade_count` | 5 | 1–8 | probe levels |
2283
+ | `probe_cascade_resolution` | 32 | 16, 32, 64 | lattice points per axis per cascade |
2284
+ | `probe_spacing` | 1 m | > 0 | finest spacing; every cascade doubles it |
2285
+ | `radiance_resolution` | 16 | 4–32, power of two | octahedral radiance texels per side |
2286
+ | `depth_resolution` | 8 | 4–32, power of two | octahedral depth texels per side |
2287
+ | `rays_per_probe` | 256 | a power of two in [n_r²/4, 4·n_r²] | rays per probe update; below n_r² an update covers a spread subset of texels, above it each texel averages several |
2288
+ | `ray_budget` | 131,072 | ≥ `rays_per_probe` | rays per frame (a time knob) |
2289
+ | `response_time` | 0.5 s | > 0 | temporal time constant τ |
2290
+ | `retention_time` | 1 s | > 0 | how long an unwanted probe keeps its slot |
2291
+
2292
+ The defaults:
2293
+ - They sit between Enshrouded's low and mid tiers (100k and 250k rays; radiance 8 and 16).
2294
+ - The probe cascade matches Lumen's 1.04 m and DDGI's usual 1–2 m.
2295
+ - The brick voxel is UE's 19.8 cm order, and the mesh voxel matches it at unit scale.
2296
+
2297
+ **Fixed, not settings**:
2298
+ - the brick's 8³ / 7 layout, for world and mesh bricks alike;
2299
+ - R = 4 voxels;
2300
+ - the size-class step of two bricks;
2301
+ - the hit threshold and minimum step, ½ voxel;
2302
+ - 64 steps a ray;
2303
+ - 64 instances per cell in the mesh provider, 256 triangles per cell in the vgeo provider;
2304
+ - 32 cards per geometry, and 4 alpha continuations per capture texel;
2305
+ - the 2³-texel object cell;
2306
+ - 2 probes per pick;
2307
+ - 2 shadowed suns and 32 local lights per hit;
2308
+ - the 4³-cell occupancy block;
2309
+ - the 25% back-face threshold.
2310
+
2311
+ Each is stated where it is used, with what is lost past it.
2312
+
2313
+ ## 11. Budget
2314
+
2315
+ Derived counts at the defaults. **No time here is measured.** §13 measures each stage on the 4090
2316
+ and on the AMD iGPU before the next begins.
2317
+
2318
+ **Memory**
2319
+
2320
+ | Resource | Size |
2321
+ |---|---|
2322
+ | brick map + occupancy | 32³ × 6 × 4 B + 8³ × 6 × 4 B = 0.76 MiB |
2323
+ | world bricks at initial capacity 12,288 | SDF 512 B + objects 256 B → 9 MiB |
2324
+ | pending ring | 196,608 × 4 B = 768 KiB; as built, 262,144 × 4 B = 1 MiB (§7.4) |
2325
+ | probe indirection + wanted bits | 32³ × 5 × 4 B + 20 KiB = 0.64 MiB |
2326
+ | per probe | radiance 18² × 8 B + depth 10² × 4 B + record 64 B + state 4 B = 3,060 B |
2327
+ | probes at initial capacity 16,384 | 48 MiB |
2328
+ | geometry caches | per surface brick of a cached geometry: 512 B of SDF and about a seventh more for the levels, once however many instances draw it |
2329
+ | card sets | per surface brick and per (geometry, material) pair: two to four pages of 512 B (a surface faces two of the six directions, and slabs add few). Measured in S2: Sponza's 103 card sets hold 154,138 pages, 79 MB. Most geometries draw with one material, so most have one card set |
2330
+ | transients | build staging 4,096 × 768 B = 3 MiB; ray records 131,072 × 24 B = 3 MiB; probe maps 512 × 2.25 KiB = 1.2 MiB |
2331
+
2332
+ The initial probe capacity is `2·N_p²·C_p` = 10,240 (a visible surface crosses each cascade as a
2333
+ one-cell-thick shell, doubled for the cage), rounded up to a power of two. It matches the 16k that
2334
+ Lumen and Enshrouded settled on.
2335
+
2336
+ **Dense comparison** (D31): every lattice point of 5 × 32³ has a probe. That is 163,840 probes,
2337
+ 478 MiB, and at the same ray budget a period ten times longer.
2338
+
2339
+ **Work a frame**
2340
+ - Rays ≤ 131,072, each ≤ 64 steps of 2–3 loads, plus up to 2 sun shadow marches.
2341
+ - Shading: an object load, the card surface (§6.6), up to 32 lights, and a pick.
2342
+ - World bricks ≤ 4,096 cells. An empty cell costs one TLAS level. A cell with instances costs, per
2343
+ texel, ≤ 64 box tests, plus a transform, an indirection load and a tap per instance that passes.
2344
+ - Pixels: 8 × (an indirection load, a state word, a depth tap), then 2 records and 2 radiance taps.
2345
+ - Bakes: only while caches fill, ≤ `mesh_sdf_bake_budget` × 33k BLAS queries a frame.
2346
+ - Captures: only for new pairs and changed materials, ≤ `card_capture_budget` × 64 texels a frame,
2347
+ each a ray, up to 4 alpha draws and a material sample.
2348
+ - **Passes**: about 20 dispatches a frame, counting the one-thread command builders. A pass on the
2349
+ 4090 costs a measured 5–8 µs however small (2–3 µs for one thread), so the floor is near 0.1 ms
2350
+ before any work. It is stated so the measurement can be read against it.
2351
+
2352
+ ## 12. Verification
2353
+
2354
+ **Tier 1, WGSL parse and validation**: every new module, through the existing `*_wgsl_validity`
2355
+ specs. A real compile on a device catches what the validator misses.
2356
+
2357
+ **Tier 2, emulator**: pure chunks against CPU oracles.
2358
+ - **Mesh caches**:
2359
+ - Size classes: every axis even, ≥ 2, grown in steps of two; the voxel grows past the cap.
2360
+ - The bake's texels against `blas_query_sdf` evaluated on the CPU at the same points, for a sphere,
2361
+ a box and an open plane. Exact distances within one LSB; signs right on the closed meshes.
2362
+ - As built (S3): against UE's vote evaluated in doubles, which pins as well the shell behind an
2363
+ open quad, a closed box drawn two-sided, and a texel past R/2 inside a large face.
2364
+ - Classify never drops a brick that evaluate would keep.
2365
+ - `mesh_sdf_sample` outside the grid box never exceeds the true distance (contract 4).
2366
+ - Card placement covers every run start of a hollow box and of an L-shaped room within 32 cards.
2367
+ - A capture of a textured quad matches `sample_material_data` at the same points under the same
2368
+ seed: diffuse albedo and emissive, each within one LSB of its encoding.
2369
+ - A recapture of an unchanged material writes the same bytes.
2370
+ - The card depth tolerance passes a hit displaced by up to ½ voxel of its cascade, at every
2371
+ cascade.
2372
+ - **World bricks**:
2373
+ - `r8unorm` encode/decode round trip within one LSB.
2374
+ - The mesh provider's texels against a brute-force minimum over the same instances' CPU distances.
2375
+ - The merge: two providers in either order produce the same bytes and, outside ties, the same
2376
+ objects.
2377
+ - `brick_clipmap_trace` against analytic spheres, boxes and planes built into bricks on the CPU:
2378
+ the hit distance error is ≤ ½ voxel + 1 LSB.
2379
+ - The occupancy skip never misses a hit that a brute-force march finds.
2380
+ - UNKNOWN cells defer to the parent.
2381
+ - The soft-shadow penumbra matches the analytic disk light at a sphere's edge.
2382
+ - As built (S3e): against the disk past the surface the tracer hits, half a voxel out, within 0.1;
2383
+ half at the edge within 0.1.
2384
+ - `mesh_card_surface`: a hit on a card's surface returns that texel's diffuse albedo and emissive,
2385
+ and a hit hidden from every card returns the material mean.
2386
+ - **Probes**:
2387
+ - Every generated direction encodes back into its own texel.
2388
+ - SH2 projection of constant radiance L gives E = πL for every n.
2389
+ - A single bright texel matches the SH2 of that cone.
2390
+ - The update blend reproduces α for a known Δt.
2391
+ - A ray from inside a solid is a back face at its first step.
2392
+ - **Sampling**:
2393
+ - The pick's frequencies converge to the normalised weights over many ξ.
2394
+ - A probe behind a slab, per its depth moments, weighs under the crush and is never picked.
2395
+ - The cascade blend is continuous across the skirt.
2396
+ - `resolve_irradiance_sh_to_specular` at g₁ = 2/3 equals `resolve_irradiance_sh_to_diffuse`, and
2397
+ returns L under constant radiance L at every α.
2398
+ - **Extracted pieces** (probe weight, pick, hash, soft-shadow estimator, free-list pop/push): their
2399
+ old callers' specs stay green. LPV's and Brick4's sampling are unchanged to the bit.
2400
+
2401
+ **Tier 3, SoftwareGPUDevice**: host orchestration, black-box on what reaches the device.
2402
+ - A one-cell anchor move produces exactly the scroll boxes' cells in the pending ring and frees the
2403
+ vacated slots: host-written bytes and dispatch counts.
2404
+ - Every dispatch is sized by a live count: indirect over a device count, or host-known for `scroll`,
2405
+ `want`, `coarse` and the bake. None is sized by a capacity.
2406
+ - A row whose `SDFWorld` bit is cleared reaches the device with bit 0 of its `flags` clear, and the
2407
+ host pushes its box.
2408
+ - A geometry is baked once however many rows draw it, and freed when the last row goes.
2409
+ - A pair is captured once however many rows draw it.
2410
+ - A row that changes material moves one pair's count to another.
2411
+ - A material whose version moves recaptures exactly its own card sets, once.
2412
+ - A pair still capturing reads null in the row → card set table.
2413
+ - A provider registered after the mesh provider runs after it, over the same taken keys.
2414
+ - A settings change reallocates to the new sizes.
2415
+ - Entering and leaving the mode leaves `device.live_resources` as it was (the leak-spec pattern).
2416
+ - The mover list is produced once a frame and read by both VSM and this mode.
2417
+
2418
+ **Tier 4, device** (headless Chrome; few hundred frames at small sizes, never sweeps):
2419
+ - **White furnace**: a closed box of albedo ρ and emission L_e converges to L = L_e/(1 − ρ). This
2420
+ checks multi-bounce energy end to end.
2421
+ - **Cornell box** against the accumulating path tracer, with an error metric.
2422
+ - **Leak cases**: a sunlit wall thinner than a coarse voxel; a closed room beside daylight.
2423
+ - **Absence**: a bright emissive mesh out of the SDF world lights nothing through GI.
2424
+ - **Recapture**: an emissive material switched on lights the scene through GI after its card sets are
2425
+ recaptured. The lag is measured in frames at the default budget.
2426
+ - **Stability**: an orbit and a dolly, the same path for A and B, measuring frame-to-frame change of
2427
+ the indirect term. A still camera proves nothing. The pick's noise is measured here against the
2428
+ eight-probe evaluation, as a one-off.
2429
+ - **Counters**: dropped instances and triangles, oversize geometries, unresolved rays, dead probes,
2430
+ allocation failures, period T.
2431
+ - **The storage-write rounding question of §8.8.**
2432
+
2433
+ ## 13. Stages
2434
+
2435
+ Each stage lands suite-green and is measured before the next.
2436
+
2437
+ | Stage | Scope | Done when |
2438
+ |---|---|---|
2439
+ | S0 | enum value, `ProbeClipmapSettings`, lifecycle; the five alternatives and the deferred case behave as IBL | consumer specs green with the new value; leak spec |
2440
+ | S1 | scene-level mover list with the skinned bit (D32), VSM migrated; the `SDFWorld` bit through `ShadedGeometrySystem` into the row's `flags`; `onMeshWritten` | VSM specs and playground unchanged; rows specs |
2441
+ | S2 | geometry caches: `GPUGeometrySDFManager` sparse (classify, evaluate, store, levels, size classes); cards (placement, capture, recapture on the resident context's repack signal); the pair bookkeeping and the row → card set table; the bake and capture queues and budgets; the four readers ported; debug views of a mesh's bricks and cards | tier-2 oracles; bake and capture timings, which set `mesh_sdf_bake_budget` and `card_capture_budget` |
2442
+ | S3 | brick clipmap: windows, map, atlas, free list, scroll, movers, clear, the provider contract, the mesh provider, store, occupancy, object cells, trace chunks, a ray-marched debug view | tier-2 oracles; device timings of build and trace |
2443
+ | S4 | probe clipmap: lifetime, relocation, schedule, trace with sun shadow, shade (emissive, sun, sky; the card surface), accumulate, publish; deferred diffuse through the pick | furnace (one bounce), stability, timings |
2444
+ | S5 | next bounce (E_ind); local lights via generalised world clusters; the forward, water, SSR-hit and irradiance-clipmap alternatives | furnace (multi-bounce), Cornell vs path tracer |
2445
+ | S6 | specular: radiance ⊕ GGX-SH2, parallax, fused pass, SSR fallback, forward and water specular | parallax A/B, reflections in a closed room |
2446
+ | S7 | the virtual geometry provider: box cut, streaming invalidation | Zorah lit by its own geometry; timings |
2447
+ | S8 | measured follow-ups only (§17) | — |
2448
+
2449
+ ## 14. Decisions taken here
2450
+
2451
+ Each says what would reverse it.
2452
+
2453
+ - **D1. Brick = 8³ texels on 7³ voxels (corner lattice)**, for world and mesh bricks alike. UE pages
2454
+ and mesh distance fields agree. *Reverse:* none foreseen.
2455
+ - **D2. Signed distance, 4-voxel band, ½-voxel hit.**
2456
+ - (a)'s case for unsigned was that a per-cell triangle gather cannot tell inside from outside.
2457
+ Whole-mesh bakes can, and the minimum of signed fields is their union.
2458
+ - What the sign buys: relocation pushes probes out from inside, back faces are a gradient test, and
2459
+ no triangle orientation is stored.
2460
+ - The ½-voxel hit keeps walls thinner than a voxel, as UE's expand does.
2461
+ - *Reverse:* if measured sign failures on real assets cost more than this.
2462
+ - **D3. Allocate iff a staged texel has |d| under one voxel.** Fewer bricks than UE's
2463
+ within-R-of-the-page-radius rule; the occupancy skip covers the cells left out.
2464
+ *Reverse:* if trace steps measure high beside surfaces.
2465
+ - **D4. Two-level occupancy (HDDA) instead of UE's coarse eikonal mip.** Incremental, toroidal, no
2466
+ propagation passes. *Reverse:* if sky rays exhaust 64 steps in measurement.
2467
+ - **D5. Material from surface cards with Lumen's payload** (Alex's answer on the card payload).
2468
+ - Diffuse albedo and emissive are captured per (geometry, material) pair and recaptured when the
2469
+ material's version moves.
2470
+ - A hit does no material work.
2471
+ - *Reverse:* none of mine; Alex chose it over cards that hold uvs.
2472
+ - **D6. No triangle is read per frame.** Meshes are read at bakes (the SDF, per geometry) and at
2473
+ captures (the cards, per pair and per material change). The vgeo provider reads its cut per
2474
+ requested cell, never per frame. *Reverse:* none; it is the review's rule.
2475
+ - **D7. Hits are diffuse only: `L = emissive + ρ_d·E/π`.**
2476
+ - That is what Lumen's payload holds, and Lumen's surface cache lights diffusely too.
2477
+ - (b) first had the full BRDF's directional albedo at the hit's NoV (`tSplitSum`), which needed
2478
+ roughness and metalness at every hit.
2479
+ - What is lost: a metal bounces only its emissive.
2480
+ - *Reverse:* if metals measure dark in the bounce, capture the BRDF's hemispherical albedo in place
2481
+ of the diffuse one. That needs the same storage and no hit-side change.
2482
+ - **D8. Radiance `rgba16float`, two-pass update.** Hardware bilinear for every consumer.
2483
+ *Reverse:* if the stall bias measures visible, f32 history in a buffer.
2484
+ - **D9. Depth moments normalised by spacing, clamped at √3·s.**
2485
+ - **D10. SH2 projected from blended radiance, not blended separately.**
2486
+ - **D11. Exponential blend over a response time in seconds; jittered stratified rays.**
2487
+ - Lumen overwrites without jitter, but its screen probes filter downstream. Here consumers read
2488
+ the probes directly.
2489
+ - DDGI 2021's per-texel change boost is left out. A texel here sees one ray an update, so a change
2490
+ test on it is a noise test.
2491
+ - *Reverse:* if noise or lag measures visible at the defaults, Enshrouded's moving-average
2492
+ estimator, which is the variance-aware form of that boost.
2493
+ - **D12. Schedule: NEW first, then a slot-hashed phase with a period from the live count.**
2494
+ - **D13. Pixels pick 2 of 8 by WRS after visibility-only weights** (the review). Brick4's sampler and
2495
+ noise. *Reverse:* if the measured noise under TAA is visible, then a screen-space reservoir resolve,
2496
+ argued from that measurement.
2497
+ - **D14. Sun shadows at hits by SDF soft-shadow rays.** Shadow maps read lit off screen.
2498
+ - **D15. Local lights from the world clusters with the shadow-atlas lookups.** A light with a
2499
+ cleared map is unshadowed at hits.
2500
+ - **D16. Settings sub-object, rebuild on mismatch.**
2501
+ - **D17. Capacity learned from reported failures, never shrinks.**
2502
+ - **D18. The mode is named `ProbeClipmap`**, after what shading samples, as Brick4 and LPV are.
2503
+ - **D19. No bounce attenuation factor.**
2504
+ - **D20. Specular blends a radiance tap with GGX-convolved SH2 by `roughness_to_mip_ratio`** (the
2505
+ review), LPV's blend in Metro form. *Reverse:* none of mine; the review set it.
2506
+ - **D21. One object per 2³-texel cell, written by the providers' own minimum.**
2507
+ - UE's object grid has the same 4³ cells a page but keeps the 4 nearest objects per cell, 1 KiB a
2508
+ page. It is filled by its own pass, and a hit blends their cards up to a weight of 0.9.
2509
+ - Here the cell costs 256 B, and the argmin falls out of the minimum the providers compute anyway.
2510
+ - Where two objects meet inside one cell, a hit can name the wrong one. Its card depth test then
2511
+ fails, and the hit takes the material mean.
2512
+ - *Reverse:* if seams measure visible, then UE's four candidates.
2513
+ - **D22. Providers merge by a min of encoded bytes, objects by the cell minimum.** The order of
2514
+ providers cannot change a distance.
2515
+ - **D23. Cards per depth slab, placed by UE's clustering rule at brick granularity, ≤ 32 per
2516
+ geometry.**
2517
+ - Six bounds cards would miss every interior surface of a single-mesh room or atrium.
2518
+ - UE places its near planes from 10 cm surfels with 32 rays a column. The brick occupancy the bake
2519
+ already holds gives the same rule (MinRayZ ≤ N ≤ Z) at 7-voxel granularity, with no rays.
2520
+ - *Reverse:* if coverage measures short on real assets, then surfels from the capture rays.
2521
+ - **D24. Card texels are two `rgba8unorm` planes, 8 B in all.**
2522
+ - Diffuse albedo is stored as its square root, as UE stores it.
2523
+ - Emissive is stored under the pair's scale s_e, which loses nothing that 8-bit resident textures
2524
+ had.
2525
+ - Depth is 8 bits over the slab, under 0.5 voxel at the 18-brick cap. That is well inside the depth
2526
+ tolerance of 1.5 cascade voxels.
2527
+ - *Reverse:* an emissive that measures banded; then `rgba16float` for that plane, 4 B more a texel.
2528
+ - **D25. SDF membership is a `ShadedGeometryFlags` bit, on by default, mirrored into the row.**
2529
+ - It is the entity's data, carried as `Skinned` is, and transparent materials stay out by rule.
2530
+ - UE's `bAffectDistanceFieldLighting` is the same switch, and UE leaves translucent sections out
2531
+ too.
2532
+ - **D26. A cascade samples the coarsest mesh level no coarser than itself.**
2533
+ - Its voxel is within a factor of two of the cascade's, and its band reaches at least half the
2534
+ cascade's. Past that band a sample under-estimates, which is safe.
2535
+ - UE instead walks the resident mips from coarse to fine per sample, with mips streamed by distance.
2536
+ Choosing per cascade is one decision per instance and cell, and it needs no residency.
2537
+ - *Reverse:* if steps measure slow beside surfaces at the band's edge, then the next level up.
2538
+ - **D27. The bake drops the open-mesh wrap.** The band stores nothing past R, which is what the wrap
2539
+ was for.
2540
+ - **D28. The caches live on the geometry manager, not on the GI instance.** They survive a mode switch
2541
+ and serve any later SDF reader. The GI keeps only the bookkeeping that requests them.
2542
+ - **D29. Recapture keys on `ShadeMaterial.version`, through the resident context's repack.**
2543
+ - It is the change signal every material consumer already uses, and the repack is the one place it
2544
+ is read. Nothing polls.
2545
+ - UE tracks no material change at all; there a primitive is recaptured on an explicit
2546
+ `InvalidateLumenSurfaceCache` or by the slow refresh of its oldest pages (§2.3).
2547
+ - *Reverse:* none foreseen.
2548
+ - **D30. Each passing card gives one texel, blended across cards by n².**
2549
+ - UE also blends four depth-weighted taps per card.
2550
+ - Here a probe's many rays do that averaging, and one texel per card halves the loads.
2551
+ - *Reverse:* if card seams measure visible in the bounce, then UE's four taps.
2552
+ - **D31. Probes are a sparse cache from the screen, not a dense lattice** (Alex, as recommended).
2553
+ - "Also a 3D clipmap" holds either way.
2554
+ - At the defaults the dense form is 10× the memory and 10× the update period (§11).
2555
+ - The cost of sparse: no probes where nothing visible needs them, so off-screen bounces see only the
2556
+ probes that exist.
2557
+ - *Reverse:* if the off-screen bounce measures short, Enshrouded's world-cache probes (§17).
2558
+ - **D32. The mover pass moves from VSM to scene level, with a skinned bit** (Alex, as recommended).
2559
+ - The kernels and the list stay the same. The scene context owns them and produces the list once a
2560
+ frame for any reader.
2561
+ - The skinned bit lets this mode skip boxes that only animation moved (§7.4).
2562
+ - VSM's lifetime coupling goes away.
2563
+ - *Reverse:* none foreseen.
2564
+
2565
+ ## 15. Forks for Alex
2566
+
2567
+ None is open. How each was settled:
2568
+ - **(a)'s fork 1**, vgeo and DynamicMesh invisible to rays: by the geometry caches and the providers
2569
+ of the review (§6, §7.6–7.8).
2570
+ - **(a)'s fork 2**, unsigned distance: dissolved, because a whole-mesh bake knows the sign (D2).
2571
+ - **(a)'s fork 3**, a sparse probe cache: taken as recommended (D31).
2572
+ - **(a)'s fork 4**, the mover pass at scene level: taken as recommended, with the skinned bit (D32).
2573
+ - **(b)'s card payload**: Lumen's, diffuse albedo and emissive captured per (geometry, material) and
2574
+ recaptured on a material change (D5).
2575
+
2576
+ ## 16. Duplication ledger
2577
+
2578
+ Found during the audit. Items marked *(here)* are resolved by this proposal; the rest are listed,
2579
+ not fixed.
2580
+
2581
+ **Resolved here**
2582
+ - *(here)* `GPUGeometrySDFManager`'s dense tiles, readers and all → sparse bricks in place.
2583
+ - *(here)* The probe weighting lives only inside LPV's tetrahedral sampler → extracted.
2584
+ - *(here)* Brick4's pick and its forward hash, private to Brick4 → extracted.
2585
+ - *(here)* An SDF penumbra estimator buried in a dense-volume shader → not extracted: the brick
2586
+ clipmap's estimate is the two-sided one (§4.2).
2587
+ - *(here)* GPU slot stacks: particles' own → extracted and shared.
2588
+ - *(here)* World clusters keyed to one consumer's struct → keyed by `CLIPMAP_LEVEL_ARRAY`.
2589
+ - *(here)* The mover list owned by VSM → scene level.
2590
+
2591
+ **Listed**
2592
+ - `CascadedSceneSDF` duplicates what the brick clipmap does once S3 lands, and is a candidate for
2593
+ deletion. Alex's call; the lightmap tree is the precedent for keeping things. The Brixelizer port
2594
+ stays as a reference.
2595
+ - Toroidal wrap in five places, and cascade placement in two (`IrradianceCascadePlacement` beside
2596
+ `ClipmapWindowSet`).
2597
+ - Finest-cascade selection in two forms (box, sphere), and cascade tables in four forms. The unused
2598
+ `global_illumination/clipmap/CLIPMAP_METADATA.js` and `CLIPMAP_CASCADE_METADATA.js` are kept
2599
+ surface.
2600
+ - Eight radiance → SH projections; `sh2_color_get_irradiance_at` ≡ `sh2_color_irradiance` apart
2601
+ from a clamp.
2602
+ - Three manual octahedral bilinear samplers; two border painters (LPV's perimeter walk, whose
2603
+ radiance border is never read, and the environment skirt).
2604
+ - Two 64-ray volume-sign votes plus a CPU twin; three SDF-gradient variants; three ray-AABB slab
2605
+ tests. S3 deleted the BLAS vote, with the bake's move to UE's.
2606
+ - `chunk_lpv_mask_weights_by_visibility` and its `_no_depth` twin define the same WGSL function name.
2607
+ - The irradiance clipmap cites a "Decision 6.3" document that exists nowhere in the tree or its
2608
+ history.
2609
+
2610
+ ## 17. Not in this proposal
2611
+
2612
+ Each item is added only if a measurement asks for it, or, where marked, when Alex schedules it:
2613
+ - **Skinned meshes as a dense animated patch** (Alex: later). The hooks are the clone's header alias
2614
+ (§6.3), the mesh provider's accept (§7.7) and the skinned movers the GI skips today (§7.4).
2615
+ - **DynamicMesh in the SDF world.** It has no row and changes every frame; a provider writing per-frame
2616
+ patches is the same mechanism as the skinned one.
2617
+ - **Cards for virtual geometry**, its own plan; until then vgeo hits take the material mean.
2618
+ - **Lighting in the surface cache** (Lumen's direct lighting and radiosity per card texel). Here the
2619
+ probes carry the bounce.
2620
+ - **Specular at secondary hits.** Hits are diffuse only (D7), so a metal bounces nothing but its
2621
+ emissive. The measured fix is the BRDF's hemispherical albedo captured in place of the diffuse
2622
+ one.
2623
+ - **Caches persisted across sessions**, an offline bake format.
2624
+ - World-cache probes at ray hits (Enshrouded's second kind), if the off-screen bounce measures short.
2625
+ - Importance-sampled ray directions, if noise at the defaults measures visible.
2626
+ - Ray and history reprojection between probes, if long-range propagation into enclosed spaces
2627
+ measures short.
2628
+ - Foliage and translucency in the field, Enshrouded's open problem too.
2629
+ - Alpha-tested geometry is in the SDF as its triangles, so canopies over-occlude. The `SDFWorld`
2630
+ bit is the authored way out.
2631
+ - UE marks voxels within the band of only two-sided meshes with zero coverage. There its trace
2632
+ shrinks the surface expand from 1.0 to 0.6 and lengthens the minimum step fourfold. That is the
2633
+ shape of the fix if it measures necessary: a coverage bit per brick cell beside the object.
2634
+ - Ambient probes for fog. Fog has no GI in any mode.
2635
+ - Sharing one clipmap between views.
2636
+
2637
+ ## 18. Sources
2638
+
2639
+ - J. Kolesik, *Realtime Global Illumination in Enshrouded*, GPC 2024 —
2640
+ https://www.youtube.com/watch?v=57F1ezwH7Mk
2641
+ - Unreal Engine 5.4 source, under `Engine/`:
2642
+ - the global field: `Source/Runtime/Renderer/Private/GlobalDistanceField.cpp`,
2643
+ `Shaders/Private/DistanceField/GlobalDistanceField*.usf/.ush`, `GlobalDistanceFieldObjectGrid.ush`;
2644
+ - mesh distance fields: `Source/Runtime/Engine/Public/DistanceFieldAtlas.h`,
2645
+ `Source/Developer/MeshUtilities/Private/MeshDistanceFieldUtilities.cpp`,
2646
+ `Shaders/Private/MeshDistanceFieldCommon.ush`, `Shaders/Private/DistanceFieldLightingShared.ush`;
2647
+ - mesh cards and the surface cache: `Source/Developer/MeshUtilities/Private/MeshCardRepresentationUtilities.cpp`,
2648
+ `Source/Runtime/Renderer/Private/Lumen/LumenSurfaceCache.cpp`, `LumenSceneRendering.cpp`,
2649
+ `LumenSceneCardCapture.cpp`, `Shaders/Private/Lumen/SurfaceCache/LumenSurfaceCacheSampling.ush`,
2650
+ `Shaders/Private/Lumen/LumenSoftwareRayTracing.ush`;
2651
+ - the radiance cache: `Source/Runtime/Renderer/Private/Lumen/LumenRadianceCache*.cpp`,
2652
+ `Shaders/Private/Lumen/LumenRadianceCache*.usf/.ush`.
2653
+ - Z. Majercik et al., *Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields*,
2654
+ JCGT 8(2), 2019 — https://jcgt.org/published/0008/02/01/ ; *Scaling Probe-Based Real-Time Dynamic
2655
+ Global Illumination for Production*, JCGT 10(2), 2021 — https://jcgt.org/published/0010/02/01/
2656
+ - NVIDIA RTXGI-DDGI, `rtxgi-sdk/include/rtxgi/ddgi/DDGIVolume.h` and `docs/DDGIVolume.md` —
2657
+ https://github.com/NVIDIAGameWorks/RTXGI-DDGI
2658
+ - AMD FidelityFX Brixelizer and Brixelizer GI —
2659
+ https://gpuopen.com/manuals/fidelityfx_sdk/fidelityfx_sdk-page_techniques_brixelizer/ ,
2660
+ https://gpuopen.com/manuals/fidelityfx_sdk/techniques/brixelizer-gi/ , FidelityFX-SDK v1.1.4
2661
+ `sdk/include/FidelityFX/gpu/brixelizer/`, and
2662
+ https://gpuopen.com/gdc-presentations/2024/GDC2024_GI_with_AMD_FidelityFX_Brixelizer.pdf
2663
+ - Godot 4.3 SDFGI — https://docs.godotengine.org/en/stable/tutorials/3d/global_illumination/using_sdfgi.html ,
2664
+ `servers/rendering/renderer_rd/environment/gi.cpp` and `shaders/environment/sdfgi_*.glsl`;
2665
+ HDDAGI — https://github.com/godotengine/godot/pull/86267 , https://github.com/godotengine/godot/pull/119869
2666
+ - kajiya GI overview — https://github.com/EmbarkStudios/kajiya/blob/main/docs/gi-overview.md
2667
+ - K. Museth, *NanoVDB: A GPU-Friendly and Portable VDB Data Structure for Real-Time Rendering and
2668
+ Simulation*, SIGGRAPH 2021 Talks.
2669
+ - M. Fajardo et al., *Stochastic Texture Filtering*, 2023 — the WRS of `sample_discrete_wrs_mat2x4`.
2670
+ - M. Pettineo, *SHforHLSL* — https://github.com/TheRealMJP/SHforHLSL (the GGX zonal fit).
2671
+ - S. Lagarde and C. de Rousiers, *Moving Frostbite to Physically Based Rendering 3.0*, SIGGRAPH 2014
2672
+ course notes (the dominant direction; the roughness-to-mip curve).
2673
+ - *Exploring Ray-Traced Future in Metro Exodus*, GTC 2019 (the L1 YCoCg encoding; in-tree
2674
+ `l1i/NOTES.md`).
2675
+ - I. Quílez, distance-field gradients (the tetrahedral 4-tap form) and soft shadows.
2676
+ - In-tree: `SHADER_SWITCH_PROPOSAL_2026_10_16.md`, `engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md`,
2677
+ `shadow/vsm/PLAN.md`, `volumetrics/NOTES.md`, `geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md`.