@woosh/meep-engine 3.42.0 → 3.43.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 (62) hide show
  1. package/package.json +91 -96
  2. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  3. package/src/shade/playground/vgeo_runtime/README.md +5 -4
  4. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  5. package/src/shade/renderer/Renderer.js +6 -5
  6. package/src/shade/renderer/atmosphere/GPUSky.d.ts +12 -0
  7. package/src/shade/renderer/atmosphere/GPUSky.d.ts.map +1 -1
  8. package/src/shade/renderer/atmosphere/GPUSky.js +162 -147
  9. package/src/shade/renderer/lightmap/bake/shader_lightmap_denoise_sh.d.ts.map +1 -1
  10. package/src/shade/renderer/lightmap/bake/shader_lightmap_denoise_sh.js +10 -3
  11. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  12. package/src/shade/renderer/particles/DESIGN.md +13 -9
  13. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +1 -1
  14. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +1 -1
  15. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  16. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +3 -2
  17. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  18. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +3 -2
  19. package/src/shade/renderer/scene/GPUSceneContext.d.ts +9 -1
  20. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  21. package/src/shade/renderer/scene/GPUSceneContext.js +23 -1
  22. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +4 -1
  23. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  24. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +74 -3
  25. package/src/shade/renderer/volumetrics/NOTES.md +1023 -957
  26. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.d.ts +5 -4
  27. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.d.ts.map +1 -1
  28. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.js +5 -4
  29. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.d.ts +1 -1
  30. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.js +1 -1
  31. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.d.ts +1 -1
  32. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.js +1 -1
  33. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts +41 -0
  34. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts.map +1 -0
  35. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.js +112 -0
  36. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +9 -23
  37. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
  38. package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +18 -126
  39. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.d.ts +22 -0
  40. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.d.ts.map +1 -0
  41. package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.js +228 -0
  42. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  43. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +0 -53
  44. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts +4 -3
  45. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts.map +1 -1
  46. package/src/shade/renderer/water/surface/chunk_water_surface_sample.js +17 -7
  47. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
  48. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +69 -23
  49. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts.map +1 -1
  50. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js +13 -5
  51. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts +29 -8
  52. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts.map +1 -1
  53. package/src/shade/renderer/water/surface/particles/chunk_water_particle.js +155 -30
  54. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts +6 -1
  55. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -1
  56. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +157 -39
  57. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts +91 -21
  58. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts.map +1 -1
  59. package/src/shade/renderer/water/surface/particles/shader_water_particles.js +442 -70
  60. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +11 -3
  61. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  62. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +3 -0
@@ -2,10 +2,11 @@
2
2
  * The froxel irradiance volume: the light a transparent surface standing in a froxel receives, for
3
3
  * surfaces the lighting pass cannot see — the particles. The froxel GI stage (`gi/`) starts it with
4
4
  * whatever the renderer's indirect lighting mode says a point there receives — the environment,
