@woosh/meep-engine 3.53.0 → 3.54.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 (194) hide show
  1. package/package.json +1 -1
  2. package/src/core/math/noise/worley_noise_2d.d.ts +14 -0
  3. package/src/core/math/noise/worley_noise_2d.d.ts.map +1 -0
  4. package/src/core/math/noise/worley_noise_2d.js +74 -0
  5. package/src/engine/graphics/texture/atlas/CachingTextureAtlas.d.ts +6 -1
  6. package/src/engine/graphics/texture/atlas/CachingTextureAtlas.d.ts.map +1 -1
  7. package/src/engine/graphics/texture/atlas/CachingTextureAtlas.js +363 -325
  8. package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.d.ts +93 -14
  9. package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.d.ts.map +1 -1
  10. package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.js +322 -183
  11. package/src/engine/graphics/texture/atlas/ReferencedTextureAtlas.d.ts +9 -0
  12. package/src/engine/graphics/texture/atlas/ReferencedTextureAtlas.d.ts.map +1 -1
  13. package/src/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +110 -83
  14. package/src/engine/graphics/texture/atlas/SpriteAtlas.d.ts +42 -0
  15. package/src/engine/graphics/texture/atlas/SpriteAtlas.d.ts.map +1 -0
  16. package/src/engine/{graphics3/decal/DecalAtlas.js → graphics/texture/atlas/SpriteAtlas.js} +202 -194
  17. package/src/engine/graphics/texture/atlas/SpriteAtlasFill.d.ts +12 -0
  18. package/src/engine/graphics/texture/atlas/SpriteAtlasFill.d.ts.map +1 -0
  19. package/src/engine/graphics/texture/atlas/SpriteAtlasFill.js +30 -0
  20. package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts +7 -0
  21. package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
  22. package/src/engine/graphics/texture/atlas/TextureAtlas.js +11 -1
  23. package/src/engine/graphics/texture/atlas/sprite_atlas_border.d.ts +52 -0
  24. package/src/engine/graphics/texture/atlas/sprite_atlas_border.d.ts.map +1 -0
  25. package/src/engine/{graphics3/decal/decal_atlas_border.js → graphics/texture/atlas/sprite_atlas_border.js} +69 -69
  26. package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
  27. package/src/engine/graphics3/DecalSystem.js +447 -450
  28. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +9 -22
  29. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
  30. package/src/engine/graphics3/GPUParticleEmitterSystem.js +892 -951
  31. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  32. package/src/generation/foliage/FOLIAGE_DESIGN.md +2 -1
  33. package/src/generation/foliage/config/BarkMaterialConfig.d.ts +4 -3
  34. package/src/generation/foliage/config/BarkMaterialConfig.d.ts.map +1 -1
  35. package/src/generation/foliage/config/BarkMaterialConfig.js +6 -6
  36. package/src/generation/foliage/config/FoliageBarkType.d.ts +11 -0
  37. package/src/generation/foliage/config/FoliageBarkType.d.ts.map +1 -0
  38. package/src/generation/foliage/config/FoliageBarkType.js +16 -0
  39. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +58 -5
  40. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -1
  41. package/src/generation/foliage/config/FoliageMaterialConfig.js +279 -181
  42. package/src/generation/foliage/index.d.ts +2 -1
  43. package/src/generation/foliage/index.js +44 -43
  44. package/src/generation/foliage/material/make_bark_material.d.ts.map +1 -1
  45. package/src/generation/foliage/material/make_bark_material.js +23 -95
  46. package/src/generation/foliage/material/make_foliage_material.d.ts +29 -3
  47. package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -1
  48. package/src/generation/foliage/material/make_foliage_material.js +605 -359
  49. package/src/generation/foliage/mesh/branch_collar_project.d.ts.map +1 -1
  50. package/src/generation/foliage/mesh/branch_collar_project.js +205 -203
  51. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +15 -0
  52. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -1
  53. package/src/generation/foliage/mesh/foliage_collect_attachments.js +569 -502
  54. package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
  55. package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1049 -1047
  56. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +2 -1
  57. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -1
  58. package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +454 -415
  59. package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
  60. package/src/generation/foliage/presets/make_tree_species_preset.js +870 -837
  61. package/src/generation/foliage/skeleton/crown_envelope_evaluate.js +121 -121
  62. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts +10 -7
  63. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts.map +1 -1
  64. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js +206 -179
  65. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
  66. package/src/generation/foliage/skeleton/tree_skeleton_grow.js +1871 -1104
  67. package/src/shade/playground/foliage_wind/foliage_world.d.ts +6 -0
  68. package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
  69. package/src/shade/playground/foliage_wind/foliage_world.js +602 -593
  70. package/src/shade/playground/foliage_wind/index.html +260 -254
  71. package/src/shade/playground/foliage_wind/main.js +275 -263
  72. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  73. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  74. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  75. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  76. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  77. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +1 -1
  78. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +3 -3
  79. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  80. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +350 -294
  81. package/src/shade/renderer/hiz/generate_downsampler_code.d.ts +0 -2
  82. package/src/shade/renderer/hiz/generate_downsampler_code.d.ts.map +1 -1
  83. package/src/shade/renderer/hiz/generate_downsampler_code.js +99 -100
  84. package/src/shade/renderer/hiz/hzb_pick_alignment.d.ts +15 -0
  85. package/src/shade/renderer/hiz/hzb_pick_alignment.d.ts.map +1 -0
  86. package/src/shade/renderer/hiz/hzb_pick_alignment.js +148 -0
  87. package/src/shade/renderer/hiz/hzb_plan_reduction_steps.d.ts +28 -0
  88. package/src/shade/renderer/hiz/hzb_plan_reduction_steps.d.ts.map +1 -0
  89. package/src/shade/renderer/hiz/hzb_plan_reduction_steps.js +58 -0
  90. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +5 -5
  91. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
  92. package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +57 -67
  93. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +3 -3
  94. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +1 -1
  95. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.js +111 -112
  96. package/src/shade/renderer/hiz/shader_hzb_spd.d.ts +5 -0
  97. package/src/shade/renderer/hiz/shader_hzb_spd.d.ts.map +1 -0
  98. package/src/shade/renderer/hiz/shader_hzb_spd.js +160 -0
  99. package/src/shade/renderer/light/GPULightCollection.d.ts +8 -0
  100. package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
  101. package/src/shade/renderer/light/GPULightCollection.js +67 -0
  102. package/src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.d.ts +7 -0
  103. package/src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.d.ts.map +1 -0
  104. package/src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.js +13 -0
  105. package/src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.d.ts +10 -0
  106. package/src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.d.ts.map +1 -0
  107. package/src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.js +72 -0
  108. package/src/shade/renderer/light/world_cluster/WORLD_LIGHT_CLUSTER.d.ts +39 -0
  109. package/src/shade/renderer/light/world_cluster/WORLD_LIGHT_CLUSTER.d.ts.map +1 -0
  110. package/src/shade/renderer/light/world_cluster/WORLD_LIGHT_CLUSTER.js +90 -0
  111. package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.d.ts +12 -0
  112. package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.d.ts.map +1 -0
  113. package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.js +56 -0
  114. package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.d.ts +31 -0
  115. package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.d.ts.map +1 -0
  116. package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.js +196 -0
  117. package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.d.ts +10 -0
  118. package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.d.ts.map +1 -0
  119. package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.js +163 -0
  120. package/src/shade/renderer/light/world_cluster/shader_world_cluster_cull_lights.d.ts +4 -0
  121. package/src/shade/renderer/light/world_cluster/shader_world_cluster_cull_lights.d.ts.map +1 -0
  122. package/src/shade/renderer/light/world_cluster/shader_world_cluster_cull_lights.js +137 -0
  123. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  124. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  125. package/src/shade/renderer/particles/GPUParticleSystem.js +4 -3
  126. package/src/shade/renderer/particles/graph_particles_avboit.d.ts +4 -3
  127. package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
  128. package/src/shade/renderer/particles/graph_particles_avboit.js +28 -11
  129. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +9 -13
  130. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts.map +1 -1
  131. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +25 -20
  132. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
  133. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +21 -38
  134. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  135. package/src/shade/renderer/shader/chunk/depth/chunk_query_depth_from_screen_space_bb.d.ts.map +1 -1
  136. package/src/shade/renderer/shader/chunk/depth/chunk_query_depth_from_screen_space_bb.js +62 -62
  137. package/src/shade/renderer/shader/chunk/random/lowbias/chunk_hash_lowbias32_vec2u.d.ts +6 -0
  138. package/src/shade/renderer/shader/chunk/random/lowbias/chunk_hash_lowbias32_vec2u.d.ts.map +1 -0
  139. package/src/shade/renderer/shader/chunk/random/lowbias/chunk_hash_lowbias32_vec2u.js +19 -0
  140. package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_get_mip_resolution.d.ts.map +1 -1
  141. package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_get_mip_resolution.js +16 -10
  142. package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_hierarchical_raymarch.d.ts.map +1 -1
  143. package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_hierarchical_raymarch.js +118 -117
  144. package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts +41 -7
  145. package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts.map +1 -1
  146. package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.js +162 -58
  147. package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.js +1 -1
  148. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +10 -12
  149. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  150. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +583 -606
  151. package/src/shade/renderer/volumetrics/chunk_volumetrics_froxel_sample.d.ts +24 -0
  152. package/src/shade/renderer/volumetrics/chunk_volumetrics_froxel_sample.d.ts.map +1 -0
  153. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi_sample.d.ts.map +1 -1
  154. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +1 -1
  155. package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +640 -640
  156. package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts +113 -0
  157. package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts.map +1 -0
  158. package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.js +484 -0
  159. package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.d.ts +50 -0
  160. package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.d.ts.map +1 -0
  161. package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.js +60 -0
  162. package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP_STRUCT.d.ts +25 -0
  163. package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP_STRUCT.d.ts.map +1 -0
  164. package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP_STRUCT.js +47 -0
  165. package/src/shade/renderer/volumetrics/irradiance_clipmap/IrradianceCascadePlacement.d.ts +74 -0
  166. package/src/shade/renderer/volumetrics/irradiance_clipmap/IrradianceCascadePlacement.d.ts.map +1 -0
  167. package/src/shade/renderer/volumetrics/irradiance_clipmap/IrradianceCascadePlacement.js +173 -0
  168. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts +26 -0
  169. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts.map +1 -0
  170. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.js +83 -0
  171. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_local_light.d.ts +31 -0
  172. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_local_light.d.ts.map +1 -0
  173. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_local_light.js +113 -0
  174. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_sample.d.ts +121 -0
  175. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_sample.d.ts.map +1 -0
  176. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_sample.js +356 -0
  177. package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.d.ts +16 -0
  178. package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.d.ts.map +1 -0
  179. package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.js +191 -0
  180. package/src/shade/renderer/volumetrics/shader_volumetrics_classify_froxels.d.ts +16 -0
  181. package/src/shade/renderer/volumetrics/shader_volumetrics_classify_froxels.d.ts.map +1 -0
  182. package/src/shade/renderer/volumetrics/shader_volumetrics_lighting_regimes.d.ts +23 -0
  183. package/src/shade/renderer/volumetrics/shader_volumetrics_lighting_regimes.d.ts.map +1 -0
  184. package/src/shade/renderer/wind/GPUSceneWind.d.ts +1 -1
  185. package/src/shade/renderer/wind/GPUSceneWind.js +1 -1
  186. package/src/engine/graphics3/decal/DecalAtlasFill.js +0 -32
  187. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_froxel_centre_ws.js +0 -49
  188. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.js +0 -50
  189. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi_sample.js +0 -105
  190. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.js +0 -80
  191. package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi.js +0 -51
  192. package/src/shade/renderer/volumetrics/gi/volumetrics_gi_resources.js +0 -39
  193. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.js +0 -121
  194. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.js +0 -237
