@woosh/meep-engine 3.34.0 → 3.36.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 (161) hide show
  1. package/package.json +1 -1
  2. package/src/engine/Engine.d.ts +2 -0
  3. package/src/engine/Engine.d.ts.map +1 -1
  4. package/src/engine/Engine.js +5 -1
  5. package/src/engine/input/devices/XRInputDevice.d.ts +63 -0
  6. package/src/engine/input/devices/XRInputDevice.d.ts.map +1 -0
  7. package/src/engine/input/devices/XRInputDevice.js +386 -0
  8. package/src/engine/input/devices/xr/XRInputAction.d.ts +37 -0
  9. package/src/engine/input/devices/xr/XRInputAction.d.ts.map +1 -0
  10. package/src/engine/input/devices/xr/XRInputAction.js +85 -0
  11. package/src/engine/input/devices/xr/XRInputButton.d.ts +28 -0
  12. package/src/engine/input/devices/xr/XRInputButton.d.ts.map +1 -0
  13. package/src/engine/input/devices/xr/XRInputButton.js +43 -0
  14. package/src/engine/input/devices/xr/XRInputCoordinates.d.ts +15 -0
  15. package/src/engine/input/devices/xr/XRInputCoordinates.d.ts.map +1 -0
  16. package/src/engine/input/devices/xr/XRInputCoordinates.js +21 -0
  17. package/src/engine/input/devices/xr/XRInputHandle.d.ts +63 -0
  18. package/src/engine/input/devices/xr/XRInputHandle.d.ts.map +1 -0
  19. package/src/engine/input/devices/xr/XRInputHandle.js +171 -0
  20. package/src/engine/input/devices/xr/XRInputPose.d.ts +23 -0
  21. package/src/engine/input/devices/xr/XRInputPose.d.ts.map +1 -0
  22. package/src/engine/input/devices/xr/XRInputPose.js +36 -0
  23. package/src/engine/input/devices/xr/XRInputTypes.d.ts +76 -0
  24. package/src/engine/input/devices/xr/XRInputTypes.d.ts.map +1 -0
  25. package/src/engine/input/devices/xr/XRInputTypes.js +31 -0
  26. package/src/engine/input/devices/xr/XRInputValueSource.d.ts +11 -0
  27. package/src/engine/input/devices/xr/XRInputValueSource.d.ts.map +1 -0
  28. package/src/engine/input/devices/xr/XRInputValueSource.js +11 -0
  29. package/src/engine/input/ecs/ism/coordinate/InputCoordinateChannel.d.ts +15 -1
  30. package/src/engine/input/ecs/ism/coordinate/InputCoordinateChannel.d.ts.map +1 -1
  31. package/src/engine/input/ecs/ism/coordinate/InputCoordinateChannel.js +9 -0
  32. package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.d.ts +15 -4
  33. package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.d.ts.map +1 -1
  34. package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.js +22 -0
  35. package/src/engine/input/ecs/ism/coordinate/InputCoordinateSwitches.d.ts +17 -2
  36. package/src/engine/input/ecs/ism/coordinate/InputCoordinateSwitches.d.ts.map +1 -1
  37. package/src/engine/input/ecs/ism/device/GamepadInputDeviceAdapter.d.ts +5 -0
  38. package/src/engine/input/ecs/ism/device/GamepadInputDeviceAdapter.d.ts.map +1 -1
  39. package/src/engine/input/ecs/ism/device/InputDeviceAdapter.d.ts +2 -0
  40. package/src/engine/input/ecs/ism/device/InputDeviceAdapter.d.ts.map +1 -1
  41. package/src/engine/input/ecs/ism/device/InputDeviceAdapter.js +2 -0
  42. package/src/engine/input/ecs/ism/device/KeyboardInputDeviceAdapter.d.ts +7 -0
  43. package/src/engine/input/ecs/ism/device/KeyboardInputDeviceAdapter.d.ts.map +1 -1
  44. package/src/engine/input/ecs/ism/device/ManualInputDeviceAdapter.d.ts +5 -0
  45. package/src/engine/input/ecs/ism/device/ManualInputDeviceAdapter.d.ts.map +1 -1
  46. package/src/engine/input/ecs/ism/device/PointerInputDeviceAdapter.d.ts +5 -0
  47. package/src/engine/input/ecs/ism/device/PointerInputDeviceAdapter.d.ts.map +1 -1
  48. package/src/engine/input/ecs/ism/device/XRInputDeviceAdapter.d.ts +16 -0
  49. package/src/engine/input/ecs/ism/device/XRInputDeviceAdapter.d.ts.map +1 -0
  50. package/src/engine/input/ecs/ism/device/XRInputDeviceAdapter.js +54 -0
  51. package/src/engine/input/ecs/ism/device/XR_INPUT_DEVICE_IDS.d.ts +9 -0
  52. package/src/engine/input/ecs/ism/device/XR_INPUT_DEVICE_IDS.d.ts.map +1 -0
  53. package/src/engine/input/ecs/ism/device/XR_INPUT_DEVICE_IDS.js +12 -0
  54. package/src/engine/input/ecs/ism/trigger/InputTrigger.d.ts +11 -1
  55. package/src/engine/input/ecs/ism/trigger/InputTrigger.d.ts.map +1 -1
  56. package/src/engine/input/ecs/ism/trigger/InputTrigger.js +7 -0
  57. package/src/engine/input/ecs/ism/trigger/InputTriggerChord.d.ts +16 -2
  58. package/src/engine/input/ecs/ism/trigger/InputTriggerChord.d.ts.map +1 -1
  59. package/src/engine/input/ecs/ism/trigger/InputTriggerHold.d.ts +22 -2
  60. package/src/engine/input/ecs/ism/trigger/InputTriggerHold.d.ts.map +1 -1
  61. package/src/engine/input/ecs/ism/trigger/InputTriggerRelease.d.ts +16 -2
  62. package/src/engine/input/ecs/ism/trigger/InputTriggerRelease.d.ts.map +1 -1
  63. package/src/engine/input/ecs/ism/trigger/InputTriggerSequence.d.ts +24 -4
  64. package/src/engine/input/ecs/ism/trigger/InputTriggerSequence.d.ts.map +1 -1
  65. package/src/engine/input/ecs/ism/trigger/InputTriggerSwitch.d.ts +6 -8
  66. package/src/engine/input/ecs/ism/trigger/InputTriggerSwitch.d.ts.map +1 -1
  67. package/src/engine/input/ecs/ism/trigger/InputTriggerSwitch.js +5 -0
  68. package/src/engine/input/ecs/ism/trigger/InputTriggerXRButton.d.ts +7 -0
  69. package/src/engine/input/ecs/ism/trigger/InputTriggerXRButton.d.ts.map +1 -0
  70. package/src/engine/input/ecs/ism/trigger/InputTriggerXRButton.js +15 -0
  71. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  72. package/src/shade/device/timing/profile/GPUProfileSession.d.ts +25 -11
  73. package/src/shade/device/timing/profile/GPUProfileSession.d.ts.map +1 -1
  74. package/src/shade/device/timing/profile/GPUProfileSession.js +553 -474
  75. package/src/shade/playground/avboit/main.d.ts.map +1 -1
  76. package/src/shade/playground/avboit/main.js +888 -916
  77. package/src/shade/playground/particle_ecs/README.md +13 -7
  78. package/src/shade/playground/particle_ecs/bonfire_effects.d.ts +5 -5
  79. package/src/shade/playground/particle_ecs/bonfire_effects.js +5 -5
  80. package/src/shade/playground/particle_ecs/effects/smoke.json +1859 -1859
  81. package/src/shade/playground/particle_ecs/effects/soot.json +1605 -1605
  82. package/src/shade/playground/particle_system/README.md +1 -2
  83. package/src/shade/playground/profile_hotkey.d.ts.map +1 -1
  84. package/src/shade/playground/profile_hotkey.js +4 -40
  85. package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -1
  86. package/src/shade/playground/skinned_blas_refit/main.js +4 -39
  87. package/src/shade/playground/volumetrics_froxel/main.d.ts.map +1 -1
  88. package/src/shade/playground/volumetrics_froxel/main.js +4 -39
  89. package/src/shade/playground/volumetrics_froxel/measure.d.ts.map +1 -1
  90. package/src/shade/playground/volumetrics_froxel/measure.js +2 -4
  91. package/src/shade/renderer/Renderer.d.ts +1 -1
  92. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  93. package/src/shade/renderer/Renderer.js +3 -1
  94. package/src/shade/renderer/light/GPULightCollection.d.ts +9 -1
  95. package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
  96. package/src/shade/renderer/light/GPULightCollection.js +41 -0
  97. package/src/shade/renderer/light/environment/shader_project_environment_sh.d.ts +37 -0
  98. package/src/shade/renderer/light/environment/shader_project_environment_sh.d.ts.map +1 -0
  99. package/src/shade/renderer/light/environment/shader_project_environment_sh.js +105 -0
  100. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  101. package/src/shade/renderer/particles/DESIGN.md +65 -8
  102. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +7 -1
  103. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  104. package/src/shade/renderer/particles/GPUParticleSystem.js +1247 -1244
  105. package/src/shade/renderer/particles/graph_particles_avboit.d.ts +7 -1
  106. package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
  107. package/src/shade/renderer/particles/graph_particles_avboit.js +9 -0
  108. package/src/shade/renderer/particles/shaders/chunk_particle_billboard_vertex.d.ts.map +1 -1
  109. package/src/shade/renderer/particles/shaders/chunk_particle_billboard_vertex.js +4 -2
  110. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +15 -9
  111. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts.map +1 -1
  112. package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +29 -11
  113. package/src/shade/renderer/particles/shaders/chunk_particle_lighting_model.d.ts +24 -0
  114. package/src/shade/renderer/particles/shaders/chunk_particle_lighting_model.d.ts.map +1 -0
  115. package/src/shade/renderer/particles/shaders/chunk_particle_lighting_model.js +45 -0
  116. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts +3 -0
  117. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts.map +1 -1
  118. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.js +38 -0
  119. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
  120. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +190 -185
  121. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +8 -0
  122. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  123. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +5 -0
  124. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts +8 -1
  125. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  126. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +9 -0
  127. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +13 -3
  128. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  129. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +9 -1
  130. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.d.ts +39 -0
  131. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.d.ts.map +1 -0
  132. package/src/shade/renderer/volumetrics/chunk_volumetrics_irradiance_sh.js +107 -0
  133. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_froxel_centre_ws.d.ts +15 -0
  134. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_froxel_centre_ws.d.ts.map +1 -0
  135. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_froxel_centre_ws.js +44 -0
  136. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.d.ts +19 -0
  137. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.d.ts.map +1 -0
  138. package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.js +48 -0
  139. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.d.ts +29 -0
  140. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.d.ts.map +1 -0
  141. package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.js +90 -0
  142. package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi_brick4.d.ts +10 -0
  143. package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi_brick4.d.ts.map +1 -0
  144. package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi_brick4.js +55 -0
  145. package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi_ibl.d.ts +10 -0
  146. package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi_ibl.d.ts.map +1 -0
  147. package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi_ibl.js +47 -0
  148. package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi_lpv.d.ts +10 -0
  149. package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi_lpv.d.ts.map +1 -0
  150. package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi_lpv.js +63 -0
  151. package/src/shade/renderer/volumetrics/gi/volumetrics_gi_resources.d.ts +17 -0
  152. package/src/shade/renderer/volumetrics/gi/volumetrics_gi_resources.d.ts.map +1 -0
  153. package/src/shade/renderer/volumetrics/gi/volumetrics_gi_resources.js +26 -0
  154. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +8 -1
  155. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
  156. package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +50 -2
  157. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  158. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +488 -436
  159. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts +1 -1
  160. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  161. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +254 -63