5
- * Brick4, the light probe volume — and `shader_volumetrics_build_lighting` adds, in the same loop
6
- * that lights the fog, every directional, point and spot light, their shadows, and the fog's own
7
- * attenuation toward each light. idTech 8 builds the same thing in the same pass ("Froxels
8
- * Irradiance Volume", Sousa, SIGGRAPH 2025, p.29).
5
+ * Brick4, the light probe volume — and `shader_volumetrics_build_irradiance` adds every directional,
6
+ * point and spot light with its shadow. idTech 8 builds the same volume ("Froxels Irradiance Volume",
7
+ * Sousa, SIGGRAPH 2025, p.29), in the pass that lights its fog; here it has a pass of its own and no
8
+ * fog in it, so a particle is lit as the surfaces beside it are, and the volume costs the same with
9
+ * or without participating media.
9
10
  *
10
11
  * Stored in the Metro Exodus L1 encoding (`l1i/`): luma as SH2 — four coefficients — and chroma as
11
12
  * its constant band only. Two lights of different colours from opposite sides therefore light both
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_volumetrics_irradiance_sh.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.js"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,8CAFU,SAAS,CA+DjB;0BAnGwB,iCAAiC"}
1
+ {"version":3,"file":"chunk_volumetrics_irradiance_sh.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.js"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,8CAFU,SAAS,CA+DjB;0BApGwB,iCAAiC"}
@@ -11,10 +11,11 @@ import { CodeChunk } from "../shader/compiler/CodeChunk.js";
11
11
  * The froxel irradiance volume: the light a transparent surface standing in a froxel receives, for
12
12
  * surfaces the lighting pass cannot see — the particles. The froxel GI stage (`gi/`) starts it with
13
13
  * whatever the renderer's indirect lighting mode says a point there receives — the environment,
14
- * Brick4, the light probe volume — and `shader_volumetrics_build_lighting` adds, in the same loop
15
- * that lights the fog, every directional, point and spot light, their shadows, and the fog's own
16
- * attenuation toward each light. idTech 8 builds the same thing in the same pass ("Froxels
17
- * Irradiance Volume", Sousa, SIGGRAPH 2025, p.29).
14
+ * Brick4, the light probe volume — and `shader_volumetrics_build_irradiance` adds every directional,
15
+ * point and spot light with its shadow. idTech 8 builds the same volume ("Froxels Irradiance Volume",
16
+ * Sousa, SIGGRAPH 2025, p.29), in the pass that lights its fog; here it has a pass of its own and no
17
+ * fog in it, so a particle is lit as the surfaces beside it are, and the volume costs the same with
18
+ * or without participating media.
18
19
  *
19
20
  * Stored in the Metro Exodus L1 encoding (`l1i/`): luma as SH2 — four coefficients — and chroma as
20
21
  * its constant band only. Two lights of different colours from opposite sides therefore light both
@@ -2,7 +2,7 @@
2
2
  * What every froxel GI module shares. A module is one concrete compute shader per indirect lighting
3
3
  * mode (`shader_volumetrics_gi_ibl`, `_brick4`, `_lpv`), one thread per froxel: it asks its mode what
4
4
  * radiance arrives at the froxel, as RGB SH2, and hands the answer to `volumetrics_gi_store`. That
5
- * starts the froxel irradiance volume, and `shader_volumetrics_build_lighting` adds the lights to it.
5
+ * starts the froxel irradiance volume, and `shader_volumetrics_build_irradiance` adds the lights to it.
6
6
  * A new mode is one more module: nothing downstream knows which mode wrote the volume.
7
7
  *
8
8
  * `volumetrics_froxel_centre_ws` (`chunk_volumetrics_froxel_centre_ws`) says where a froxel is, for a
@@ -9,7 +9,7 @@ import { chunk_volumetrics_irradiance_sh } from "../chunk_volumetrics_irradiance
9
9
  * What every froxel GI module shares. A module is one concrete compute shader per indirect lighting
10
10
  * mode (`shader_volumetrics_gi_ibl`, `_brick4`, `_lpv`), one thread per froxel: it asks its mode what
11
11
  * radiance arrives at the froxel, as RGB SH2, and hands the answer to `volumetrics_gi_store`. That
12
- * starts the froxel irradiance volume, and `shader_volumetrics_build_lighting` adds the lights to it.
12
+ * starts the froxel irradiance volume, and `shader_volumetrics_build_irradiance` adds the lights to it.
13
13
  * A new mode is one more module: nothing downstream knows which mode wrote the volume.
14
14
  *
15
15
  * `volumetrics_froxel_centre_ws` (`chunk_volumetrics_froxel_centre_ws`) says where a froxel is, for a
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The froxel GI stage: the renderer's indirect lighting at every froxel, as the froxel irradiance
3
- * volume encodes light, for `shader_volumetrics_build_lighting` to add the lights to. One module per
3
+ * volume encodes light, for `shader_volumetrics_build_irradiance` to add the lights to. One module per
4
4
  * mode (see `chunk_volumetrics_gi`); this picks the one `indirect_lighting_mode` names and binds its
5
5
  * source from the scene.
6
6
  *
@@ -9,7 +9,7 @@ import { VOLUMETRICS_GI_WORKGROUP_RESOLUTION } from "./volumetrics_gi_resources.
9
9
 
10
10
  /**
11
11
  * The froxel GI stage: the renderer's indirect lighting at every froxel, as the froxel irradiance
12
- * volume encodes light, for `shader_volumetrics_build_lighting` to add the lights to. One module per
12
+ * volume encodes light, for `shader_volumetrics_build_irradiance` to add the lights to. One module per
13
13
  * mode (see `chunk_volumetrics_gi`); this picks the one `indirect_lighting_mode` names and binds its
14
14
  * source from the scene.
15
15
  *
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The froxel irradiance volume (`chunk_volumetrics_irradiance_sh`), what lit particles are lit by: the
3
+ * froxel GI stage (`gi/graph_build_froxel_gi`), then every light with its shadow on top of it
4
+ * (`shader_volumetrics_build_irradiance`).
5
+ *
6
+ * Nothing here reads the fog. The volume is the same with or without participating media, and the
7
+ * two passes run only when something reads what they write — the frame graph culls them otherwise,
8
+ * which is the frame with no lit particle in it.
9
+ *
10
+ * @param {Object} options
11
+ * @param {import("../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} options.graph
12
+ * @param {import("../camera/GPUCameraContext.js").GPUCameraContext} options.camera
13
+ * @param {import("../view/GPUViewContext.js").GPUViewContext} options.view
14
+ * @param {import("../light/GPULightCollection.js").GPULightCollection} options.lights
15
+ * @param {number} options.light_cluster_data
16
+ * @param {number} options.light_cluster_lookup
17
+ * @param {number} options.light_cluster_parameters
18
+ * @param {number} options.shadowmap_atlas
19
+ * @param {number} options.volumetrics_metadata where the froxels are
20
+ * @param {number[]} options.resolution the froxel grid
21
+ * @param {import("../ShadeIndirectLightingMode.js").ShadeIndirectLightingMode} options.indirect_lighting_mode which froxel GI
22
+ * module starts the volume
23
+ * @returns {{Y: number, CoCg: number}} handles of the volume: luma SH2, and chroma in `.rg`
24
+ */
25
+ export function graph_build_froxel_irradiance({ graph, camera, view, lights, light_cluster_data, light_cluster_lookup, light_cluster_parameters, shadowmap_atlas, volumetrics_metadata, resolution, indirect_lighting_mode, }: {
26
+ graph: import("../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph;
27
+ camera: import("../camera/GPUCameraContext.js").GPUCameraContext;
28
+ view: import("../view/GPUViewContext.js").GPUViewContext;
29
+ lights: import("../light/GPULightCollection.js").GPULightCollection;
30
+ light_cluster_data: number;
31
+ light_cluster_lookup: number;
32
+ light_cluster_parameters: number;
33
+ shadowmap_atlas: number;
34
+ volumetrics_metadata: number;
35
+ resolution: number[];
36
+ indirect_lighting_mode: import("../ShadeIndirectLightingMode.js").ShadeIndirectLightingMode;
37
+ }): {
38
+ Y: number;
39
+ CoCg: number;
40
+ };
41
+ //# sourceMappingURL=graph_build_froxel_irradiance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph_build_froxel_irradiance.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/volumetrics/graph_build_froxel_irradiance.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH;IAdmG,KAAK,EAA7F,OAAO,2DAA2D,EAAE,UAAU;IACZ,MAAM,EAAxE,OAAO,+BAA+B,EAAE,gBAAgB;IACI,IAAI,EAAhE,OAAO,2BAA2B,EAAE,cAAc;IACmB,MAAM,EAA3E,OAAO,gCAAgC,EAAE,kBAAkB;IAC3C,kBAAkB,EAAlC,MAAM;IACU,oBAAoB,EAApC,MAAM;IACU,wBAAwB,EAAxC,MAAM;IACU,eAAe,EAA/B,MAAM;IACU,oBAAoB,EAApC,MAAM;IACY,UAAU,EAA5B,MAAM,EAAE;IACqE,sBAAsB,EAAnG,OAAO,iCAAiC,EAAE,yBAAyB;IAEjE;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAkFrC"}
@@ -0,0 +1,112 @@
1
+ import { TextureResourceDescriptor } from "../../device/graph/TextureResourceDescriptor.js";
2
+ import { SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR } from "../shadow/map/SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR.js";
3
+ import { STATIC_GRAPHICS_ENGINE_ASSETS } from "../STATIC_GRAPHICS_ENGINE_ASSETS.js";
4
+ import { DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR } from "../texture/DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR.js";
5
+ import { graph_build_froxel_gi } from "./gi/graph_build_froxel_gi.js";
6
+ import { shader_volumetrics_build_irradiance } from "./shader_volumetrics_build_irradiance.js";
7
+
8
+ /**
9
+ * The froxel irradiance volume (`chunk_volumetrics_irradiance_sh`), what lit particles are lit by: the
10
+ * froxel GI stage (`gi/graph_build_froxel_gi`), then every light with its shadow on top of it
11
+ * (`shader_volumetrics_build_irradiance`).
12
+ *
13
+ * Nothing here reads the fog. The volume is the same with or without participating media, and the
14
+ * two passes run only when something reads what they write — the frame graph culls them otherwise,
15
+ * which is the frame with no lit particle in it.
16
+ *
17
+ * @param {Object} options
18
+ * @param {import("../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} options.graph
19
+ * @param {import("../camera/GPUCameraContext.js").GPUCameraContext} options.camera
20
+ * @param {import("../view/GPUViewContext.js").GPUViewContext} options.view
21
+ * @param {import("../light/GPULightCollection.js").GPULightCollection} options.lights
22
+ * @param {number} options.light_cluster_data
23
+ * @param {number} options.light_cluster_lookup
24
+ * @param {number} options.light_cluster_parameters
25
+ * @param {number} options.shadowmap_atlas
26
+ * @param {number} options.volumetrics_metadata where the froxels are
27
+ * @param {number[]} options.resolution the froxel grid
28
+ * @param {import("../ShadeIndirectLightingMode.js").ShadeIndirectLightingMode} options.indirect_lighting_mode which froxel GI
29
+ * module starts the volume
30
+ * @returns {{Y: number, CoCg: number}} handles of the volume: luma SH2, and chroma in `.rg`
31
+ */
32
+ export function graph_build_froxel_irradiance({
33
+ graph,
34
+ camera,
35
+ view,
36
+ lights,
37
+ light_cluster_data,
38
+ light_cluster_lookup,
39
+ light_cluster_parameters,
40
+ shadowmap_atlas,
41
+ volumetrics_metadata,
42
+ resolution,
43
+ indirect_lighting_mode,
44
+ }) {
45
+
46
+ const gi = graph_build_froxel_gi({
47
+ graph,
48
+ indirect_lighting_mode,
49
+ scene_ctx: view.scene,
50
+ camera,
51
+ volumetrics_metadata,
52
+ resolution,
53
+ });
54
+
55
+ const data = {};
56
+
57
+ const pass = graph.add(shader_volumetrics_build_irradiance.descriptor.label, data, (data, resources, context) => {
58
+ const output_Y = resources.get(data.irradiance_Y);
59
+ const output_CoCg = resources.get(data.irradiance_CoCg);
60
+
61
+ // The blue noise the sample is jittered by. Fetched here rather than when the pass is
62
+ // recorded: the engine's assets arrive at startup, and this is when the pass needs them.
63
+ const tSTBN_vec3 = context.graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
64
+
65
+ shader_volumetrics_build_irradiance.dispatchThreads({
66
+ encoder: context.encoder,
67
+ thread_count_x: output_Y.width,
68
+ thread_count_y: output_Y.height,
69
+ thread_count_z: output_Y.depth,
70
+ bindings: {
71
+ volumetrics_metadata: resources.get(data.volumetrics_metadata),
72
+ camera: camera.buffer.buffer,
73
+ view: view.uniform_buffer.buffer,
74
+ tSTBN_vec3: tSTBN_vec3.obtainView(),
75
+ tGIY: resources.get(data.gi_Y).obtainView(),
76
+ tGICoCg: resources.get(data.gi_CoCg).obtainView(),
77
+ tIrradianceY: output_Y.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
78
+ tIrradianceCoCg: output_CoCg.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
79
+
80
+ light_data: lights.buffer_data,
81
+ cluster_parameters: resources.get(data.light_cluster_parameters),
82
+ cluster_lookup: resources.get(data.light_cluster_lookup),
83
+ cluster_data: resources.get(data.light_cluster_data),
84
+ shadowmapAtlas: resources.get(data.shadowmap_atlas).obtainView(),
85
+ sCompareLinear: context.graphics.samplers.obtain(SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR),
86
+ },
87
+ });
88
+ });
89
+
90
+ data.volumetrics_metadata = pass.read(volumetrics_metadata);
91
+ data.gi_Y = pass.read(gi.Y);
92
+ data.gi_CoCg = pass.read(gi.CoCg);
93
+ data.light_cluster_data = pass.read(light_cluster_data);
94
+ data.light_cluster_lookup = pass.read(light_cluster_lookup);
95
+ data.light_cluster_parameters = pass.read(light_cluster_parameters);
96
+ data.shadowmap_atlas = pass.read(shadowmap_atlas);
97
+
98
+ const volume = (label) => pass.create(label, TextureResourceDescriptor.from({
99
+ resolution,
100
+ dimension: "3d",
101
+ format: "rgba16float",
102
+ usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
103
+ }));
104
+
105
+ data.irradiance_Y = volume("Froxel Irradiance Y");
106
+ data.irradiance_CoCg = volume("Froxel Irradiance CoCg");
107
+
108
+ return {
109
+ Y: data.irradiance_Y,
110
+ CoCg: data.irradiance_CoCg,
111
+ };
112
+ }
@@ -1,25 +1,17 @@
1
1
  /**
2
- * Transmittance LUT, then the multiple-scattering LUT that reads it. Exported for
3
- * `graph_integrate_sky.spec.js`, which pins the dispatch shape and the transient's usage
4
- * flags -- neither of which the WGSL validity gate can see.
5
- *
6
- * @param {Object} options
7
- * @param {FrameGraph} options.graph
8
- * @returns {{transmittance_lut: number, multiscatted_lut: number}} resource handles
9
- */
10
- export function graph_integrate_sky({ graph }: {
11
- graph: FrameGraph;
12
- }): {
13
- transmittance_lut: number;
14
- multiscatted_lut: number;
15
- };
16
- /**
2
+ * The fog: participating media -> per-froxel lighting -> ray-marched integration into the aerial LUT
3
+ * every surface behind it is seen through. Particle lighting is not here — it needs no medium, and
4
+ * `graph_build_froxel_irradiance` builds it on its own.
17
5
  *
18
6
  * @param {Object} options
19
7
  * @param {FrameGraph} options.graph
20
8
  * @param {GPUCameraContext} options.camera
21
9
  * @param {GPULightCollection} options.lights
22
10
  * @param {GPUViewContext} options.view
11
+ * @param {GPUSky} options.sky the scene's sky, already {@link GPUSky#update updated}: its two
12
+ * persistent LUTs are imported and read, not rebuilt. The sun's transmittance and the multiple
13
+ * scattering depend on nothing but the atmosphere's constants, so building them again per frame
14
+ * bought the same texels at a cost that was paid whether or not the scene had any fog.
23
15
  * @param {number} options.light_cluster_data
24
16
  * @param {number} options.light_cluster_lookup
25
17
  * @param {number} options.light_cluster_parameters
@@ -29,17 +21,16 @@ export function graph_integrate_sky({ graph }: {
29
21
  * `[1, 1, 1]` when the froxels are marching instead, which keeps the passes in the graph without
30
22
  * doing any work
31
23
  * @param {number} options.volumetrics_metadata
32
- * @param {import("../ShadeIndirectLightingMode.js").ShadeIndirectLightingMode} options.indirect_lighting_mode which froxel GI module starts the
33
- * froxel irradiance volume (`gi/graph_build_froxel_gi`)
34
24
  * @param {number} [options.taa_history] imported previous-frame accumulated scattering volume
35
25
  * @param {number} [options.taa_output] imported destination for this frame's accumulated scattering volume
36
26
  * @param {GPUCameraContext} [options.camera_previous] previous-frame camera, for temporal reprojection
37
27
  */
38
- export function graph_build_volumetrics({ graph, camera, lights, view, light_cluster_data, light_cluster_lookup, light_cluster_parameters, shadowmap_atlas, volumetric_resolution, sun_shadow_resolution, volumetrics_metadata, indirect_lighting_mode, taa_history, taa_output, camera_previous, }: {
28
+ export function graph_build_volumetrics({ graph, camera, lights, view, sky, light_cluster_data, light_cluster_lookup, light_cluster_parameters, shadowmap_atlas, volumetric_resolution, sun_shadow_resolution, volumetrics_metadata, taa_history, taa_output, camera_previous, }: {
39
29
  graph: FrameGraph;
40
30
  camera: GPUCameraContext;
41
31
  lights: GPULightCollection;
42
32
  view: GPUViewContext;
33
+ sky: GPUSky;
43
34
  light_cluster_data: number;
44
35
  light_cluster_lookup: number;
45
36
  light_cluster_parameters: number;
@@ -47,7 +38,6 @@ export function graph_build_volumetrics({ graph, camera, lights, view, light_clu
47
38
  volumetric_resolution: number[];
48
39
  sun_shadow_resolution: number[];
49
40
  volumetrics_metadata: number;
50
- indirect_lighting_mode: import("../ShadeIndirectLightingMode.js").ShadeIndirectLightingMode;
51
41
  taa_history?: number;
52
42
  taa_output?: number;
53
43
  camera_previous?: GPUCameraContext;
@@ -55,10 +45,6 @@ export function graph_build_volumetrics({ graph, camera, lights, view, light_clu
55
45
  lut_transmittance: number;
56
46
  lut_multiple_scattering: number;
57
47
  lut_aerial: any;
58
- irradiance: {
59
- Y: number;
60
- CoCg: number;
61
- };
62
48
  volumetrics_metadata: number;
63
49
  };
64
50
  //# sourceMappingURL=graph_build_volumetrics.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"graph_build_volumetrics.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/volumetrics/graph_build_volumetrics.js"],"names":[],"mappings":"AA0BA;;;;;;;;GAQG;AACH;IAH+B,KAAK;IACvB;IAAC,iBAAiB,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAC,CA8DjE;AAoVD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;IAnB+B,KAAK;IACC,MAAM;IACJ,MAAM;IACV,IAAI;IACZ,kBAAkB,EAAlC,MAAM;IACU,oBAAoB,EAApC,MAAM;IACU,wBAAwB,EAAxC,MAAM;IACU,eAAe,EAA/B,MAAM;IACY,qBAAqB,EAAvC,MAAM,EAAE;IACU,qBAAqB,EAAvC,MAAM,EAAE;IAGQ,oBAAoB,EAApC,MAAM;IACuE,sBAAsB,EAAnG,OAAO,iCAAiC,EAAE,yBAAyB;IAElD,WAAW,GAA5B,MAAM;IACW,UAAU,GAA3B,MAAM;IACqB,eAAe;;;;;;WAjKH,MAAM;cAAQ,MAAM;;;EAyVrE"}
1
+ {"version":3,"file":"graph_build_volumetrics.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/volumetrics/graph_build_volumetrics.js"],"names":[],"mappings":"AA2UA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH;IArB+B,KAAK;IACC,MAAM;IACJ,MAAM;IACV,IAAI;IACZ,GAAG;IAIH,kBAAkB,EAAlC,MAAM;IACU,oBAAoB,EAApC,MAAM;IACU,wBAAwB,EAAxC,MAAM;IACU,eAAe,EAA/B,MAAM;IACY,qBAAqB,EAAvC,MAAM,EAAE;IACU,qBAAqB,EAAvC,MAAM,EAAE;IAGQ,oBAAoB,EAApC,MAAM;IACW,WAAW,GAA5B,MAAM;IACW,UAAU,GAA3B,MAAM;IACqB,eAAe;;;;;;EA+KpD"}
@@ -1,10 +1,9 @@
1
1
  import { assert } from "../../../core/assert.js";
2
2
  import { SamplerDescriptor } from "../../descriptor/texture/SamplerDescriptor.js";
3
3
  import { TextureResourceDescriptor } from "../../device/graph/TextureResourceDescriptor.js";
4
- import { shader_multiscatter_lut } from "../atmosphere/shader_multiscatter_lut.js";
5
- import { shader_transmittance_lut } from "../atmosphere/shader_transmittance_lut.js";
6
4
  import { graph_compute_pass } from "../shader/graph/compute/graph_compute_pass.js";
7
5
  import { graph_import_buffer } from "../shader/graph/graph_import_buffer.js";
6
+ import { graph_import_texture } from "../shader/graph/graph_import_texture.js";
8
7
  import { SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR } from "../shadow/map/SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR.js";
9
8
  import { STATIC_GRAPHICS_ENGINE_ASSETS } from "../STATIC_GRAPHICS_ENGINE_ASSETS.js";
10
9
  import { DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR } from "../texture/DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR.js";
@@ -17,85 +16,12 @@ import {
17
16
  shader_volumetrics_build_sun_shadow_volume_seeded
18
17
  } from "./shader_volumetrics_build_sun_shadow_volume.js";
19
18
  import { shader_volumetrics_taa } from "./taa/shader_volumetrics_taa.js";
20
- import { graph_build_froxel_gi } from "./gi/graph_build_froxel_gi.js";
21
19
  import {
22
20
  VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT,
23
21
  VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION,
24
22
  volumetrics_sun_shadow_sub_steps
25
23
  } from "./VOLUMETRICS_SUN_SHADOW_RESOLUTION.js";
26
24
 
27
- /**
28
- * Transmittance LUT, then the multiple-scattering LUT that reads it. Exported for
29
- * `graph_integrate_sky.spec.js`, which pins the dispatch shape and the transient's usage
30
- * flags -- neither of which the WGSL validity gate can see.
31
- *
32
- * @param {Object} options
33
- * @param {FrameGraph} options.graph
34
- * @returns {{transmittance_lut: number, multiscatted_lut: number}} resource handles
35
- */
36
- export function graph_integrate_sky({ graph }) {
37
-
38
- graph.push_scope("integrate sky");
39
-
40
- const t_data = {};
41
-
42
- const t_pass = graph.add("transmittance", t_data, (data, resources, context) => {
43
-
44
- const output = resources.get(data.output);
45
-
46
- const encoder = context.encoder;
47
-
48
- const settings = {
49
- steps: 40,
50
- // taken off the target being drawn into, so the generator cannot be told a size
51
- // the texture does not have
52
- resolution: [output.width, output.height],
53
- };
54
-
55
- shader_transmittance_lut.draw({
56
- encoder: encoder,
57
- bindings: {
58
- settings
59
- },
60
- colorAttachments: [{
61
- view: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
62
- loadOp: "clear",
63
- storeOp: "store",
64
- }]
65
- })
66
- });
67
-
68
- t_data.output = t_pass.create("transmittance lut", TextureResourceDescriptor.from({
69
- resolution: [256, 64],
70
- format: "rgba16float",
71
- usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
72
- }));
73
-
74
- // The transient does not exist yet at graph-build time, so the dispatch cannot be
75
- // counted off it the way GPUSky does; one local value feeds both instead.
76
- const multiscatter_resolution = [32, 32];
77
-
78
- const multiscatter_outputs = graph_compute_pass({
79
- graph,
80
- shader: shader_multiscatter_lut,
81
- // one workgroup per LUT texel, each thread integrating one direction
82
- group_count: [multiscatter_resolution[0], multiscatter_resolution[1], 1],
83
- bindings: {
84
- tSkyLutTransmittance: t_data.output,
85
- tSkyLutMultiscatterOut: TextureResourceDescriptor.from({
86
- resolution: multiscatter_resolution,
87
- format: "rgba16float",
88
- usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING
89
- })
90
- }
91
- });
92
-
93
- graph.pop_scope();
94
-
95
- return { transmittance_lut: t_data.output, multiscatted_lut: multiscatter_outputs.tSkyLutMultiscatterOut };
96
- }
97
-
98
-
99
25
  /**
100
26
  *
101
27
  * @param {Object} options
@@ -291,9 +217,7 @@ function graph_build_sun_shadow_volume({
291
217
  * @param view
292
218
  * @param camera
293
219
  * @param resolution
294
- * @param {{Y: number, CoCg: number}} gi the froxel GI stage's volume, which the irradiance starts from
295
- * @returns {{scattering: number, irradiance: {Y: number, CoCg: number}}} the lit scattering volume,
296
- * and the froxel irradiance volume: the GI plus the same lights (chunk_volumetrics_irradiance_sh)
220
+ * @returns {number} the lit scattering volume
297
221
  */
298
222
  function graph_integrate_light_scattering({
299
223
  graph,
@@ -311,7 +235,6 @@ function graph_integrate_light_scattering({
311
235
  view,
312
236
  camera,
313
237
  resolution,
314
- gi,
315
238
  }) {
316
239
 
317
240
  const data = {};
@@ -356,10 +279,6 @@ function graph_integrate_light_scattering({
356
279
  tParticipatingMedia0: participating_media0.obtainView(),
357
280
  tParticipatingMedia1: participating_media1.obtainView(),
358
281
  tLighting: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
359
- tGIY: resources.get(data.gi_Y).obtainView(),
360
- tGICoCg: resources.get(data.gi_CoCg).obtainView(),
361
- tIrradianceY: resources.get(data.irradiance_Y).obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
362
- tIrradianceCoCg: resources.get(data.irradiance_CoCg).obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
363
282
  //
364
283
  light_data: lights.buffer_data,
365
284
 
@@ -399,9 +318,6 @@ function graph_integrate_light_scattering({
399
318
  data.sun_multiple_scattering_lut = pass.read(sun_multiple_scattering_lut);
400
319
  data.sun_shadow_cascades = sun_shadow_cascades.map(handle => pass.read(handle));
401
320
 
402
- data.gi_Y = pass.read(gi.Y);
403
- data.gi_CoCg = pass.read(gi.CoCg);
404
-
405
321
  data.output = pass.create("Light Scattering LUT", TextureResourceDescriptor.from({
406
322
  resolution,
407
323
  dimension: "3d",
@@ -409,37 +325,24 @@ function graph_integrate_light_scattering({
409
325
  usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
410
326
  }));
411
327
 
412
- data.irradiance_Y = pass.create("Froxel Irradiance Y", TextureResourceDescriptor.from({
413
- resolution,
414
- dimension: "3d",
415
- format: "rgba16float",
416
- usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
417
- }));
418
-
419
- data.irradiance_CoCg = pass.create("Froxel Irradiance CoCg", TextureResourceDescriptor.from({
420
- resolution,
421
- dimension: "3d",
422
- format: "rgba16float",
423
- usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
424
- }));
425
-
426
- return {
427
- scattering: data.output,
428
- irradiance: {
429
- Y: data.irradiance_Y,
430
- CoCg: data.irradiance_CoCg,
431
- },
432
- };
328
+ return data.output;
433
329
 
434
330
  }
435
331
 
436
332
  /**
333
+ * The fog: participating media -> per-froxel lighting -> ray-marched integration into the aerial LUT
334
+ * every surface behind it is seen through. Particle lighting is not here — it needs no medium, and
335
+ * `graph_build_froxel_irradiance` builds it on its own.
437
336
  *
438
337
  * @param {Object} options
439
338
  * @param {FrameGraph} options.graph
440
339
  * @param {GPUCameraContext} options.camera
441
340
  * @param {GPULightCollection} options.lights
442
341
  * @param {GPUViewContext} options.view
342
+ * @param {GPUSky} options.sky the scene's sky, already {@link GPUSky#update updated}: its two
343
+ * persistent LUTs are imported and read, not rebuilt. The sun's transmittance and the multiple
344
+ * scattering depend on nothing but the atmosphere's constants, so building them again per frame
345
+ * bought the same texels at a cost that was paid whether or not the scene had any fog.
443
346
  * @param {number} options.light_cluster_data
444
347
  * @param {number} options.light_cluster_lookup
445
348
  * @param {number} options.light_cluster_parameters
@@ -449,8 +352,6 @@ function graph_integrate_light_scattering({
449
352
  * `[1, 1, 1]` when the froxels are marching instead, which keeps the passes in the graph without
450
353
  * doing any work
451
354
  * @param {number} options.volumetrics_metadata
452
- * @param {import("../ShadeIndirectLightingMode.js").ShadeIndirectLightingMode} options.indirect_lighting_mode which froxel GI module starts the
453
- * froxel irradiance volume (`gi/graph_build_froxel_gi`)
454
355
  * @param {number} [options.taa_history] imported previous-frame accumulated scattering volume
455
356
  * @param {number} [options.taa_output] imported destination for this frame's accumulated scattering volume
456
357
  * @param {GPUCameraContext} [options.camera_previous] previous-frame camera, for temporal reprojection
@@ -460,6 +361,7 @@ export function graph_build_volumetrics({
460
361
  camera,
461
362
  lights,
462
363
  view,
364
+ sky,
463
365
  light_cluster_data,
464
366
  light_cluster_lookup,
465
367
  light_cluster_parameters,
@@ -467,19 +369,23 @@ export function graph_build_volumetrics({
467
369
  volumetric_resolution,
468
370
  sun_shadow_resolution,
469
371
  volumetrics_metadata,
470
- indirect_lighting_mode,
471
372
  taa_history,
472
373
  taa_output,
473
374
  camera_previous,
474
375
  }) {
475
376
 
476
377
  assert.defined(view, 'view');
378
+ assert.defined(sky, 'sky');
379
+ assert.equal(sky.needs_update, false, 'sky has not been updated, its LUTs hold nothing yet');
477
380
  assert.defined(volumetric_resolution, 'volumetric_resolution');
478
381
  assert.defined(sun_shadow_resolution, 'sun_shadow_resolution');
479
382
 
480
383
  graph.push_scope("build volumetrics");
481
384
 
482
- const { transmittance_lut, multiscatted_lut } = graph_integrate_sky({ graph: graph });
385
+ // Read-only here, so nothing in this graph orders against a write to either; the sky wrote
386
+ // them in commands of its own, submitted before this frame's.
387
+ const transmittance_lut = graph_import_texture(graph, sky.lut_transmittance);
388
+ const multiscatted_lut = graph_import_texture(graph, sky.lut_multiple_scattering);
483
389
 
484
390
  const {
485
391
  participating_media0,
@@ -501,20 +407,7 @@ export function graph_build_volumetrics({
501
407
  resolution: sun_shadow_resolution,
502
408
  });
503
409
 
504
- const gi = graph_build_froxel_gi({
505
- graph,
506
- indirect_lighting_mode,
507
- scene_ctx: view.scene,
508
- camera,
509
- volumetrics_metadata,
510
- resolution: volumetric_resolution,
511
- });
512
-
513
- const {
514
- scattering: light_scattering_lut,
515
- irradiance,
516
- } = graph_integrate_light_scattering({
517
- gi,
410
+ const light_scattering_lut = graph_integrate_light_scattering({
518
411
  graph,
519
412
  resolution: volumetric_resolution,
520
413
  camera,
@@ -634,7 +527,6 @@ export function graph_build_volumetrics({
634
527
  lut_transmittance: transmittance_lut,
635
528
  lut_multiple_scattering: multiscatted_lut,
636
529
  lut_aerial: a_data.output,
637
- irradiance,
638
530
  volumetrics_metadata,
639
531
  };
640
532
  }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Workgroup shape of this pass, `[x, y, z]` in froxels, stated to the `@workgroup_size` below and
3
+ * read back out of it by the dispatch. Flat in z and 64 invocations, for the reasons the fog's
4
+ * lighting pass gives (`VOLUMETRICS_LIGHTING_WORKGROUP_RESOLUTION`): it walks the same light
5
+ * clusters, and those are farthest apart along depth.
6
+ *
7
+ * @type {number[]}
8
+ */
9
+ export const VOLUMETRICS_IRRADIANCE_WORKGROUP_RESOLUTION: number[];
10
+ /**
11
+ * The froxel irradiance volume (`chunk_volumetrics_irradiance_sh`): what a lit particle standing in a
12
+ * froxel is lit by. Starts from the froxel GI stage's volume and adds every directional, point and
13
+ * spot light with its shadow, at a point jittered through the froxel every frame.
14
+ *
15
+ * Its own pass, not a by-product of the fog's lighting pass: particle lighting needs no medium, so it
16
+ * runs whether or not the scene has any fog, and the frame graph culls it when nothing reads it.
17
+ *
18
+ * @type {ComputeShader}
19
+ */
20
+ export const shader_volumetrics_build_irradiance: ComputeShader;
21
+ import { ComputeShader } from "../shader/ComputeShader.js";
22
+ //# sourceMappingURL=shader_volumetrics_build_irradiance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_volumetrics_build_irradiance.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.js"],"names":[],"mappings":"AAqCA;;;;;;;GAOG;AACH,0DAFU,MAAM,EAAE,CAEmD;AAwKrE;;;;;;;;;GASG;AACH,kDAFU,aAAa,CAMpB;8BA3M2B,4BAA4B"}