@@ -0,0 +1,113 @@
1
+ /**
2
+ * World-space irradiance clipmap (`GPUIrradianceClipmap`):
3
+ *
4
+ * Replaces the camera-frustum froxel irradiance volume with nested world-space clipmap cascades
5
+ * stored in a multi-texture {@link GPUTileAtlas3D} (`Y` in texture 0, `CoCg` in texture 1).
6
+ *
7
+ * - **Defaults (Decision 6.3):** 6 cascades (`c = 0..5`) of `32 × 32 × 32` content cells (plus a
8
+ * 1-texel trilinear skirt -> `34³` texels per tile), with finest voxel size `h0 = 0.25 m`
9
+ * (covering `8 m, 16 m, 32 m, 64 m, 128 m, 256 m`).
10
+ * - **Amortized Updates & Warp Detection (Decision 3.2):** Cascade `0` and the dyadic ruler cascade
11
+ * `fluid_cascade_ruler(tick, count)` update every frame. In addition, whenever a cascade's window
12
+ * shifts by 1 voxel (`placement.moved(c)`), an immediate update is forced on that cascade so the
13
+ * linear atlas tile never holds stale pre-shift texels.
14
+ */
15
+ export class GPUIrradianceClipmap {
16
+ /**
17
+ * @param {GPUDevice} device
18
+ * @param {Object} [options]
19
+ * @param {number} [options.cascade_count=IRRADIANCE_CLIPMAP_DEFAULT_CASCADE_COUNT]
20
+ * @param {number|ArrayLike<number>} [options.resolution=IRRADIANCE_CLIPMAP_DEFAULT_RESOLUTION]
21
+ * @param {number} [options.cell_size=IRRADIANCE_CLIPMAP_DEFAULT_CELL_SIZE]
22
+ * @param {number} [options.blend_skirt=IRRADIANCE_CLIPMAP_DEFAULT_BLEND_SKIRT]
23
+ */
24
+ constructor(device: GPUDevice, { cascade_count, resolution, cell_size, blend_skirt, }?: {
25
+ cascade_count?: number;
26
+ resolution?: number | ArrayLike<number>;
27
+ cell_size?: number;
28
+ blend_skirt?: number;
29
+ });
30
+ /**
31
+ * @returns {GPUTileAtlas3D}
32
+ */
33
+ get atlas(): GPUTileAtlas3D;
34
+ /**
35
+ * @returns {GPUTextureContext}
36
+ */
37
+ get texture_y(): GPUTextureContext;
38
+ /**
39
+ * @returns {GPUTextureContext}
40
+ */
41
+ get texture_cocg(): GPUTextureContext;
42
+ /**
43
+ * @returns {GPUBuffer}
44
+ */
45
+ get uniform(): GPUBuffer;
46
+ /**
47
+ * @returns {number}
48
+ */
49
+ get cascade_count(): number;
50
+ /**
51
+ * Number of voxels at each cascade window's outer faces where blending takes place.
52
+ * @returns {number}
53
+ */
54
+ get blend_skirt(): number;
55
+ /**
56
+ * @returns {IrradianceCascadePlacement}
57
+ */
58
+ get placement(): IrradianceCascadePlacement;
59
+ /**
60
+ * Forces all cascades to rebuild on the next executed frame.
61
+ */
62
+ invalidate_all(): void;
63
+ /**
64
+ * Updates cascade window placements around `anchor` (`[x, y, z]` in world metres), detects
65
+ * warp events (`placement.moved(c)`), schedules cascade updates, and uploads the uniform table.
66
+ *
67
+ * @param {number} x
68
+ * @param {number} y
69
+ * @param {number} z
70
+ * @param {ShaderSwitchSet} [shader_switches]
71
+ */
72
+ update_placement(x: number, y: number, z: number, shader_switches?: ShaderSwitchSet): void;
73
+ /**
74
+ * Records the world-space light cluster clipmap build and the irradiance clipmap cascade update
75
+ * passes into `graph`.
76
+ *
77
+ * Neither pass is marked a side effect, so if nothing in the frame reads `Y` or `CoCg` (e.g. a
78
+ * frame with no volumetrics and no lit particles), the frame graph culls both passes and `#dirty`
79
+ * remains set until a frame actually executes them.
80
+ *
81
+ * @param {Object} options
82
+ * @param {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} options.graph
83
+ * @param {import("../../camera/GPUCameraContext.js").GPUCameraContext} options.camera
84
+ * @param {import("../../scene/GPUSceneContext.js").GPUSceneContext} options.scene_ctx
85
+ * @param {number} options.shadowmap_atlas
86
+ * @param {ShaderSwitchSet} [options.shader_switches]
87
+ * @param {import("../../global_illumination/brick4/Brick4LightMap.js").Brick4LightMap} [options.brick4]
88
+ * @param {import("../../global_illumination/lpv/GPULightProbeVolume.js").GPULightProbeVolume} [options.lpv]
89
+ * @returns {{Y: number, CoCg: number, uniform: number}}
90
+ */
91
+ graph_update({ graph, camera, scene_ctx, shadowmap_atlas, shader_switches, brick4, lpv, }: {
92
+ graph: import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph;
93
+ camera: import("../../camera/GPUCameraContext.js").GPUCameraContext;
94
+ scene_ctx: import("../../scene/GPUSceneContext.js").GPUSceneContext;
95
+ shadowmap_atlas: number;
96
+ shader_switches?: ShaderSwitchSet;
97
+ brick4?: import("../../global_illumination/brick4/Brick4LightMap.js").Brick4LightMap;
98
+ lpv?: import("../../global_illumination/lpv/GPULightProbeVolume.js").GPULightProbeVolume;
99
+ }): {
100
+ Y: number;
101
+ CoCg: number;
102
+ uniform: number;
103
+ };
104
+ /**
105
+ * Releases GPU resources owned by the clipmap. Safe to call twice.
106
+ */
107
+ destroy(): void;
108
+ #private;
109
+ }
110
+ import { GPUTileAtlas3D } from "../../texture/atlas/GPUTileAtlas3D.js";
111
+ import { IrradianceCascadePlacement } from "./IrradianceCascadePlacement.js";
112
+ import { ShaderSwitchSet } from "../../shader/compiler/ShaderSwitchSet.js";
113
+ //# sourceMappingURL=GPUIrradianceClipmap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GPUIrradianceClipmap.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.js"],"names":[],"mappings":"AA6CA;;;;;;;;;;;;;GAaG;AACH;IA2CI;;;;;;;OAOG;IACH;QAL4B,aAAa,GAA9B,MAAM;QAC6B,UAAU,GAA7C,MAAM,GAAC,UAAU,MAAM,CAAC;QACP,SAAS,GAA1B,MAAM;QACW,WAAW,GAA5B,MAAM;OA8DhB;IAED;;OAEG;IACH,4BAEC;IAED;;OAEG;IACH,mCAEC;IAED;;OAEG;IACH,sCAEC;IAED;;OAEG;IACH,yBAEC;IAED;;OAEG;IACH,4BAEC;IAED;;;OAGG;IACH,0BAEC;IAED;;OAEG;IACH,4CAEC;IAED;;OAEG;IACH,uBAEC;IAED;;;;;;;;OAQG;IACH,oBALW,MAAM,KACN,MAAM,KACN,MAAM,oBACN,eAAe,QAgFzB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH;QATsG,KAAK,EAAhG,OAAO,8DAA8D,EAAE,UAAU;QACZ,MAAM,EAA3E,OAAO,kCAAkC,EAAE,gBAAgB;QACO,SAAS,EAA3E,OAAO,gCAAgC,EAAE,eAAe;QACxC,eAAe,EAA/B,MAAM;QACoB,eAAe,GAAzC,eAAe;QACuE,MAAM,GAA5F,OAAO,oDAAoD,EAAE,cAAc;QACkB,GAAG,GAAhG,OAAO,sDAAsD,EAAE,mBAAmB;QAChF;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAuItD;IAED;;OAEG;IACH,gBAQC;;CACJ;+BAzd8B,uCAAuC;2CAe3B,iCAAiC;gCApB5C,0CAA0C"}
@@ -0,0 +1,484 @@
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { fluid_cascade_ruler } from "../../fluid/fluid_cascade_ruler.js";
3
+ import { INDIRECT_LIGHTING } from "../../INDIRECT_LIGHTING.js";
4
+ import { graph_build_world_light_clusters } from "../../light/world_cluster/graph_build_world_light_clusters.js";
5
+ import { CLIPMAP_LEVEL_STRUCT } from "../../shader/chunk/clipmap/CLIPMAP_LEVEL_STRUCT.js";
6
+ import { ShaderSwitchSet } from "../../shader/compiler/ShaderSwitchSet.js";
7
+ import { graph_import_buffer } from "../../shader/graph/graph_import_buffer.js";
8
+ import { graph_import_texture } from "../../shader/graph/graph_import_texture.js";
9
+ import { encoder_prepare_shader_bindings_defaults } from "../../shader/resource/encoder_prepare_shader_bindings_defaults.js";
10
+ import { SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR } from "../../shadow/map/SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR.js";
11
+ import { GPUTileAtlas3D } from "../../texture/atlas/GPUTileAtlas3D.js";
12
+ import { DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR } from "../../texture/DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR.js";
13
+ import {
14
+ IRRADIANCE_CLIPMAP_CASCADE_LIMIT,
15
+ IRRADIANCE_CLIPMAP_DEFAULT_BLEND_SKIRT,
16
+ IRRADIANCE_CLIPMAP_DEFAULT_CASCADE_COUNT,
17
+ IRRADIANCE_CLIPMAP_DEFAULT_CELL_SIZE,
18
+ IRRADIANCE_CLIPMAP_DEFAULT_RESOLUTION,
19
+ IRRADIANCE_CLIPMAP_TILE_BORDER,
20
+ IRRADIANCE_CLIPMAP_TILE_FORMAT,
21
+ } from "./IRRADIANCE_CLIPMAP.js";
22
+ import {
23
+ IRRADIANCE_CASCADE_STRUCT,
24
+ IRRADIANCE_CLIPMAP_STRUCT,
25
+ } from "./IRRADIANCE_CLIPMAP_STRUCT.js";
26
+ import { IrradianceCascadePlacement } from "./IrradianceCascadePlacement.js";
27
+ import {
28
+ IRRADIANCE_CLIPMAP_BUILD_STRUCT,
29
+ shader_irradiance_clipmap_build,
30
+ } from "./shader_irradiance_clipmap_build.js";
31
+
32
+ // Word offsets in IRRADIANCE_CLIPMAP_STRUCT
33
+ const LEVELS = IRRADIANCE_CLIPMAP_STRUCT.get("levels").offset >>> 2;
34
+ const LEVEL_STRIDE = CLIPMAP_LEVEL_STRUCT.aligned_size >>> 2;
35
+ const LEVEL_CORNER = CLIPMAP_LEVEL_STRUCT.get("corner").offset >>> 2;
36
+ const LEVEL_CELL_SIZE = CLIPMAP_LEVEL_STRUCT.get("cell_size").offset >>> 2;
37
+ const LEVEL_SIZE = CLIPMAP_LEVEL_STRUCT.get("size").offset >>> 2;
38
+ const CASCADES = IRRADIANCE_CLIPMAP_STRUCT.get("cascades").offset >>> 2;
39
+ const CASCADE_STRIDE = IRRADIANCE_CASCADE_STRUCT.aligned_size >>> 2;
40
+ const CASCADE_CONTENT_ORIGIN = IRRADIANCE_CASCADE_STRUCT.get("content_origin").offset >>> 2;
41
+ const INVERSE_ATLAS_SIZE = IRRADIANCE_CLIPMAP_STRUCT.get("inverse_atlas_size").offset >>> 2;
42
+ const CASCADE_COUNT = IRRADIANCE_CLIPMAP_STRUCT.get("cascade_count").offset >>> 2;
43
+ const ANCHOR = IRRADIANCE_CLIPMAP_STRUCT.get("anchor").offset >>> 2;
44
+ const BLEND_SKIRT = IRRADIANCE_CLIPMAP_STRUCT.get("blend_skirt").offset >>> 2;
45
+
46
+ /**
47
+ * World-space irradiance clipmap (`GPUIrradianceClipmap`):
48
+ *
49
+ * Replaces the camera-frustum froxel irradiance volume with nested world-space clipmap cascades
50
+ * stored in a multi-texture {@link GPUTileAtlas3D} (`Y` in texture 0, `CoCg` in texture 1).
51
+ *
52
+ * - **Defaults (Decision 6.3):** 6 cascades (`c = 0..5`) of `32 × 32 × 32` content cells (plus a
53
+ * 1-texel trilinear skirt -> `34³` texels per tile), with finest voxel size `h0 = 0.25 m`
54
+ * (covering `8 m, 16 m, 32 m, 64 m, 128 m, 256 m`).
55
+ * - **Amortized Updates & Warp Detection (Decision 3.2):** Cascade `0` and the dyadic ruler cascade
56
+ * `fluid_cascade_ruler(tick, count)` update every frame. In addition, whenever a cascade's window
57
+ * shifts by 1 voxel (`placement.moved(c)`), an immediate update is forced on that cascade so the
58
+ * linear atlas tile never holds stale pre-shift texels.
59
+ */
60
+ export class GPUIrradianceClipmap {
61
+ /** @type {GPUDevice} */
62
+ #device;
63
+
64
+ /** @type {GPUTileAtlas3D} */
65
+ #atlas;
66
+
67
+ /** @type {IrradianceCascadePlacement} */
68
+ #placement;
69
+
70
+ /** @type {GPUBuffer} */
71
+ #uniform;
72
+
73
+ /** @type {ArrayBuffer} */
74
+ #bytes = new ArrayBuffer(IRRADIANCE_CLIPMAP_STRUCT.size);
75
+ #f32 = new Float32Array(this.#bytes);
76
+ #i32 = new Int32Array(this.#bytes);
77
+ #u32 = new Uint32Array(this.#bytes);
78
+
79
+ /** @type {Uint32Array} */
80
+ #slots = new Uint32Array(IRRADIANCE_CLIPMAP_CASCADE_LIMIT);
81
+
82
+ /** @type {Uint8Array} */
83
+ #dirty = new Uint8Array(IRRADIANCE_CLIPMAP_CASCADE_LIMIT);
84
+
85
+ /** @type {Object[]} */
86
+ #build_records = [];
87
+
88
+ /** @type {number[]} */
89
+ #origin = [0, 0, 0];
90
+
91
+ /** @type {number} */
92
+ #tick = 0;
93
+
94
+ /** @type {number} */
95
+ #blend_skirt;
96
+
97
+ /** @type {number} */
98
+ #last_indirect_mode = -1;
99
+
100
+ /** @type {boolean} */
101
+ #destroyed = false;
102
+
103
+ /**
104
+ * @param {GPUDevice} device
105
+ * @param {Object} [options]
106
+ * @param {number} [options.cascade_count=IRRADIANCE_CLIPMAP_DEFAULT_CASCADE_COUNT]
107
+ * @param {number|ArrayLike<number>} [options.resolution=IRRADIANCE_CLIPMAP_DEFAULT_RESOLUTION]
108
+ * @param {number} [options.cell_size=IRRADIANCE_CLIPMAP_DEFAULT_CELL_SIZE]
109
+ * @param {number} [options.blend_skirt=IRRADIANCE_CLIPMAP_DEFAULT_BLEND_SKIRT]
110
+ */
111
+ constructor(device, {
112
+ cascade_count = IRRADIANCE_CLIPMAP_DEFAULT_CASCADE_COUNT,
113
+ resolution = IRRADIANCE_CLIPMAP_DEFAULT_RESOLUTION,
114
+ cell_size = IRRADIANCE_CLIPMAP_DEFAULT_CELL_SIZE,
115
+ blend_skirt = IRRADIANCE_CLIPMAP_DEFAULT_BLEND_SKIRT,
116
+ } = {}) {
117
+ assert.defined(device, "device");
118
+ assert.isPositiveInteger(cascade_count, "cascade_count");
119
+ assert.lessThanOrEqual(cascade_count, IRRADIANCE_CLIPMAP_CASCADE_LIMIT, "cascade_count");
120
+ assert.isNumber(blend_skirt, "blend_skirt");
121
+ assert.greaterThan(blend_skirt, 0, "blend_skirt");
122
+
123
+ const res = typeof resolution === "number"
124
+ ? [resolution, resolution, resolution]
125
+ : [resolution[0], resolution[1], resolution[2]];
126
+
127
+ this.#device = device;
128
+ this.#blend_skirt = blend_skirt;
129
+ this.#placement = new IrradianceCascadePlacement({
130
+ cascade_count,
131
+ resolution: res,
132
+ cell_size,
133
+ });
134
+
135
+ const tile_z = res[2] + 2 * IRRADIANCE_CLIPMAP_TILE_BORDER;
136
+
137
+ this.#atlas = new GPUTileAtlas3D({
138
+ device,
139
+ formats: [IRRADIANCE_CLIPMAP_TILE_FORMAT, IRRADIANCE_CLIPMAP_TILE_FORMAT],
140
+ content_size: res,
141
+ border: IRRADIANCE_CLIPMAP_TILE_BORDER,
142
+ slots_x: 1,
143
+ slots_y: 1,
144
+ capacity: Math.max(1, Math.min(cascade_count, Math.floor(device.limits.maxTextureDimension3D / tile_z))),
145
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING,
146
+ label: "GPUIrradianceClipmap/atlas",
147
+ });
148
+
149
+ for (let c = 0; c < cascade_count; c++) {
150
+ this.#slots[c] = this.#atlas.allocate();
151
+ this.#dirty[c] = 1;
152
+ this.#build_records.push({
153
+ tile_origin: [0, 0, 0],
154
+ cascade_index: c,
155
+ corner: [0, 0, 0],
156
+ cell_size: this.#placement.cell_size(c),
157
+ tile_size: [
158
+ this.#atlas.tile_size[0],
159
+ this.#atlas.tile_size[1],
160
+ this.#atlas.tile_size[2],
161
+ ],
162
+ border: IRRADIANCE_CLIPMAP_TILE_BORDER,
163
+ });
164
+ }
165
+
166
+ this.#uniform = device.createBuffer({
167
+ label: "GPUIrradianceClipmap/table",
168
+ size: IRRADIANCE_CLIPMAP_STRUCT.size,
169
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
170
+ });
171
+ }
172
+
173
+ /**
174
+ * @returns {GPUTileAtlas3D}
175
+ */
176
+ get atlas() {
177
+ return this.#atlas;
178
+ }
179
+
180
+ /**
181
+ * @returns {GPUTextureContext}
182
+ */
183
+ get texture_y() {
184
+ return this.#atlas.texture_at(0);
185
+ }
186
+
187
+ /**
188
+ * @returns {GPUTextureContext}
189
+ */
190
+ get texture_cocg() {
191
+ return this.#atlas.texture_at(1);
192
+ }
193
+
194
+ /**
195
+ * @returns {GPUBuffer}
196
+ */
197
+ get uniform() {
198
+ return this.#uniform;
199
+ }
200
+
201
+ /**
202
+ * @returns {number}
203
+ */
204
+ get cascade_count() {
205
+ return this.#placement.cascade_count;
206
+ }
207
+
208
+ /**
209
+ * Number of voxels at each cascade window's outer faces where blending takes place.
210
+ * @returns {number}
211
+ */
212
+ get blend_skirt() {
213
+ return this.#blend_skirt;
214
+ }
215
+
216
+ /**
217
+ * @returns {IrradianceCascadePlacement}
218
+ */
219
+ get placement() {
220
+ return this.#placement;
221
+ }
222
+
223
+ /**
224
+ * Forces all cascades to rebuild on the next executed frame.
225
+ */
226
+ invalidate_all() {
227
+ this.#dirty.fill(1, 0, this.#placement.cascade_count);
228
+ }
229
+
230
+ /**
231
+ * Updates cascade window placements around `anchor` (`[x, y, z]` in world metres), detects
232
+ * warp events (`placement.moved(c)`), schedules cascade updates, and uploads the uniform table.
233
+ *
234
+ * @param {number} x
235
+ * @param {number} y
236
+ * @param {number} z
237
+ * @param {ShaderSwitchSet} [shader_switches]
238
+ */
239
+ update_placement(x, y, z, shader_switches = ShaderSwitchSet.EMPTY) {
240
+ assert.notOk(this.#destroyed, "destroyed");
241
+
242
+ const placement = this.#placement;
243
+ const count = placement.cascade_count;
244
+ const res = placement.resolution;
245
+
246
+ const indirect_mode = shader_switches.get(INDIRECT_LIGHTING);
247
+ if (indirect_mode !== this.#last_indirect_mode) {
248
+ this.#last_indirect_mode = indirect_mode;
249
+ this.#dirty.fill(1, 0, count);
250
+ }
251
+
252
+ placement.begin();
253
+ placement.place_all(x, y, z);
254
+
255
+ // Always schedule cascade 0 and the dyadic ruler cascade
256
+ this.#dirty[0] = 1;
257
+ const ruler_cascade = fluid_cascade_ruler(this.#tick, count);
258
+ if (ruler_cascade >= 0) {
259
+ this.#dirty[ruler_cascade] = 1;
260
+ }
261
+
262
+ // Force immediate update on any cascade whose window crossed a hysteretic voxel boundary (warp)
263
+ for (let c = 0; c < count; c++) {
264
+ if (placement.moved(c)) {
265
+ this.#dirty[c] = 1;
266
+ }
267
+ }
268
+
269
+ const atlas = this.#atlas;
270
+ const origin = this.#origin;
271
+ const f32 = this.#f32;
272
+ const i32 = this.#i32;
273
+
274
+ for (let c = 0; c < count; c++) {
275
+ const cx = placement.corner(c, 0);
276
+ const cy = placement.corner(c, 1);
277
+ const cz = placement.corner(c, 2);
278
+ const h = placement.cell_size(c);
279
+
280
+ const level = LEVELS + c * LEVEL_STRIDE;
281
+ i32[level + LEVEL_CORNER] = cx;
282
+ i32[level + LEVEL_CORNER + 1] = cy;
283
+ i32[level + LEVEL_CORNER + 2] = cz;
284
+ f32[level + LEVEL_CELL_SIZE] = h;
285
+ i32[level + LEVEL_SIZE] = res[0];
286
+ i32[level + LEVEL_SIZE + 1] = res[1];
287
+ i32[level + LEVEL_SIZE + 2] = res[2];
288
+
289
+ atlas.slot_origin(this.#slots[c], origin);
290
+
291
+ const cascade = CASCADES + c * CASCADE_STRIDE + CASCADE_CONTENT_ORIGIN;
292
+ f32[cascade] = origin[0] + IRRADIANCE_CLIPMAP_TILE_BORDER;
293
+ f32[cascade + 1] = origin[1] + IRRADIANCE_CLIPMAP_TILE_BORDER;
294
+ f32[cascade + 2] = origin[2] + IRRADIANCE_CLIPMAP_TILE_BORDER;
295
+
296
+ const record = this.#build_records[c];
297
+ record.tile_origin[0] = origin[0];
298
+ record.tile_origin[1] = origin[1];
299
+ record.tile_origin[2] = origin[2];
300
+ record.corner[0] = cx;
301
+ record.corner[1] = cy;
302
+ record.corner[2] = cz;
303
+ record.cell_size = h;
304
+ }
305
+
306
+ const tile = atlas.tile_size;
307
+ f32[INVERSE_ATLAS_SIZE] = 1 / (atlas.slots_x * tile[0]);
308
+ f32[INVERSE_ATLAS_SIZE + 1] = 1 / (atlas.slots_y * tile[1]);
309
+ f32[INVERSE_ATLAS_SIZE + 2] = 1 / (atlas.slots_z * tile[2]);
310
+ this.#u32[CASCADE_COUNT] = count;
311
+ f32[ANCHOR] = x;
312
+ f32[ANCHOR + 1] = y;
313
+ f32[ANCHOR + 2] = z;
314
+ f32[BLEND_SKIRT] = this.#blend_skirt;
315
+
316
+ this.#device.queue.writeBuffer(this.#uniform, 0, this.#bytes);
317
+ }
318
+
319
+ /**
320
+ * Records the world-space light cluster clipmap build and the irradiance clipmap cascade update
321
+ * passes into `graph`.
322
+ *
323
+ * Neither pass is marked a side effect, so if nothing in the frame reads `Y` or `CoCg` (e.g. a
324
+ * frame with no volumetrics and no lit particles), the frame graph culls both passes and `#dirty`
325
+ * remains set until a frame actually executes them.
326
+ *
327
+ * @param {Object} options
328
+ * @param {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} options.graph
329
+ * @param {import("../../camera/GPUCameraContext.js").GPUCameraContext} options.camera
330
+ * @param {import("../../scene/GPUSceneContext.js").GPUSceneContext} options.scene_ctx
331
+ * @param {number} options.shadowmap_atlas
332
+ * @param {ShaderSwitchSet} [options.shader_switches]
333
+ * @param {import("../../global_illumination/brick4/Brick4LightMap.js").Brick4LightMap} [options.brick4]
334
+ * @param {import("../../global_illumination/lpv/GPULightProbeVolume.js").GPULightProbeVolume} [options.lpv]
335
+ * @returns {{Y: number, CoCg: number, uniform: number}}
336
+ */
337
+ graph_update({
338
+ graph,
339
+ camera,
340
+ scene_ctx,
341
+ shadowmap_atlas,
342
+ shader_switches = ShaderSwitchSet.EMPTY,
343
+ brick4,
344
+ lpv,
345
+ }) {
346
+ const transform = camera?.camera?.transform;
347
+ const x = transform !== undefined ? transform.translation_x : 0;
348
+ const y = transform !== undefined ? transform.translation_y : 0;
349
+ const z = transform !== undefined ? transform.translation_z : 0;
350
+
351
+ this.update_placement(x, y, z, shader_switches);
352
+
353
+ const gr_uniform = graph_import_buffer(graph, this.#uniform, "irradiance clipmap table");
354
+ const count = this.#placement.cascade_count;
355
+ const coarsest = count - 1;
356
+ const coarsest_record = this.#build_records[coarsest];
357
+ const coarsest_h = coarsest_record.cell_size;
358
+ const border = IRRADIANCE_CLIPMAP_TILE_BORDER;
359
+ const res = this.#placement.resolution;
360
+
361
+ const coarsest_min = [
362
+ (coarsest_record.corner[0] - border) * coarsest_h,
363
+ (coarsest_record.corner[1] - border) * coarsest_h,
364
+ (coarsest_record.corner[2] - border) * coarsest_h,
365
+ ];
366
+ const coarsest_max = [
367
+ (coarsest_record.corner[0] + res[0] + border) * coarsest_h,
368
+ (coarsest_record.corner[1] + res[1] + border) * coarsest_h,
369
+ (coarsest_record.corner[2] + res[2] + border) * coarsest_h,
370
+ ];
371
+
372
+ const world_clusters = graph_build_world_light_clusters({
373
+ graph,
374
+ lights: scene_ctx.lights,
375
+ irradiance_clipmap_uniform: gr_uniform,
376
+ cascade_count: count,
377
+ coarsest_min,
378
+ coarsest_max,
379
+ });
380
+
381
+ const gr_atlas_y = graph_import_texture(graph, this.texture_y, "irradiance clipmap Y");
382
+ const gr_atlas_cocg = graph_import_texture(graph, this.texture_cocg, "irradiance clipmap CoCg");
383
+
384
+ const data = {};
385
+
386
+ const pass = graph.add(shader_irradiance_clipmap_build.descriptor.label, data, (data, resources, context) => {
387
+ if (this.#destroyed) {
388
+ return;
389
+ }
390
+
391
+ const encoder = context.encoder;
392
+ const output_Y = resources.get(data.irradiance_Y);
393
+ const output_CoCg = resources.get(data.irradiance_CoCg);
394
+ const world_cluster_lookup = resources.get(data.world_cluster_lookup);
395
+ const world_cluster_data = resources.get(data.world_cluster_data);
396
+ const shadowmap_view = resources.get(data.shadowmap_atlas).obtainView();
397
+ const sCompareLinear = context.graphics.samplers.obtain(SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR);
398
+
399
+ const tile = this.#atlas.tile_size;
400
+ const count = this.#placement.cascade_count;
401
+ const variant = shader_irradiance_clipmap_build.variant(shader_switches);
402
+
403
+ for (let c = 0; c < count; c++) {
404
+ if (this.#dirty[c] === 0) {
405
+ continue;
406
+ }
407
+
408
+ const bindings = {
409
+ build_settings: encoder.allocateTransientValueBuffer(
410
+ IRRADIANCE_CLIPMAP_BUILD_STRUCT,
411
+ this.#build_records[c],
412
+ GPUBufferUsage.UNIFORM
413
+ ),
414
+ camera: camera.buffer.buffer,
415
+ environment_sh: scene_ctx.lights.environment_sh,
416
+ light_data: scene_ctx.lights.buffer_data,
417
+ world_cluster_lookup,
418
+ world_cluster_data,
419
+ shadowmapAtlas: shadowmap_view,
420
+ sCompareLinear,
421
+ atlas_y: output_Y.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
422
+ atlas_cocg: output_CoCg.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
423
+ };
424
+
425
+ if (brick4 !== undefined) {
426
+ bindings.brick4 = brick4.buffer;
427
+ }
428
+
429
+ if (lpv !== undefined) {
430
+ bindings.lpv_lookup = lpv.buffer_mesh_bvh;
431
+ bindings.lpv_metadata = lpv.buffer_metadata;
432
+ bindings.lpv_mesh = lpv.buffer_mesh;
433
+ bindings.lpv_probes = lpv.buffer_probes;
434
+ }
435
+
436
+ encoder_prepare_shader_bindings_defaults(bindings, context, variant.descriptor.resources);
437
+
438
+ variant.dispatchThreads({
439
+ encoder,
440
+ thread_count_x: tile[0],
441
+ thread_count_y: tile[1],
442
+ thread_count_z: tile[2],
443
+ bindings,
444
+ });
445
+
446
+ this.#dirty[c] = 0;
447
+ }
448
+
449
+ this.#tick++;
450
+ });
451
+
452
+ data.world_cluster_lookup = pass.read(world_clusters.lookup);
453
+ data.world_cluster_data = pass.read(world_clusters.data);
454
+ data.shadowmap_atlas = pass.read(shadowmap_atlas);
455
+ pass.read(gr_atlas_y);
456
+ data.irradiance_Y = pass.write(gr_atlas_y);
457
+ pass.read(gr_atlas_cocg);
458
+ data.irradiance_CoCg = pass.write(gr_atlas_cocg);
459
+
460
+ // Allow the frame graph to cull the clipmap build (and upstream world cluster passes) on
461
+ // frames where neither volumetric fog nor lit particles read `Y` or `CoCg`. `#dirty` stays
462
+ // set until a surviving frame actually executes the pass.
463
+ graph.__pass_nodes[graph.__pass_nodes.length - 1].has_side_effects = false;
464
+
465
+ return {
466
+ Y: data.irradiance_Y,
467
+ CoCg: data.irradiance_CoCg,
468
+ uniform: gr_uniform,
469
+ };
470
+ }
471
+
472
+ /**
473
+ * Releases GPU resources owned by the clipmap. Safe to call twice.
474
+ */
475
+ destroy() {
476
+ if (this.#destroyed) {
477
+ return;
478
+ }
479
+
480
+ this.#destroyed = true;
481
+ this.#atlas.destroy();
482
+ this.#uniform.destroy();
483
+ }
484
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Default number of cascades in the world-space irradiance clipmap (Decision 6.3).
3
+ * Covers 8 m, 16 m, 32 m, 64 m, 128 m, 256 m at 32³ and h0 = 0.25 m.
4
+ * @type {number}
5
+ */
6
+ export const IRRADIANCE_CLIPMAP_DEFAULT_CASCADE_COUNT: number;
7
+ /**
8
+ * Maximum number of cascades supported by the irradiance clipmap table.
9
+ * @type {number}
10
+ */
11
+ export const IRRADIANCE_CLIPMAP_CASCADE_LIMIT: number;
12
+ /**
13
+ * Default resolution (cells per axis) of each irradiance clipmap cascade (Decision 6.3).
14
+ * @type {number}
15
+ */
16
+ export const IRRADIANCE_CLIPMAP_DEFAULT_RESOLUTION: number;
17
+ /**
18
+ * Default finest cascade cell size h0 in metres (25 cm, Decision 6.3).
19
+ * @type {number}
20
+ */
21
+ export const IRRADIANCE_CLIPMAP_DEFAULT_CELL_SIZE: number;
22
+ /**
23
+ * Texels of skirt on each side of a cascade's tile in the 3D atlas: 1 texel for hardware trilinear
24
+ * filtering (`tile_size = resolution + 2`).
25
+ * @type {number}
26
+ */
27
+ export const IRRADIANCE_CLIPMAP_TILE_BORDER: number;
28
+ /**
29
+ * Default blend-skirt width in voxels (cells of that cascade) at the outer faces of each cascade
30
+ * window where blending takes place. At the very outer edge of the border voxel (`edge = 0`), the
31
+ * finer cascade's weight is `0.0` (`edge_weight = 1.0`); `blend_skirt` voxels inward, the finer
32
+ * cascade's weight is `1.0` (`edge_weight = 0.0`).
33
+ * @type {number}
34
+ */
35
+ export const IRRADIANCE_CLIPMAP_DEFAULT_BLEND_SKIRT: number;
36
+ /**
37
+ * Format of the two synchronized 3D atlas textures (`Y` and `CoCg`).
38
+ * @type {GPUTextureFormat}
39
+ */
40
+ export const IRRADIANCE_CLIPMAP_TILE_FORMAT: GPUTextureFormat;
41
+ /**
42
+ * Sampler used for trilinear taps of the irradiance clipmap atlas textures.
43
+ */
44
+ export const IRRADIANCE_CLIPMAP_SAMPLER_DESCRIPTOR: Readonly<import("../../../descriptor/texture/SamplerDescriptor.js").SamplerDescriptor>;
45
+ /**
46
+ * Maximum number of point or spot lights evaluated per voxel in the irradiance clipmap build pass.
47
+ * @type {number}
48
+ */
49
+ export const IRRADIANCE_CLIPMAP_LIGHT_BUDGET: number;
50
+ //# sourceMappingURL=IRRADIANCE_CLIPMAP.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IRRADIANCE_CLIPMAP.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.js"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,uDAFU,MAAM,CAE0C;AAE1D;;;GAGG;AACH,+CAFU,MAAM,CAEoD;AAEpE;;;GAGG;AACH,oDAFU,MAAM,CAEwC;AAExD;;;GAGG;AACH,mDAFU,MAAM,CAEyC;AAEzD;;;;GAIG;AACH,6CAFU,MAAM,CAEgC;AAEhD;;;;;;GAMG;AACH,qDAFU,MAAM,CAEwC;AAExD;;;GAGG;AACH,8DAA4D;AAE5D;;GAEG;AACH,2IAA4E;AAE5E;;;GAGG;AACH,8CAFU,MAAM,CAEkC"}