@@ -0,0 +1,39 @@
1
+ /**
2
+ * The froxel irradiance volume: the light a transparent surface standing in a froxel receives, for
3
+ * surfaces the lighting pass cannot see — the particles. The froxel GI stage (`gi/`) starts it with
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).
9
+ *
10
+ * Stored in the Metro Exodus L1 encoding (`l1i/`): luma as SH2 — four coefficients — and chroma as
11
+ * its constant band only. Two lights of different colours from opposite sides therefore light both
12
+ * sides in their luminance-weighted mix, not one colour each; that is the price of 6 coefficients
13
+ * instead of 12.
14
+ *
15
+ * Every light is added as a delta — all of its irradiance from one direction — and scaled by
16
+ * `1/(2 pi)`, which is the scale under which `resolve_irradiance_sh_to_diffuse(Y, CoCg, n)` returns
17
+ * `E(n) / pi`: the Lambertian radiance of a unit-albedo surface facing `n`. With SH2 that is
18
+ * `E * max(0, 1/4 + cos(theta)/2)` per light, over `pi` — the band-limited clamped cosine, a quarter
19
+ * dim at the peak and a quarter lit a right angle past the terminator.
20
+ *
21
+ * - `volumetrics_irradiance_sh_add(sh, irradiance, direction_to_light)` — one light's contribution,
22
+ * `irradiance` being what reaches the point at normal incidence and `direction_to_light` a unit
23
+ * vector pointing toward the light.
24
+ * - `volumetrics_irradiance_sh_add_radiance(sh, radiance)` — a whole radiance field arriving at the
25
+ * point, as RGB SH2: coefficients of radiance, not cosine-convolved, ordered `[DC, y, z, x]` in
26
+ * the project's all-positive basis (`sh2_basis_at`). The form every GI source hands over — the
27
+ * probes of Brick4 and of the light probe volume, and `GPULightCollection.environment_sh`. A light
28
+ * is the delta field `E sh2_basis_at(l)`, and adding it this way adds exactly what
29
+ * `volumetrics_irradiance_sh_add` does.
30
+ * - `volumetrics_irradiance_sh_storable(sh)` — what an `rgba16float` volume can hold. A clustered
31
+ * light close to a froxel exceeds half precision on its own and stores as +Inf, and an infinite
32
+ * luma times a zero band-1 basis is a NaN; either would reach every particle sampling that froxel.
33
+ * Non-finite coefficients become 0 and the rest are clamped to the half range.
34
+ *
35
+ * @type {CodeChunk}
36
+ */
37
+ export const chunk_volumetrics_irradiance_sh: CodeChunk;
38
+ import { CodeChunk } from "../shader/compiler/CodeChunk.js";
39
+ //# sourceMappingURL=chunk_volumetrics_irradiance_sh.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,107 @@
1
+ import { F16_MAX_DEFINITION } from "../shader/chunk/math/F16_MAX_DEFINITION.js";
2
+ import { F32_MAX_DEFINITION } from "../shader/chunk/math/F32_MAX_DEFINITION.js";
3
+ import {
4
+ chunk_convert_to_irradiance_sh,
5
+ METRO_L1_IRRADIANCE_STRUCT
6
+ } from "../shader/chunk/spherical_harmonics/l1i/chunk_convert_to_irradiance_sh.js";
7
+ import { chunk_rgb_to_YCoCg } from "../shader/chunk/color/YCoCg/chunk_rgb_to_YCoCg.js";
8
+ import { CodeChunk } from "../shader/compiler/CodeChunk.js";
9
+
10
+ /**
11
+ * The froxel irradiance volume: the light a transparent surface standing in a froxel receives, for
12
+ * surfaces the lighting pass cannot see — the particles. The froxel GI stage (`gi/`) starts it with
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).
18
+ *
19
+ * Stored in the Metro Exodus L1 encoding (`l1i/`): luma as SH2 — four coefficients — and chroma as
20
+ * its constant band only. Two lights of different colours from opposite sides therefore light both
21
+ * sides in their luminance-weighted mix, not one colour each; that is the price of 6 coefficients
22
+ * instead of 12.
23
+ *
24
+ * Every light is added as a delta — all of its irradiance from one direction — and scaled by
25
+ * `1/(2 pi)`, which is the scale under which `resolve_irradiance_sh_to_diffuse(Y, CoCg, n)` returns
26
+ * `E(n) / pi`: the Lambertian radiance of a unit-albedo surface facing `n`. With SH2 that is
27
+ * `E * max(0, 1/4 + cos(theta)/2)` per light, over `pi` — the band-limited clamped cosine, a quarter
28
+ * dim at the peak and a quarter lit a right angle past the terminator.
29
+ *
30
+ * - `volumetrics_irradiance_sh_add(sh, irradiance, direction_to_light)` — one light's contribution,
31
+ * `irradiance` being what reaches the point at normal incidence and `direction_to_light` a unit
32
+ * vector pointing toward the light.
33
+ * - `volumetrics_irradiance_sh_add_radiance(sh, radiance)` — a whole radiance field arriving at the
34
+ * point, as RGB SH2: coefficients of radiance, not cosine-convolved, ordered `[DC, y, z, x]` in
35
+ * the project's all-positive basis (`sh2_basis_at`). The form every GI source hands over — the
36
+ * probes of Brick4 and of the light probe volume, and `GPULightCollection.environment_sh`. A light
37
+ * is the delta field `E sh2_basis_at(l)`, and adding it this way adds exactly what
38
+ * `volumetrics_irradiance_sh_add` does.
39
+ * - `volumetrics_irradiance_sh_storable(sh)` — what an `rgba16float` volume can hold. A clustered
40
+ * light close to a froxel exceeds half precision on its own and stores as +Inf, and an infinite
41
+ * luma times a zero band-1 basis is a NaN; either would reach every particle sampling that froxel.
42
+ * Non-finite coefficients become 0 and the rest are clamped to the half range.
43
+ *
44
+ * @type {CodeChunk}
45
+ */
46
+ export const chunk_volumetrics_irradiance_sh = CodeChunk.from(
47
+ //language=WGSL
48
+ `
49
+ const VOLUMETRICS_IRRADIANCE_SH_SCALE : f32 = 0.15915494309189535; // 1 / (2 pi)
50
+
51
+ fn volumetrics_irradiance_sh_add(
52
+ sh: ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref},
53
+ irradiance: vec3<f32>,
54
+ direction_to_light: vec3<f32>,
55
+ ) -> ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref} {
56
+ let light = convert_to_irradiance_sh(irradiance * VOLUMETRICS_IRRADIANCE_SH_SCALE, direction_to_light);
57
+
58
+ return ${METRO_L1_IRRADIANCE_STRUCT.make({
59
+ CoCg: "sh.CoCg + light.CoCg",
60
+ Y: "sh.Y + light.Y",
61
+ })};
62
+ }
63
+
64
+ fn volumetrics_irradiance_sh_add_radiance(
65
+ sh: ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref},
66
+ radiance: array<vec3<f32>, 4>,
67
+ ) -> ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref} {
68
+ // luma carries all four coefficients, chroma the constant band only; YCoCg is linear, so the
69
+ // transform goes through the coefficients as it would through the colours
70
+ let c0 = rgb_to_YCoCg(radiance[0]);
71
+
72
+ // the Metro layout is (x, y, z, constant); the basis order is (constant, y, z, x)
73
+ let Y = vec4<f32>(
74
+ rgb_to_YCoCg(radiance[3]).x,
75
+ rgb_to_YCoCg(radiance[1]).x,
76
+ rgb_to_YCoCg(radiance[2]).x,
77
+ c0.x,
78
+ );
79
+
80
+ // the chroma a light adds is its irradiance's own, not times the band-0 basis constant
81
+ const BAND_0_BASIS : f32 = 0.28209479177387814;
82
+
83
+ return ${METRO_L1_IRRADIANCE_STRUCT.make({
84
+ CoCg: "sh.CoCg + c0.yz * (VOLUMETRICS_IRRADIANCE_SH_SCALE / BAND_0_BASIS)",
85
+ Y: "sh.Y + Y * VOLUMETRICS_IRRADIANCE_SH_SCALE",
86
+ })};
87
+ }
88
+
89
+ fn volumetrics_irradiance_sh_storable(sh: ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref}) -> ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref} {
90
+ // the comparison is what WGSL defines for a NaN; clamp is not
91
+ let Y_finite = (sh.Y == sh.Y) & (abs(sh.Y) < vec4<f32>(F32_MAX));
92
+ let CoCg_finite = (sh.CoCg == sh.CoCg) & (abs(sh.CoCg) < vec2<f32>(F32_MAX));
93
+
94
+ return ${METRO_L1_IRRADIANCE_STRUCT.make({
95
+ CoCg: "select(vec2<f32>(0.0), clamp(sh.CoCg, vec2<f32>(-F16_MAX), vec2<f32>(F16_MAX)), CoCg_finite)",
96
+ Y: "select(vec4<f32>(0.0), clamp(sh.Y, vec4<f32>(-F16_MAX), vec4<f32>(F16_MAX)), Y_finite)",
97
+ })};
98
+ }
99
+
100
+ `, [
101
+ chunk_convert_to_irradiance_sh,
102
+ chunk_rgb_to_YCoCg,
103
+ METRO_L1_IRRADIANCE_STRUCT.declaration_chunk,
104
+ F16_MAX_DEFINITION,
105
+ F32_MAX_DEFINITION,
106
+ ]
107
+ );
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `volumetrics_froxel_centre_ws(voxel, resolution)` — the world position a froxel's value stands for:
3
+ * its column's centre, at the depth its slab's content sits at (`volumetrics_froxel_content_offset`),
4
+ * which is where the lighting pass's jittered samples average to and where
5
+ * `volumetrics_position_world_to_froxel_uvw` puts the froxel's texel centre. A froxel GI module
6
+ * whose answer depends on position asks it there; GI is smooth enough across a froxel that one
7
+ * sample is all of it.
8
+ *
9
+ * The enclosing shader binds `camera` and `volumetrics_metadata` under those names.
10
+ *
11
+ * @type {CodeChunk}
12
+ */
13
+ export const chunk_volumetrics_froxel_centre_ws: CodeChunk;
14
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
15
+ //# sourceMappingURL=chunk_volumetrics_froxel_centre_ws.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_volumetrics_froxel_centre_ws.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/volumetrics/gi/chunk_volumetrics_froxel_centre_ws.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;GAWG;AACH,iDAFU,SAAS,CAyBjB;0BAvCwB,oCAAoC"}
@@ -0,0 +1,44 @@
1
+ import { chunk_cluster_depth_from_z_slice } from "../../light/cluster/chunk_cluster_depth_from_z_slice.js";
2
+ import { chunk_camera_ray_from_uv } from "../../shader/chunk/geometry/ray/chunk_camera_ray_from_uv.js";
3
+ import { RAY_STRUCT } from "../../shader/chunk/geometry/ray/RAY_STRUCT.js";
4
+ import { chunk_texel_coordinate_to_uv } from "../../shader/chunk/texture/chunk_texel_coordinate_to_uv.js";
5
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
6
+ import { chunk_camera_ray_planar_depth_scale } from "../chunk_camera_ray_planar_depth_scale.js";
7
+ import { chunk_volumetrics_froxel_content_offset } from "../chunk_volumetrics_froxel_content_offset.js";
8
+
9
+ /**
10
+ * `volumetrics_froxel_centre_ws(voxel, resolution)` — the world position a froxel's value stands for:
11
+ * its column's centre, at the depth its slab's content sits at (`volumetrics_froxel_content_offset`),
12
+ * which is where the lighting pass's jittered samples average to and where
13
+ * `volumetrics_position_world_to_froxel_uvw` puts the froxel's texel centre. A froxel GI module
14
+ * whose answer depends on position asks it there; GI is smooth enough across a froxel that one
15
+ * sample is all of it.
16
+ *
17
+ * The enclosing shader binds `camera` and `volumetrics_metadata` under those names.
18
+ *
19
+ * @type {CodeChunk}
20
+ */
21
+ export const chunk_volumetrics_froxel_centre_ws = CodeChunk.from(
22
+ //language=WGSL
23
+ `
24
+ fn volumetrics_froxel_centre_ws(voxel: vec3<u32>, resolution: vec3<u32>) -> vec3<f32> {
25
+ let curve = volumetrics_metadata.froxel_cluster_parameters;
26
+ let near_far = camera.clip_near_far;
27
+
28
+ let slice = f32(voxel.z) + volumetrics_froxel_content_offset(curve.z);
29
+ let view_depth = clamp(cluster_depth_from_z_slice(slice, curve, f32(resolution.z)), near_far.x, near_far.y);
30
+
31
+ let ray = camera_ray_from_uv(texel_coordinate_to_uv(vec2<f32>(voxel.xy), resolution.xy), camera);
32
+
33
+ // planar depth to a distance along the ray, as the lighting pass does
34
+ return ray.origin + ray.direction * (view_depth * camera_ray_planar_depth_scale(ray.direction, camera));
35
+ }
36
+ `, [
37
+ RAY_STRUCT.declaration_chunk,
38
+ chunk_volumetrics_froxel_content_offset,
39
+ chunk_cluster_depth_from_z_slice,
40
+ chunk_camera_ray_from_uv,
41
+ chunk_texel_coordinate_to_uv,
42
+ chunk_camera_ray_planar_depth_scale,
43
+ ]
44
+ );
@@ -0,0 +1,19 @@
1
+ /**
2
+ * What every froxel GI module shares. A module is one concrete compute shader per indirect lighting
3
+ * mode (`shader_volumetrics_gi_ibl`, `_brick4`, `_lpv`), one thread per froxel: it asks its mode what
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.
6
+ * A new mode is one more module: nothing downstream knows which mode wrote the volume.
7
+ *
8
+ * `volumetrics_froxel_centre_ws` (`chunk_volumetrics_froxel_centre_ws`) says where a froxel is, for a
9
+ * mode whose answer depends on position; `volumetrics_gi_store(voxel, radiance)` — scales the field by `INDIRECT_LIGHT_INTENSITY`, as the
10
+ * deferred and forward paths scale their indirect light, encodes it as the volume stores light
11
+ * (`volumetrics_irradiance_sh_add_radiance`) and writes it to `tGIY` / `tGICoCg`.
12
+ *
13
+ * The enclosing shader binds `tGIY` and `tGICoCg` under those names.
14
+ *
15
+ * @type {CodeChunk}
16
+ */
17
+ export const chunk_volumetrics_gi: CodeChunk;
18
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
19
+ //# sourceMappingURL=chunk_volumetrics_gi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_volumetrics_gi.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;GAeG;AACH,mCAFU,SAAS,CA0BjB;0BA5CwB,oCAAoC"}
@@ -0,0 +1,48 @@
1
+ import {
2
+ METRO_L1_IRRADIANCE_STRUCT
3
+ } from "../../shader/chunk/spherical_harmonics/l1i/chunk_convert_to_irradiance_sh.js";
4
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
5
+ import { INDIRECT_LIGHT_INTENSITY } from "../../deferred/INDIRECT_LIGHT_INTENSITY.js";
6
+ import { chunk_volumetrics_irradiance_sh } from "../chunk_volumetrics_irradiance_sh.js";
7
+
8
+ /**
9
+ * What every froxel GI module shares. A module is one concrete compute shader per indirect lighting
10
+ * mode (`shader_volumetrics_gi_ibl`, `_brick4`, `_lpv`), one thread per froxel: it asks its mode what
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.
13
+ * A new mode is one more module: nothing downstream knows which mode wrote the volume.
14
+ *
15
+ * `volumetrics_froxel_centre_ws` (`chunk_volumetrics_froxel_centre_ws`) says where a froxel is, for a
16
+ * mode whose answer depends on position; `volumetrics_gi_store(voxel, radiance)` — scales the field by `INDIRECT_LIGHT_INTENSITY`, as the
17
+ * deferred and forward paths scale their indirect light, encodes it as the volume stores light
18
+ * (`volumetrics_irradiance_sh_add_radiance`) and writes it to `tGIY` / `tGICoCg`.
19
+ *
20
+ * The enclosing shader binds `tGIY` and `tGICoCg` under those names.
21
+ *
22
+ * @type {CodeChunk}
23
+ */
24
+ export const chunk_volumetrics_gi = CodeChunk.from(
25
+ //language=WGSL
26
+ `
27
+ fn volumetrics_gi_store(voxel: vec3<u32>, radiance: array<vec3<f32>, 4>) {
28
+ const INDIRECT_INTENSITY : f32 = ${INDIRECT_LIGHT_INTENSITY};
29
+
30
+ let scaled = array<vec3<f32>, 4>(
31
+ radiance[0] * INDIRECT_INTENSITY,
32
+ radiance[1] * INDIRECT_INTENSITY,
33
+ radiance[2] * INDIRECT_INTENSITY,
34
+ radiance[3] * INDIRECT_INTENSITY,
35
+ );
36
+
37
+ var sh: ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref};
38
+
39
+ let stored = volumetrics_irradiance_sh_storable(volumetrics_irradiance_sh_add_radiance(sh, scaled));
40
+
41
+ textureStore(tGIY, voxel, stored.Y);
42
+ textureStore(tGICoCg, voxel, vec4<f32>(stored.CoCg, 0.0, 0.0));
43
+ }
44
+ `, [
45
+ METRO_L1_IRRADIANCE_STRUCT.declaration_chunk,
46
+ chunk_volumetrics_irradiance_sh,
47
+ ]
48
+ );
@@ -0,0 +1,29 @@
1
+ /**
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
4
+ * mode (see `chunk_volumetrics_gi`); this picks the one `indirect_lighting_mode` names and binds its
5
+ * source from the scene.
6
+ *
7
+ * @param {object} options
8
+ * @param {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} options.graph
9
+ * @param {ShadeIndirectLightingMode} options.indirect_lighting_mode
10
+ * @param {import("../../scene/GPUSceneContext.js").GPUSceneContext} options.scene_ctx the GI sources:
11
+ * `lights.environment_sh`, `volumetric_light_map`, `light_probe_volume`
12
+ * @param {import("../../camera/GPUCameraContext.js").GPUCameraContext} options.camera
13
+ * @param {number} options.volumetrics_metadata graph handle
14
+ * @param {number[]} options.resolution the froxel grid
15
+ * @returns {{Y: number, CoCg: number}} handles of the GI volume, in the froxel irradiance encoding
16
+ */
17
+ export function graph_build_froxel_gi({ graph, indirect_lighting_mode, scene_ctx, camera, volumetrics_metadata, resolution, }: {
18
+ graph: import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph;
19
+ indirect_lighting_mode: ShadeIndirectLightingMode;
20
+ scene_ctx: import("../../scene/GPUSceneContext.js").GPUSceneContext;
21
+ camera: import("../../camera/GPUCameraContext.js").GPUCameraContext;
22
+ volumetrics_metadata: number;
23
+ resolution: number[];
24
+ }): {
25
+ Y: number;
26
+ CoCg: number;
27
+ };
28
+ import { ShadeIndirectLightingMode } from "../../ShadeIndirectLightingMode.js";
29
+ //# sourceMappingURL=graph_build_froxel_gi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph_build_froxel_gi.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.js"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;GAeG;AACH;IATsG,KAAK,EAAhG,OAAO,8DAA8D,EAAE,UAAU;IAC9C,sBAAsB,EAAzD,yBAAyB;IACyC,SAAS,EAA3E,OAAO,gCAAgC,EAAE,eAAe;IAEa,MAAM,EAA3E,OAAO,kCAAkC,EAAE,gBAAgB;IAC3C,oBAAoB,EAApC,MAAM;IACY,UAAU,EAA5B,MAAM,EAAE;IACN;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAkErC;0CAtFyC,oCAAoC"}
@@ -0,0 +1,90 @@
1
+ import { TextureResourceDescriptor } from "../../../device/graph/TextureResourceDescriptor.js";
2
+ import { graph_compute_pass } from "../../shader/graph/compute/graph_compute_pass.js";
3
+ import { graph_import_buffer } from "../../shader/graph/graph_import_buffer.js";
4
+ import { ShadeIndirectLightingMode } from "../../ShadeIndirectLightingMode.js";
5
+ import { shader_volumetrics_gi_brick4 } from "./shader_volumetrics_gi_brick4.js";
6
+ import { shader_volumetrics_gi_ibl } from "./shader_volumetrics_gi_ibl.js";
7
+ import { shader_volumetrics_gi_lpv } from "./shader_volumetrics_gi_lpv.js";
8
+ import { VOLUMETRICS_GI_WORKGROUP_RESOLUTION } from "./volumetrics_gi_resources.js";
9
+
10
+ /**
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
13
+ * mode (see `chunk_volumetrics_gi`); this picks the one `indirect_lighting_mode` names and binds its
14
+ * source from the scene.
15
+ *
16
+ * @param {object} options
17
+ * @param {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} options.graph
18
+ * @param {ShadeIndirectLightingMode} options.indirect_lighting_mode
19
+ * @param {import("../../scene/GPUSceneContext.js").GPUSceneContext} options.scene_ctx the GI sources:
20
+ * `lights.environment_sh`, `volumetric_light_map`, `light_probe_volume`
21
+ * @param {import("../../camera/GPUCameraContext.js").GPUCameraContext} options.camera
22
+ * @param {number} options.volumetrics_metadata graph handle
23
+ * @param {number[]} options.resolution the froxel grid
24
+ * @returns {{Y: number, CoCg: number}} handles of the GI volume, in the froxel irradiance encoding
25
+ */
26
+ export function graph_build_froxel_gi({
27
+ graph,
28
+ indirect_lighting_mode,
29
+ scene_ctx,
30
+ camera,
31
+ volumetrics_metadata,
32
+ resolution,
33
+ }) {
34
+ const volume = () => TextureResourceDescriptor.from({
35
+ resolution,
36
+ dimension: "3d",
37
+ format: "rgba16float",
38
+ usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
39
+ });
40
+
41
+ const bindings = {
42
+ volumetrics_metadata,
43
+ camera: graph_import_buffer(graph, camera.buffer.buffer, "froxel gi camera"),
44
+ tGIY: volume(),
45
+ tGICoCg: volume(),
46
+ };
47
+
48
+ let shader;
49
+
50
+ switch (indirect_lighting_mode) {
51
+ case ShadeIndirectLightingMode.IBL:
52
+ shader = shader_volumetrics_gi_ibl;
53
+ bindings.environment_sh = scene_ctx.lights.environment_sh;
54
+ break;
55
+
56
+ case ShadeIndirectLightingMode.Brick4:
57
+ shader = shader_volumetrics_gi_brick4;
58
+ bindings.brick4 = scene_ctx.volumetric_light_map.buffer;
59
+ break;
60
+
61
+ case ShadeIndirectLightingMode.LPV: {
62
+ shader = shader_volumetrics_gi_lpv;
63
+ const lpv = scene_ctx.light_probe_volume;
64
+ bindings.lpv_lookup = lpv.buffer_mesh_bvh;
65
+ bindings.lpv_metadata = lpv.buffer_metadata;
66
+ bindings.lpv_mesh = lpv.buffer_mesh;
67
+ bindings.lpv_probes = lpv.buffer_probes;
68
+ break;
69
+ }
70
+
71
+ default:
72
+ throw new Error(`Unsupported indirect lighting mode: ${indirect_lighting_mode}`);
73
+ }
74
+
75
+ const outputs = graph_compute_pass({
76
+ graph,
77
+ shader,
78
+ group_count: [
79
+ Math.ceil(resolution[0] / VOLUMETRICS_GI_WORKGROUP_RESOLUTION[0]),
80
+ Math.ceil(resolution[1] / VOLUMETRICS_GI_WORKGROUP_RESOLUTION[1]),
81
+ Math.ceil(resolution[2] / VOLUMETRICS_GI_WORKGROUP_RESOLUTION[2]),
82
+ ],
83
+ bindings,
84
+ });
85
+
86
+ return {
87
+ Y: outputs.tGIY,
88
+ CoCg: outputs.tGICoCg,
89
+ };
90
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Froxel GI under `ShadeIndirectLightingMode.Brick4`: the sparse volumetric lightmap's probes,
3
+ * interpolated at each froxel's centre and truncated from SH3 to SH2. See `chunk_volumetrics_gi` for
4
+ * what a GI module is.
5
+ *
6
+ * @type {ComputeShader}
7
+ */
8
+ export const shader_volumetrics_gi_brick4: ComputeShader;
9
+ import { ComputeShader } from "../../shader/ComputeShader.js";
10
+ //# sourceMappingURL=shader_volumetrics_gi_brick4.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_volumetrics_gi_brick4.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/volumetrics/gi/shader_volumetrics_gi_brick4.js"],"names":[],"mappings":"AA2CA;;;;;;GAMG;AACH,2CAFU,aAAa,CAMpB;8BAnD2B,+BAA+B"}
@@ -0,0 +1,55 @@
1
+ import { BRICK4_DATA_STRUCT } from "../../global_illumination/brick4/gpu/BRICK4_DATA_STRUCT.js";
2
+ import { chunk_brick4_sample_sh } from "../../global_illumination/brick4/gpu/draw/chunk_brick4_sample_sh.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 { chunk_volumetrics_gi } from "./chunk_volumetrics_gi.js";
7
+ import { chunk_volumetrics_froxel_centre_ws } from "./chunk_volumetrics_froxel_centre_ws.js";
8
+ import { VOLUMETRICS_GI_WORKGROUP_RESOLUTION, volumetrics_gi_resource_group } from "./volumetrics_gi_resources.js";
9
+
10
+ const resources = new ShaderResourceSetDescriptor();
11
+
12
+ resources.addGroup(
13
+ volumetrics_gi_resource_group()
14
+ .addStorageBuffer("brick4", BRICK4_DATA_STRUCT)
15
+ );
16
+
17
+ const body = CodeChunk.from(
18
+ //language=WGSL
19
+ `
20
+ @compute @workgroup_size(${VOLUMETRICS_GI_WORKGROUP_RESOLUTION.join(", ")})
21
+ fn main(@builtin(global_invocation_id) voxel: vec3<u32>) {
22
+ let resolution = textureDimensions(tGIY);
23
+
24
+ if (any(voxel >= resolution)) {
25
+ return;
26
+ }
27
+
28
+ let position = volumetrics_froxel_centre_ws(voxel, resolution);
29
+
30
+ // A froxel has no surface. The normal only masks probes behind one, and a zero normal weighs
31
+ // every probe of the brick the same (brick4_probe_compute_weight_by_normal), which is the
32
+ // interpolation a point in open space wants.
33
+ let sh = brick4_sample_sh(position, vec3<f32>(0.0));
34
+
35
+ // SH3 to SH2: the first four coefficients are the same two bands, in the same order
36
+ volumetrics_gi_store(voxel, array<vec3<f32>, 4>(sh[0], sh[1], sh[2], sh[3]));
37
+ }
38
+ `, [
39
+ chunk_volumetrics_gi,
40
+ chunk_volumetrics_froxel_centre_ws,
41
+ chunk_brick4_sample_sh,
42
+ ]);
43
+
44
+ /**
45
+ * Froxel GI under `ShadeIndirectLightingMode.Brick4`: the sparse volumetric lightmap's probes,
46
+ * interpolated at each froxel's centre and truncated from SH3 to SH2. See `chunk_volumetrics_gi` for
47
+ * what a GI module is.
48
+ *
49
+ * @type {ComputeShader}
50
+ */
51
+ export const shader_volumetrics_gi_brick4 = ComputeShader.from({
52
+ label: "Volumetrics / GI Brick4",
53
+ resources,
54
+ body,
55
+ });
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Froxel GI under `ShadeIndirectLightingMode.IBL`: the environment, as
3
+ * `GPULightCollection.environment_sh` holds it (`shader_project_environment_sh`), at every froxel.
4
+ * See `chunk_volumetrics_gi` for what a GI module is.
5
+ *
6
+ * @type {ComputeShader}
7
+ */
8
+ export const shader_volumetrics_gi_ibl: ComputeShader;
9
+ import { ComputeShader } from "../../shader/ComputeShader.js";
10
+ //# sourceMappingURL=shader_volumetrics_gi_ibl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_volumetrics_gi_ibl.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/volumetrics/gi/shader_volumetrics_gi_ibl.js"],"names":[],"mappings":"AAmCA;;;;;;GAMG;AACH,wCAFU,aAAa,CAMpB;8BA5C2B,+BAA+B"}
@@ -0,0 +1,47 @@
1
+ import { ENVIRONMENT_SH_TYPE } from "../../light/environment/shader_project_environment_sh.js";
2
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
3
+ import { ComputeShader } from "../../shader/ComputeShader.js";
4
+ import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
5
+ import { chunk_volumetrics_gi } from "./chunk_volumetrics_gi.js";
6
+ import { VOLUMETRICS_GI_WORKGROUP_RESOLUTION, volumetrics_gi_resource_group } from "./volumetrics_gi_resources.js";
7
+
8
+ const resources = new ShaderResourceSetDescriptor();
9
+
10
+ resources.addGroup(
11
+ volumetrics_gi_resource_group()
12
+ .addUniform("environment_sh", ENVIRONMENT_SH_TYPE)
13
+ );
14
+
15
+ const body = CodeChunk.from(
16
+ //language=WGSL
17
+ `
18
+ @compute @workgroup_size(${VOLUMETRICS_GI_WORKGROUP_RESOLUTION.join(", ")})
19
+ fn main(@builtin(global_invocation_id) voxel: vec3<u32>) {
20
+ if (any(voxel >= textureDimensions(tGIY))) {
21
+ return;
22
+ }
23
+
24
+ // the environment is infinitely far: every froxel receives the same field
25
+ volumetrics_gi_store(voxel, array<vec3<f32>, 4>(
26
+ environment_sh[0].xyz,
27
+ environment_sh[1].xyz,
28
+ environment_sh[2].xyz,
29
+ environment_sh[3].xyz,
30
+ ));
31
+ }
32
+ `, [
33
+ chunk_volumetrics_gi,
34
+ ]);
35
+
36
+ /**
37
+ * Froxel GI under `ShadeIndirectLightingMode.IBL`: the environment, as
38
+ * `GPULightCollection.environment_sh` holds it (`shader_project_environment_sh`), at every froxel.
39
+ * See `chunk_volumetrics_gi` for what a GI module is.
40
+ *
41
+ * @type {ComputeShader}
42
+ */
43
+ export const shader_volumetrics_gi_ibl = ComputeShader.from({
44
+ label: "Volumetrics / GI IBL",
45
+ resources,
46
+ body,
47
+ });
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Froxel GI under `ShadeIndirectLightingMode.LPV`: the light probe volume's tetrahedral mesh, its
3
+ * probes (radiance SH2) interpolated barycentrically at each froxel's centre. See
4
+ * `chunk_volumetrics_gi` for what a GI module is.
5
+ *
6
+ * @type {ComputeShader}
7
+ */
8
+ export const shader_volumetrics_gi_lpv: ComputeShader;
9
+ import { ComputeShader } from "../../shader/ComputeShader.js";
10
+ //# sourceMappingURL=shader_volumetrics_gi_lpv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shader_volumetrics_gi_lpv.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/volumetrics/gi/shader_volumetrics_gi_lpv.js"],"names":[],"mappings":"AAmDA;;;;;;GAMG;AACH,wCAFU,aAAa,CAMpB;8BAzD2B,+BAA+B"}
@@ -0,0 +1,63 @@
1
+ import { LPV_SHADER_RESOURCE_GROUP } from "../../global_illumination/probe/octahedral/LPV_SHADER_RESOURCE_GROUP.js";
2
+ import { chunk_lpv_mesh_interpolation_probe_sh } from "../../shader/chunk/light/lpv/chunk_lpv_mesh_interpolation_probe_sh.js";
3
+ import { chunk_lpv_mesh_lookup_nearest_cell } from "../../shader/chunk/light/lpv/chunk_lpv_mesh_lookup_nearest_cell.js";
4
+ import { INVALID_TET_DECLARATION } from "../../shader/chunk/light/lpv/INVALID_TET_DECLARATION.js";
5
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
6
+ import { ComputeShader } from "../../shader/ComputeShader.js";
7
+ import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
8
+ import { chunk_volumetrics_gi } from "./chunk_volumetrics_gi.js";
9
+ import { chunk_volumetrics_froxel_centre_ws } from "./chunk_volumetrics_froxel_centre_ws.js";
10
+ import { VOLUMETRICS_GI_WORKGROUP_RESOLUTION, volumetrics_gi_resource_group } from "./volumetrics_gi_resources.js";
11
+
12
+ const resources = new ShaderResourceSetDescriptor();
13
+
14
+ resources.addGroup(volumetrics_gi_resource_group());
15
+ resources.addGroup(LPV_SHADER_RESOURCE_GROUP);
16
+
17
+ const body = CodeChunk.from(
18
+ //language=WGSL
19
+ `
20
+ @compute @workgroup_size(${VOLUMETRICS_GI_WORKGROUP_RESOLUTION.join(", ")})
21
+ fn main(@builtin(global_invocation_id) voxel: vec3<u32>) {
22
+ let resolution = textureDimensions(tGIY);
23
+
24
+ if (any(voxel >= resolution)) {
25
+ return;
26
+ }
27
+
28
+ let position = volumetrics_froxel_centre_ws(voxel, resolution);
29
+
30
+ var weights: vec4<f32>;
31
+ let tet = lpv_mesh_lookup_nearest_cell(position, &weights);
32
+
33
+ // Outside the probe mesh there is nothing to interpolate, and the deferred LPV pass gives such a
34
+ // point no indirect light either. No visibility mask: that needs a surface normal, and a froxel
35
+ // has none.
36
+ var radiance = array<vec3<f32>, 4>();
37
+
38
+ if (tet != INVALID_TET) {
39
+ radiance = lpv_mesh_interpolation_probe_sh(weights, tet);
40
+ }
41
+
42
+ volumetrics_gi_store(voxel, radiance);
43
+ }
44
+ `, [
45
+ chunk_volumetrics_gi,
46
+ chunk_volumetrics_froxel_centre_ws,
47
+ chunk_lpv_mesh_lookup_nearest_cell,
48
+ chunk_lpv_mesh_interpolation_probe_sh,
49
+ INVALID_TET_DECLARATION,
50
+ ]);
51
+
52
+ /**
53
+ * Froxel GI under `ShadeIndirectLightingMode.LPV`: the light probe volume's tetrahedral mesh, its
54
+ * probes (radiance SH2) interpolated barycentrically at each froxel's centre. See
55
+ * `chunk_volumetrics_gi` for what a GI module is.
56
+ *
57
+ * @type {ComputeShader}
58
+ */
59
+ export const shader_volumetrics_gi_lpv = ComputeShader.from({
60
+ label: "Volumetrics / GI LPV",
61
+ resources,
62
+ body,
63
+ });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The bindings every froxel GI module has, whatever its mode reads: where the froxels are, and the
3
+ * two volumes it writes (`chunk_volumetrics_gi`). rgba16float for both, because rg16float is not a
4
+ * storage format without texture-formats-tier1.
5
+ *
6
+ * @returns {ShaderResourceGroupDescriptor}
7
+ */
8
+ export function volumetrics_gi_resource_group(): ShaderResourceGroupDescriptor;
9
+ /**
10
+ * Workgroup shape of every froxel GI module, `[x, y, z]` in froxels: flat in z like the lighting
11
+ * pass, and 64 invocations.
12
+ *
13
+ * @type {number[]}
14
+ */
15
+ export const VOLUMETRICS_GI_WORKGROUP_RESOLUTION: number[];
16
+ import { ShaderResourceGroupDescriptor } from "../../shader/resource/ShaderResourceGroupDescriptor.js";
17
+ //# sourceMappingURL=volumetrics_gi_resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"volumetrics_gi_resources.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/volumetrics/gi/volumetrics_gi_resources.js"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,iDAFa,6BAA6B,CAQzC;AAED;;;;;GAKG;AACH,kDAFU,MAAM,EAAE,CAE2C;8CAxBf,wDAAwD"}