@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
@@ -1,112 +1,111 @@
1
- import { vec2u, vec4u } from "../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
2
- import { WebGPUStruct } from "../shader/type/WebGPUStruct.js";
3
- import { CodeChunk } from "../shader/compiler/CodeChunk.js";
4
- import { ImageShader } from "../shader/ImageShader.js";
5
- import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
6
- import { ShaderDescriptor } from "../shader/ShaderDescriptor.js";
7
- import { HZB_TEXTURE_FORMAT } from "./HZB_TEXTURE_FORMAT.js";
8
-
9
- /**
10
- * Per-pass, 24 bytes, read-only.
11
- *
12
- * `clip_region` and `output_resolution` were two uniforms, so two buffers per pass. WGSL allows one
13
- * immediate per entry point, so carrying them as immediate data means carrying them together.
14
- *
15
- * @type {WebGPUStruct}
16
- */
17
- const HZB_CLIP_SETTINGS = WebGPUStruct.from({
18
- // x, y, width, height
19
- clip_region: vec4u,
20
- output_resolution: vec2u,
21
- }, 'HzbClipSettings');
22
-
23
- const resources = new ShaderResourceSetDescriptor();
24
-
25
- resources.setImmediate("settings", HZB_CLIP_SETTINGS);
26
-
27
- resources.createGroup()
28
- .addTexture("tInput", "unfilterable-float")
29
- ;
30
-
31
- const body = CodeChunk.from(
32
- //language=WGSL
33
- `
34
- @fragment
35
- fn main(
36
- @builtin(position) coord: vec4<f32>,
37
- @location(0) uv: vec2<f32>,
38
- ) -> @location(0) vec2<f32>{
39
-
40
- // 1. Calculate the UV bounds of the current *output* pixel.
41
- // We use the output resolution to determine how wide one pixel is in UV space.
42
- let output_pixel_size2 = 0.5 / vec2<f32>(settings.output_resolution);
43
- let uv_min = uv - output_pixel_size2;
44
- let uv_max = uv + output_pixel_size2;
45
-
46
- // minor epsilon to avoid float rounding errors
47
- const EPSILON = 1e-6;
48
-
49
- // Nudge the bounds slightly inward to absorb floating-point drift
50
- let safe_uv_min = uv_min + EPSILON;
51
- let safe_uv_max = uv_max - EPSILON;
52
-
53
- // 2. Convert UV bounds to Source Texel coordinates (float).
54
- // We map the 0..1 UVs to the size of the source clip region.
55
- let source_size = vec2<f32>(settings.clip_region.zw);
56
- let texel_min_f = safe_uv_min * source_size;
57
- let texel_max_f = safe_uv_max * source_size;
58
-
59
- // 3. Convert to Integer Loop Bounds.
60
- // Floor the min to find the first pixel.
61
- // Ceil the max to find the exclusive upper bound.
62
- // Example (5px -> 2px):
63
- // Output Px 0 covers UV 0.0-0.5 -> Source 0.0 to 2.5
64
- // Floor(0.0) = 0. Ceil(2.5) = 3. Loop 0, 1, 2. (Pixel 2 is partially covered)
65
- // Output Px 1 covers UV 0.5-1.0 -> Source 2.5 to 5.0
66
- // Floor(2.5) = 2. Ceil(5.0) = 5. Loop 2, 3, 4. (Pixel 2 is partially covered again)
67
- let bound_min = vec2<i32>(floor(texel_min_f));
68
- let bound_max = vec2<i32>(ceil(texel_max_f));
69
-
70
- // 4. Clamp bounds to the clip region size to be safe.
71
- let limit = vec2<i32>(settings.clip_region.zw);
72
-
73
- let start = max(bound_min, vec2<i32>(0)) + vec2<i32>(settings.clip_region.xy);
74
- let end = min(bound_max, limit) + vec2<i32>(settings.clip_region.xy);
75
-
76
- var output = vec2<f32>(1.0, 0.0); // Initialize min/max
77
-
78
- // 5. Loop. Note strict usage of < end (exclusive) and i32 types.
79
- for (var y = start.y; y < end.y; y++) {
80
- for (var x = start.x; x < end.x; x++) {
81
-
82
- // Add the clip region offset (atlas support)
83
- let load_coord = vec2<i32>(x, y);
84
-
85
- let v = textureLoad(tInput, load_coord, 0).r;
86
-
87
- output.x = min(output.x, v);
88
- output.y = max(output.y, v);
89
- }
90
- }
91
-
92
- return output;
93
- }
94
- `, [
95
- ]
96
- )
97
-
98
- /**
99
- * Same as standard first mip reduction, but with a clipping region.
100
- * Primarily used for shadow maps where shadows are atlased into a single texture
101
- * @type {ImageShader}
102
- */
103
- export const shader_hzb_reduce_mip0_clip = ImageShader.from({
104
- descriptor: ShaderDescriptor.from({
105
- label: 'HZB / reduce mip0 with clip',
106
- resources,
107
- body,
108
- }),
109
- targets: [
110
- { format: HZB_TEXTURE_FORMAT }
111
- ]
112
- });
1
+ import { vec2u, vec4u } from "../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
2
+ import { WebGPUStruct } from "../shader/type/WebGPUStruct.js";
3
+ import { CodeChunk } from "../shader/compiler/CodeChunk.js";
4
+ import { ComputeShader } from "../shader/ComputeShader.js";
5
+ import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
6
+ import { HZB_TEXTURE_FORMAT } from "./HZB_TEXTURE_FORMAT.js";
7
+
8
+ /**
9
+ * Per-pass, 24 bytes, read-only.
10
+ *
11
+ * `clip_region` and `output_resolution` were two uniforms, so two buffers per pass. WGSL allows one
12
+ * immediate per entry point, so carrying them as immediate data means carrying them together.
13
+ *
14
+ * @type {WebGPUStruct}
15
+ */
16
+ const HZB_CLIP_SETTINGS = WebGPUStruct.from({
17
+ // x, y, width, height
18
+ clip_region: vec4u,
19
+ output_resolution: vec2u,
20
+ }, 'HzbClipSettings');
21
+
22
+ const resources = new ShaderResourceSetDescriptor();
23
+
24
+ resources.setImmediate("settings", HZB_CLIP_SETTINGS);
25
+
26
+ resources.createGroup()
27
+ .addTexture("tInput", "unfilterable-float")
28
+ .addStorageTexture("tOutput", HZB_TEXTURE_FORMAT, "2d", "write-only")
29
+ ;
30
+
31
+ const body = CodeChunk.from(
32
+ //language=WGSL
33
+ `
34
+ @compute @workgroup_size(8, 8, 1)
35
+ fn main(
36
+ @builtin(global_invocation_id) global_id: vec3<u32>,
37
+ ) {
38
+ if (any(global_id.xy >= settings.output_resolution)) {
39
+ return;
40
+ }
41
+
42
+ // 1. Calculate the UV bounds of the current *output* pixel.
43
+ // We use the output resolution to determine how wide one pixel is in UV space.
44
+ let output_resolution_f = vec2<f32>(settings.output_resolution);
45
+ let uv = (vec2<f32>(global_id.xy) + 0.5) / output_resolution_f;
46
+ let output_pixel_size2 = 0.5 / output_resolution_f;
47
+ let uv_min = uv - output_pixel_size2;
48
+ let uv_max = uv + output_pixel_size2;
49
+
50
+ // minor epsilon to avoid float rounding errors
51
+ const EPSILON = 1e-6;
52
+
53
+ // Nudge the bounds slightly inward to absorb floating-point drift
54
+ let safe_uv_min = uv_min + EPSILON;
55
+ let safe_uv_max = uv_max - EPSILON;
56
+
57
+ // 2. Convert UV bounds to Source Texel coordinates (float).
58
+ // We map the 0..1 UVs to the size of the source clip region.
59
+ let source_size = vec2<f32>(settings.clip_region.zw);
60
+ let texel_min_f = safe_uv_min * source_size;
61
+ let texel_max_f = safe_uv_max * source_size;
62
+
63
+ // 3. Convert to Integer Loop Bounds.
64
+ // Floor the min to find the first pixel.
65
+ // Ceil the max to find the exclusive upper bound.
66
+ // Example (5px -> 2px):
67
+ // Output Px 0 covers UV 0.0-0.5 -> Source 0.0 to 2.5
68
+ // Floor(0.0) = 0. Ceil(2.5) = 3. Loop 0, 1, 2. (Pixel 2 is partially covered)
69
+ // Output Px 1 covers UV 0.5-1.0 -> Source 2.5 to 5.0
70
+ // Floor(2.5) = 2. Ceil(5.0) = 5. Loop 2, 3, 4. (Pixel 2 is partially covered again)
71
+ let bound_min = vec2<i32>(floor(texel_min_f));
72
+ let bound_max = vec2<i32>(ceil(texel_max_f));
73
+
74
+ // 4. Clamp bounds to the clip region size to be safe.
75
+ let limit = vec2<i32>(settings.clip_region.zw);
76
+
77
+ let start = max(bound_min, vec2<i32>(0)) + vec2<i32>(settings.clip_region.xy);
78
+ let end = min(bound_max, limit) + vec2<i32>(settings.clip_region.xy);
79
+
80
+ var output = vec2<f32>(1.0, 0.0); // Initialize min/max
81
+
82
+ // 5. Loop. Note strict usage of < end (exclusive) and i32 types.
83
+ for (var y = start.y; y < end.y; y++) {
84
+ for (var x = start.x; x < end.x; x++) {
85
+
86
+ // Add the clip region offset (atlas support)
87
+ let load_coord = vec2<i32>(x, y);
88
+
89
+ let v = textureLoad(tInput, load_coord, 0).r;
90
+
91
+ output.x = min(output.x, v);
92
+ output.y = max(output.y, v);
93
+ }
94
+ }
95
+
96
+ textureStore(tOutput, vec2<i32>(global_id.xy), vec4<f32>(output, 0.0, 0.0));
97
+ }
98
+ `, [
99
+ ]
100
+ )
101
+
102
+ /**
103
+ * Same as standard first mip reduction, but with a clipping region.
104
+ * Primarily used for shadow maps where shadows are atlased into a single texture
105
+ * @type {ComputeShader}
106
+ */
107
+ export const shader_hzb_reduce_mip0_clip = ComputeShader.from({
108
+ label: 'HZB / reduce mip0 with clip',
109
+ resources,
110
+ body,
111
+ });
@@ -0,0 +1,5 @@
1
+ export const shader_hzb_spd_2: ComputeShader;
2
+ export const shader_hzb_spd_3: ComputeShader;
3
+ export const shader_hzb_spd_4: ComputeShader;
4
+ import { ComputeShader } from "../shader/ComputeShader.js";
5
+ //# sourceMappingURL=shader_hzb_spd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_hzb_spd.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/hiz/shader_hzb_spd.js"],"names":[],"mappings":"AA6JA,6CAAyD;AACzD,6CAAyD;AACzD,6CAAyD;8BA3J3B,4BAA4B"}
@@ -0,0 +1,160 @@
1
+ import { assert } from "../../../core/assert.js";
2
+ import { WebGPUExtensionType } from "../../descriptor/WebGPUExtensionType.js";
3
+ import { chunk_remap_for_wave_reduction } from "../shader/chunk/subgroup/chunk_remap_for_wave_reduction.js";
4
+ import { CodeChunk } from "../shader/compiler/CodeChunk.js";
5
+ import { ComputeShader } from "../shader/ComputeShader.js";
6
+ import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
7
+ import { HZB_TEXTURE_FORMAT } from "./HZB_TEXTURE_FORMAT.js";
8
+
9
+ /**
10
+ * Builds an SPD compute shader reducing `tInput` (`base_mip`) into `mip_count` consecutive mips
11
+ * (`tOut1 .. tOut{mip_count}`, where `mip_count` is 2, 3, or 4).
12
+ *
13
+ * Each 256-thread workgroup covers up to 32x32 texels of `tInput` (16x16 at `tOut1`):
14
+ * - `tOut1` (16x16): 256 threads in four 8x8 Morton-ordered sub-tiles each load a 2x2 quad from `tInput`.
15
+ * - `tOut2` (8x8): reduced in registers across 4-lane quads via `quadSwapX` / `quadSwapY` (no barrier).
16
+ * - `tOut3` (4x4): after a single `workgroupBarrier()` over a 64-element LDS tile, 16 threads reduce 2x2 quads.
17
+ * - `tOut4` (2x2): reduced in registers across the 4-lane quads of those 16 threads via `quadSwapX` / `quadSwapY` (no second barrier).
18
+ *
19
+ * @param {number} mip_count 2, 3, or 4
20
+ * @returns {ComputeShader}
21
+ */
22
+ function create_shader_hzb_spd(mip_count) {
23
+ assert.isInteger(mip_count, 'mip_count');
24
+ assert.greaterThanOrEqual(mip_count, 2, 'mip_count');
25
+ assert.lessThanOrEqual(mip_count, 4, 'mip_count');
26
+
27
+ const resources = new ShaderResourceSetDescriptor();
28
+ const group = resources.createGroup()
29
+ .addTexture("tInput", "unfilterable-float");
30
+
31
+ for (let m = 1; m <= mip_count; m++) {
32
+ group.addStorageTexture(`tOut${m}`, HZB_TEXTURE_FORMAT, "2d", "write-only");
33
+ }
34
+
35
+ const needs_lds = mip_count >= 3;
36
+
37
+ const lds_decl = needs_lds
38
+ ? `var<workgroup> hzb_spd_lds: array<vec2<f32>, 64>;`
39
+ : ``;
40
+
41
+ const lds_store_mip2 = needs_lds
42
+ ? `hzb_spd_lds[mip2_local.y * 8u + mip2_local.x] = v2;`
43
+ : ``;
44
+
45
+ const mip3_and_4_code = !needs_lds ? `` : `
46
+ workgroupBarrier();
47
+
48
+ // Map threads 0..15 as four 2x2 quads covering the 4x4 Mip+3 tile so quadSwapX/Y works for Mip+4
49
+ let mip3_local = vec2<u32>(
50
+ (local_idx & 1u) | ((local_idx >> 1u) & 2u),
51
+ ((local_idx >> 1u) & 1u) | ((local_idx >> 2u) & 2u),
52
+ );
53
+
54
+ var v3 = vec2<f32>(1.0, 0.0);
55
+
56
+ if (local_idx < 16u) {
57
+ let lds_base = mip3_local * 2u;
58
+ let l00 = hzb_spd_lds[(lds_base.y + 0u) * 8u + (lds_base.x + 0u)];
59
+ let l10 = hzb_spd_lds[(lds_base.y + 0u) * 8u + (lds_base.x + 1u)];
60
+ let l01 = hzb_spd_lds[(lds_base.y + 1u) * 8u + (lds_base.x + 0u)];
61
+ let l11 = hzb_spd_lds[(lds_base.y + 1u) * 8u + (lds_base.x + 1u)];
62
+
63
+ v3 = vec2<f32>(
64
+ min(min(l00.x, l10.x), min(l01.x, l11.x)),
65
+ max(max(l00.y, l10.y), max(l01.y, l11.y)),
66
+ );
67
+
68
+ let mip3_coord = workgroup_id.xy * 4u + mip3_local;
69
+ let out3_dim = textureDimensions(tOut3);
70
+ if (all(mip3_coord < out3_dim)) {
71
+ textureStore(tOut3, vec2<i32>(mip3_coord), vec4<f32>(v3, 0.0, 0.0));
72
+ }
73
+ }
74
+ ${mip_count === 4 ? `
75
+ // Mip +4: quad reduction in uniform control flow across the 4-lane quads of threads 0..15
76
+ let v4 = hzb_spd_quad_reduce(v3);
77
+
78
+ if (local_idx < 16u && (local_idx & 3u) == 0u) {
79
+ let mip4_local = mip3_local >> vec2<u32>(1u);
80
+ let mip4_coord = workgroup_id.xy * 2u + mip4_local;
81
+ let out4_dim = textureDimensions(tOut4);
82
+ if (all(mip4_coord < out4_dim)) {
83
+ textureStore(tOut4, vec2<i32>(mip4_coord), vec4<f32>(v4, 0.0, 0.0));
84
+ }
85
+ }
86
+ ` : ``}`;
87
+
88
+ const body = CodeChunk.from(
89
+ //language=WGSL
90
+ `
91
+ ${lds_decl}
92
+
93
+ fn hzb_spd_quad_reduce(v: vec2<f32>) -> vec2<f32> {
94
+ let h = vec2<f32>(min(v.x, quadSwapX(v.x)), max(v.y, quadSwapX(v.y)));
95
+ return vec2<f32>(min(h.x, quadSwapY(h.x)), max(h.y, quadSwapY(h.y)));
96
+ }
97
+
98
+ @compute @workgroup_size(256, 1, 1)
99
+ fn main(
100
+ @builtin(workgroup_id) workgroup_id: vec3<u32>,
101
+ @builtin(local_invocation_index) local_idx: u32,
102
+ ) {
103
+ let src_dim = textureDimensions(tInput);
104
+ let src_max = vec2<i32>(src_dim) - vec2<i32>(1);
105
+
106
+ // 4 sub-tiles of 8x8 (64 threads each), Morton-mapped within each sub-tile
107
+ let sub_tile = local_idx >> 6u;
108
+ let sub_offset = vec2<u32>((sub_tile & 1u) * 8u, (sub_tile >> 1u) * 8u);
109
+ let sub_xy = remap_for_wave_reduction(local_idx & 63u);
110
+
111
+ let mip1_local = sub_offset + sub_xy;
112
+ let mip1_coord = workgroup_id.xy * 16u + mip1_local;
113
+
114
+ // Mip +1: 2x2 fetch from tInput
115
+ let src_base = vec2<i32>(mip1_coord * 2u);
116
+ let s00 = textureLoad(tInput, min(src_base + vec2<i32>(0, 0), src_max), 0).xy;
117
+ let s10 = textureLoad(tInput, min(src_base + vec2<i32>(1, 0), src_max), 0).xy;
118
+ let s01 = textureLoad(tInput, min(src_base + vec2<i32>(0, 1), src_max), 0).xy;
119
+ let s11 = textureLoad(tInput, min(src_base + vec2<i32>(1, 1), src_max), 0).xy;
120
+
121
+ let v1 = vec2<f32>(
122
+ min(min(s00.x, s10.x), min(s01.x, s11.x)),
123
+ max(max(s00.y, s10.y), max(s01.y, s11.y)),
124
+ );
125
+
126
+ let out1_dim = textureDimensions(tOut1);
127
+ if (all(mip1_coord < out1_dim)) {
128
+ textureStore(tOut1, vec2<i32>(mip1_coord), vec4<f32>(v1, 0.0, 0.0));
129
+ }
130
+
131
+ // Mip +2: 2x2 quad reduction in registers (0 barriers)
132
+ let v2 = hzb_spd_quad_reduce(v1);
133
+
134
+ if ((local_idx & 3u) == 0u) {
135
+ let mip2_local = mip1_local >> vec2<u32>(1u);
136
+ let mip2_coord = workgroup_id.xy * 8u + mip2_local;
137
+ let out2_dim = textureDimensions(tOut2);
138
+ if (all(mip2_coord < out2_dim)) {
139
+ textureStore(tOut2, vec2<i32>(mip2_coord), vec4<f32>(v2, 0.0, 0.0));
140
+ }
141
+ ${lds_store_mip2}
142
+ }
143
+ ${mip3_and_4_code}
144
+ }
145
+ `,
146
+ [chunk_remap_for_wave_reduction]
147
+ );
148
+
149
+ body.addExtension(WebGPUExtensionType.Subgroups);
150
+
151
+ return ComputeShader.from({
152
+ label: `HZB / SPD ${mip_count}`,
153
+ resources,
154
+ body,
155
+ });
156
+ }
157
+
158
+ export const shader_hzb_spd_2 = create_shader_hzb_spd(2);
159
+ export const shader_hzb_spd_3 = create_shader_hzb_spd(3);
160
+ export const shader_hzb_spd_4 = create_shader_hzb_spd(4);
@@ -57,6 +57,14 @@ export class GPULightCollection {
57
57
  * @returns {GPUBuffer}
58
58
  */
59
59
  get environment_sh(): GPUBuffer;
60
+ /**
61
+ * Cached far-field L1 irradiance SH (`METRO_L1_IRRADIANCE_STRUCT`), combining `environment_sh`
62
+ * (`INDIRECT_LIGHT_INTENSITY`) and directional lights for out-of-cascade particle/volumetric
63
+ * fallback.
64
+ *
65
+ * @returns {GPUBuffer}
66
+ */
67
+ get far_field_irradiance_sh(): GPUBuffer;
60
68
  get gpu_memory_usage(): any;
61
69
  /**
62
70
  *
@@ -1 +1 @@
1
- {"version":3,"file":"GPULightCollection.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/light/GPULightCollection.js"],"names":[],"mappings":"AAkDA;IAEI;;;;;OAKG;IACH,iCAFW,eAAe,QAMzB;IAoJD;;;;;;OAMG;IACH,sBALW,eAAe,aACf,eAAe,EAqCzB;IApLD;;;OAGG;IACH,6DAEC;IAeD;;OAEG;IACH,4BAEC;IAED;;;;;;OAMG;IACH,6BAEC;IAED;;;;;;;OAOG;IACH,qFAEC;IAWD;;OAEG;IACH,+CAEC;IAgDD;;;OAGG;IACH,qCAEC;IAED;;;;;;OAMG;IACH,gCAEC;IAGD,4BAKC;IAyKD;;;OAGG;IACH,YAFW,eAAe,QA8BzB;IAED;;;;;;;;;OASG;IACH,gBAFW,OAAO,+BAA+B,EAAE,YAAY,QAkC9D;IAED;;;;;;OAMG;IACH,uBAHW,sBAAsB,mCAyBhC;IAwED,gBASC;;CACJ;8BA1hBY,OAAO,0CAA0C,EAAE,eAAe;8BAClE,OAAO,uBAAuB,EAAE,eAAe;8BAC/C,OAAO,6BAA6B,EAAE,eAAe;8BACrD,OAAO,sBAAsB,EAAE,eAAe;4BA3B/B,gCAAgC;yCACnB,2CAA2C;kCAClD,iCAAiC;uCAH5B,wCAAwC"}
1
+ {"version":3,"file":"GPULightCollection.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/light/GPULightCollection.js"],"names":[],"mappings":"AAsDA;IAEI;;;;;OAKG;IACH,iCAFW,eAAe,QAOzB;IA6KD;;;;;;OAMG;IACH,sBALW,eAAe,aACf,eAAe,EA2CzB;IAnND;;;OAGG;IACH,6DAEC;IAeD;;OAEG;IACH,4BAEC;IAED;;;;;;OAMG;IACH,6BAEC;IAED;;;;;;;OAOG;IACH,qFAEC;IAWD;;OAEG;IACH,+CAEC;IA6DD;;;OAGG;IACH,qCAEC;IAED;;;;;;OAMG;IACH,gCAEC;IAED;;;;;;OAMG;IACH,yCAEC;IAGD,4BAMC;IAmMD;;;OAGG;IACH,YAFW,eAAe,QAoCzB;IAED;;;;;;;;;OASG;IACH,gBAFW,OAAO,+BAA+B,EAAE,YAAY,QAkC9D;IAED;;;;;;OAMG;IACH,uBAHW,sBAAsB,mCA6BhC;IAwED,gBAUC;;CACJ;8BAzlBY,OAAO,0CAA0C,EAAE,eAAe;8BAClE,OAAO,uBAAuB,EAAE,eAAe;8BAC/C,OAAO,6BAA6B,EAAE,eAAe;8BACrD,OAAO,sBAAsB,EAAE,eAAe;4BA/B/B,gCAAgC;yCACnB,2CAA2C;kCAClD,iCAAiC;uCAH5B,wCAAwC"}
@@ -14,6 +14,10 @@ import {
14
14
  import { SPHERE_PROBE_MIPMAP_LEVELS } from "./environment/DEFINES.js";
15
15
  import { octahedral_skirt_matches } from "./environment/octahedral_skirt_matches.js";
16
16
  import { ENVIRONMENT_SH_TYPE, shader_project_environment_sh } from "./environment/shader_project_environment_sh.js";
17
+ import { shader_project_far_field_irradiance_sh } from "./environment/shader_project_far_field_irradiance_sh.js";
18
+ import {
19
+ METRO_L1_IRRADIANCE_STRUCT
20
+ } from "../shader/chunk/spherical_harmonics/l1i/chunk_convert_to_irradiance_sh.js";
17
21
  import { LIGHT_DATABASE_SPEC } from "./LIGHT_DATABASE_SPEC.js";
18
22
  import { light_record_directional } from "./model/io/light_record_directional.js";
19
23
  import { light_record_point } from "./model/io/light_record_point.js";
@@ -59,6 +63,7 @@ export class GPULightCollection {
59
63
  static enquirePipelines(enquiry) {
60
64
  enquire_filter_environment_map_pipelines(enquiry);
61
65
  enquiry.compute.push(shader_project_environment_sh.pipeline);
66
+ enquiry.compute.push(shader_project_far_field_irradiance_sh.pipeline);
62
67
  enquiry.compute.push(shader_refresh_light_poses.pipeline);
63
68
  }
64
69
 
@@ -180,6 +185,19 @@ export class GPULightCollection {
180
185
  */
181
186
  #environment_sh;
182
187
 
188
+ /**
189
+ * Cached far-field L1 irradiance SH (`METRO_L1_IRRADIANCE_STRUCT`): `environment_sh` scaled by
190
+ * `INDIRECT_LIGHT_INTENSITY` plus all directional lights, updated only when the environment or
191
+ * directional lights change.
192
+ * @type {GPUBuffer}
193
+ */
194
+ #far_field_irradiance_sh;
195
+
196
+ /**
197
+ * @type {boolean}
198
+ */
199
+ #far_field_sh_dirty = true;
200
+
183
201
 
184
202
  /**
185
203
  *
@@ -200,10 +218,22 @@ export class GPULightCollection {
200
218
  return this.#environment_sh;
201
219
  }
202
220
 
221
+ /**
222
+ * Cached far-field L1 irradiance SH (`METRO_L1_IRRADIANCE_STRUCT`), combining `environment_sh`
223
+ * (`INDIRECT_LIGHT_INTENSITY`) and directional lights for out-of-cascade particle/volumetric
224
+ * fallback.
225
+ *
226
+ * @returns {GPUBuffer}
227
+ */
228
+ get far_field_irradiance_sh() {
229
+ return this.#far_field_irradiance_sh;
230
+ }
231
+
203
232
 
204
233
  get gpu_memory_usage() {
205
234
  return this.#environment.gpu_memory_usage
206
235
  + this.#environment_sh.size
236
+ + this.#far_field_irradiance_sh.size
207
237
  + this.#database.gpu_memory_usage
208
238
  ;
209
239
  }
@@ -241,6 +271,12 @@ export class GPULightCollection {
241
271
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
242
272
  });
243
273
 
274
+ this.#far_field_irradiance_sh = device.createBuffer({
275
+ label: "far-field irradiance SH",
276
+ size: METRO_L1_IRRADIANCE_STRUCT.size,
277
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,
278
+ });
279
+
244
280
  this.#database = new GPUDatabase({
245
281
  device,
246
282
  label: 'Light Collection / Database',
@@ -285,6 +321,7 @@ export class GPULightCollection {
285
321
 
286
322
  // what a black environment projects to; nothing to run the projection over
287
323
  this.#device.queue.writeBuffer(this.#environment_sh, 0, new Float32Array(this.#environment_sh.size / 4));
324
+ this.#far_field_sh_dirty = true;
288
325
 
289
326
  return;
290
327
  }
@@ -372,9 +409,28 @@ export class GPULightCollection {
372
409
  },
373
410
  });
374
411
 
412
+ this.#far_field_sh_dirty = true;
413
+
375
414
  cmd.finish();
376
415
  }
377
416
 
417
+ /**
418
+ * @param {ShadeGPUCommandContext} cmd
419
+ */
420
+ #project_far_field_sh(cmd) {
421
+ shader_project_far_field_irradiance_sh.dispatch({
422
+ encoder: cmd,
423
+ group_count_x: 1,
424
+ bindings: {
425
+ environment_sh: this.#environment_sh,
426
+ light_data: this.#database.buffer,
427
+ far_field_sh: this.#far_field_irradiance_sh,
428
+ },
429
+ });
430
+
431
+ this.#far_field_sh_dirty = false;
432
+ }
433
+
378
434
  /**
379
435
  *
380
436
  * @param {GraphicsContext} ctx
@@ -399,12 +455,18 @@ export class GPULightCollection {
399
455
  }
400
456
 
401
457
  if (this.#committed_version === this.#source.version) {
458
+ if (this.#far_field_sh_dirty) {
459
+ const cmd = ShadeGPUCommandContext.create(ctx, 'GPULightCollection/far_field_sh');
460
+ this.#project_far_field_sh(cmd);
461
+ cmd.finish();
462
+ }
402
463
  return;
403
464
  }
404
465
 
405
466
  const cmd = ShadeGPUCommandContext.create(ctx, 'GPULightCollection/build');
406
467
 
407
468
  this.#build(cmd);
469
+ this.#project_far_field_sh(cmd);
408
470
 
409
471
  cmd.finish();
410
472
  }
@@ -482,6 +544,10 @@ export class GPULightCollection {
482
544
  light_database: database.buffer,
483
545
  },
484
546
  });
547
+
548
+ if (this.#prev_directional_count > 0) {
549
+ this.#project_far_field_sh(cmd_ctx);
550
+ }
485
551
  }
486
552
 
487
553
  /**
@@ -563,5 +629,6 @@ export class GPULightCollection {
563
629
  this.#database.destroy();
564
630
  this.#environment.destroy();
565
631
  this.#environment_sh.destroy();
632
+ this.#far_field_irradiance_sh.destroy();
566
633
  }
567
634
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The cached far-field irradiance SH (environment + directional lights) held on `GPULightCollection`.
3
+ * @type {ShaderResourceDescriptor}
4
+ */
5
+ export const FAR_FIELD_IRRADIANCE_SH_RESOURCE: ShaderResourceDescriptor;
6
+ import { ShaderResourceDescriptor } from "../../shader/resource/ShaderResourceDescriptor.js";
7
+ //# sourceMappingURL=FAR_FIELD_IRRADIANCE_SH_RESOURCE.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FAR_FIELD_IRRADIANCE_SH_RESOURCE.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.js"],"names":[],"mappings":"AAKA;;;GAGG;AACH,+CAFU,wBAAwB,CAKhC;yCATuC,mDAAmD"}
@@ -0,0 +1,13 @@
1
+ import {
2
+ METRO_L1_IRRADIANCE_STRUCT
3
+ } from "../../shader/chunk/spherical_harmonics/l1i/chunk_convert_to_irradiance_sh.js";
4
+ import { ShaderResourceDescriptor } from "../../shader/resource/ShaderResourceDescriptor.js";
5
+
6
+ /**
7
+ * The cached far-field irradiance SH (environment + directional lights) held on `GPULightCollection`.
8
+ * @type {ShaderResourceDescriptor}
9
+ */
10
+ export const FAR_FIELD_IRRADIANCE_SH_RESOURCE = ShaderResourceDescriptor.uniform(
11
+ "far_field_irradiance_sh",
12
+ METRO_L1_IRRADIANCE_STRUCT
13
+ );
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Projects the scene's far-field irradiance (the environment SH scaled by `INDIRECT_LIGHT_INTENSITY`
3
+ * plus unshadowed directional lights) into a single cached {@link METRO_L1_IRRADIANCE_STRUCT} buffer on
4
+ * `GPULightCollection`. Updated only when the environment or directional lights change.
5
+ *
6
+ * @type {ComputeShader}
7
+ */
8
+ export const shader_project_far_field_irradiance_sh: ComputeShader;
9
+ import { ComputeShader } from "../../shader/ComputeShader.js";
10
+ //# sourceMappingURL=shader_project_far_field_irradiance_sh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_project_far_field_irradiance_sh.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.js"],"names":[],"mappings":"AA4DA;;;;;;GAMG;AACH,qDAFU,aAAa,CAMpB;8BA5D2B,+BAA+B"}