@woosh/meep-engine 3.11.1 → 3.11.3

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 (225) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  4. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +294 -290
  5. package/src/engine/graphics3/ParticipatingMedia.d.ts +111 -0
  6. package/src/engine/graphics3/ParticipatingMedia.d.ts.map +1 -0
  7. package/src/engine/graphics3/ParticipatingMedia.js +203 -0
  8. package/src/engine/graphics3/ParticipatingMediaSerializationAdapter.d.ts +34 -0
  9. package/src/engine/graphics3/ParticipatingMediaSerializationAdapter.d.ts.map +1 -0
  10. package/src/engine/graphics3/ParticipatingMediaSerializationAdapter.js +73 -0
  11. package/src/engine/graphics3/ParticipatingMediaSystem3.d.ts +87 -0
  12. package/src/engine/graphics3/ParticipatingMediaSystem3.d.ts.map +1 -0
  13. package/src/engine/graphics3/ParticipatingMediaSystem3.js +184 -0
  14. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  15. package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.d.ts +16 -2
  16. package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.d.ts.map +1 -1
  17. package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.js +28 -4
  18. package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.d.ts +1 -1
  19. package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.d.ts.map +1 -1
  20. package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.js +5 -2
  21. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +564 -451
  22. package/src/shade/device/ShadeGPUCommandContext.d.ts +18 -2
  23. package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
  24. package/src/shade/device/ShadeGPUCommandContext.js +994 -940
  25. package/src/shade/device/immediate_data_supported.d.ts +33 -0
  26. package/src/shade/device/immediate_data_supported.d.ts.map +1 -0
  27. package/src/shade/device/immediate_data_supported.js +53 -0
  28. package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts +18 -0
  29. package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts.map +1 -1
  30. package/src/shade/device/mock/SoftwareGPUCommandEncoder.js +24 -0
  31. package/src/shade/device/mock/SoftwareGPUComputePassEncoder.d.ts +7 -0
  32. package/src/shade/device/mock/SoftwareGPUComputePassEncoder.d.ts.map +1 -1
  33. package/src/shade/device/mock/SoftwareGPUComputePassEncoder.js +49 -1
  34. package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
  35. package/src/shade/device/mock/SoftwareGPUDevice.js +20 -2
  36. package/src/shade/device/mock/SoftwareGPUImmediateData.d.ts +65 -0
  37. package/src/shade/device/mock/SoftwareGPUImmediateData.d.ts.map +1 -0
  38. package/src/shade/device/mock/SoftwareGPUImmediateData.js +160 -0
  39. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts +7 -0
  40. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts.map +1 -1
  41. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.js +50 -0
  42. package/src/shade/device/mock/pipeline_immediate_size.d.ts +11 -0
  43. package/src/shade/device/mock/pipeline_immediate_size.d.ts.map +1 -0
  44. package/src/shade/device/mock/pipeline_immediate_size.js +18 -0
  45. package/src/shade/device/pipeline/PipelineLayoutManager.d.ts.map +1 -1
  46. package/src/shade/device/pipeline/PipelineLayoutManager.js +1 -0
  47. package/src/shade/playground/volumetrics_froxel/README.md +104 -1
  48. package/src/shade/playground/volumetrics_froxel/index.html +20 -1
  49. package/src/shade/playground/volumetrics_froxel/main.d.ts.map +1 -1
  50. package/src/shade/playground/volumetrics_froxel/main.js +298 -0
  51. package/src/shade/playground/volumetrics_froxel/measure.d.ts +119 -0
  52. package/src/shade/playground/volumetrics_froxel/measure.d.ts.map +1 -0
  53. package/src/shade/playground/volumetrics_froxel/measure.js +559 -0
  54. package/src/shade/renderer/GraphicsContext.d.ts +9 -2
  55. package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
  56. package/src/shade/renderer/GraphicsContext.js +13 -1
  57. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  58. package/src/shade/renderer/Renderer.js +22 -18
  59. package/src/shade/renderer/atmosphere/GPUSky.d.ts.map +1 -1
  60. package/src/shade/renderer/atmosphere/GPUSky.js +145 -142
  61. package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.d.ts +34 -0
  62. package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.d.ts.map +1 -0
  63. package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.js +36 -0
  64. package/src/shade/renderer/atmosphere/SAMPLER_SKY_LUT.d.ts +20 -0
  65. package/src/shade/renderer/atmosphere/SAMPLER_SKY_LUT.d.ts.map +1 -0
  66. package/src/shade/renderer/atmosphere/SAMPLER_SKY_LUT.js +25 -0
  67. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts +14 -1
  68. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts.map +1 -1
  69. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.js +163 -177
  70. package/src/shade/renderer/atmosphere/chunk_multiscatter_sample_direction.d.ts +20 -0
  71. package/src/shade/renderer/atmosphere/chunk_multiscatter_sample_direction.d.ts.map +1 -0
  72. package/src/shade/renderer/atmosphere/chunk_multiscatter_sample_direction.js +46 -0
  73. package/src/shade/renderer/atmosphere/chunk_sample_multiscatter_lut.d.ts +11 -1
  74. package/src/shade/renderer/atmosphere/chunk_sample_multiscatter_lut.d.ts.map +1 -1
  75. package/src/shade/renderer/atmosphere/chunk_sample_multiscatter_lut.js +57 -27
  76. package/src/shade/renderer/atmosphere/chunk_sample_transmittance_lut.d.ts +19 -1
  77. package/src/shade/renderer/atmosphere/chunk_sample_transmittance_lut.d.ts.map +1 -1
  78. package/src/shade/renderer/atmosphere/chunk_sample_transmittance_lut.js +69 -33
  79. package/src/shade/renderer/atmosphere/chunk_sky_lut_compute_uv.d.ts +13 -0
  80. package/src/shade/renderer/atmosphere/chunk_sky_lut_compute_uv.d.ts.map +1 -1
  81. package/src/shade/renderer/atmosphere/chunk_sky_lut_compute_uv.js +35 -35
  82. package/src/shade/renderer/atmosphere/chunk_sky_lut_params.d.ts +13 -0
  83. package/src/shade/renderer/atmosphere/chunk_sky_lut_params.d.ts.map +1 -0
  84. package/src/shade/renderer/atmosphere/chunk_sky_lut_params.js +38 -0
  85. package/src/shade/renderer/atmosphere/chunk_sky_lut_texel_to_unit.d.ts +17 -0
  86. package/src/shade/renderer/atmosphere/chunk_sky_lut_texel_to_unit.d.ts.map +1 -0
  87. package/src/shade/renderer/atmosphere/chunk_sky_lut_texel_to_unit.js +29 -0
  88. package/src/shade/renderer/atmosphere/chunk_sky_lut_uv.d.ts +21 -0
  89. package/src/shade/renderer/atmosphere/chunk_sky_lut_uv.d.ts.map +1 -0
  90. package/src/shade/renderer/atmosphere/chunk_sky_lut_uv.js +42 -0
  91. package/src/shade/renderer/atmosphere/shader_multiscatter_lut.d.ts +2 -2
  92. package/src/shade/renderer/atmosphere/shader_multiscatter_lut.d.ts.map +1 -1
  93. package/src/shade/renderer/atmosphere/shader_multiscatter_lut.js +165 -84
  94. package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.d.ts.map +1 -1
  95. package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.js +215 -204
  96. package/src/shade/renderer/atmosphere/shader_transmittance_lut.d.ts.map +1 -1
  97. package/src/shade/renderer/atmosphere/shader_transmittance_lut.js +79 -67
  98. package/src/shade/renderer/light/cluster/graph_assign_clsuters.d.ts.map +1 -1
  99. package/src/shade/renderer/light/cluster/graph_assign_clsuters.js +6 -2
  100. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
  101. package/src/shade/renderer/postprocess/gtao/GTAO.js +4 -0
  102. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  103. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  104. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +341 -345
  105. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +0 -2
  106. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
  107. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +58 -57
  108. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
  109. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +7 -3
  110. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
  111. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +77 -81
  112. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
  113. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +5 -1
  114. package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
  115. package/src/shade/renderer/shader/ComputeShader.js +6 -2
  116. package/src/shade/renderer/shader/ImageShader.d.ts.map +1 -1
  117. package/src/shade/renderer/shader/ImageShader.js +4 -1
  118. package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
  119. package/src/shade/renderer/shader/ShaderDescriptor.js +26 -0
  120. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_RADII_DECLARATION.d.ts +18 -0
  121. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_RADII_DECLARATION.d.ts.map +1 -0
  122. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_RADII_DECLARATION.js +32 -0
  123. package/src/shade/renderer/shader/chunk/atmosphere/PLANET_CENTER_DECLARATION.d.ts +7 -0
  124. package/src/shade/renderer/shader/chunk/atmosphere/PLANET_CENTER_DECLARATION.d.ts.map +1 -1
  125. package/src/shade/renderer/shader/chunk/atmosphere/PLANET_CENTER_DECLARATION.js +17 -6
  126. package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_ray_bounds.d.ts +21 -0
  127. package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_ray_bounds.d.ts.map +1 -0
  128. package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_ray_bounds.js +69 -0
  129. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_contains_aabb3.d.ts +9 -0
  130. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_contains_aabb3.d.ts.map +1 -0
  131. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_contains_aabb3.js +22 -0
  132. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_from_transformed_corners.d.ts +16 -0
  133. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_from_transformed_corners.d.ts.map +1 -0
  134. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_from_transformed_corners.js +41 -0
  135. package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_m4.d.ts +11 -0
  136. package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_m4.d.ts.map +1 -1
  137. package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_m4.js +15 -19
  138. package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_plane_matrix.d.ts +23 -0
  139. package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_plane_matrix.d.ts.map +1 -0
  140. package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_plane_matrix.js +44 -0
  141. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_uv_octahedral_unit_decode.d.ts.map +1 -1
  142. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_uv_octahedral_unit_decode.js +1 -4
  143. package/src/shade/renderer/shader/compiler/CodeChunk.d.ts +7 -1
  144. package/src/shade/renderer/shader/compiler/CodeChunk.d.ts.map +1 -1
  145. package/src/shade/renderer/shader/compiler/CodeChunk.js +37 -2
  146. package/src/shade/renderer/shader/graph/compute/compute_binding_read_names.d.ts.map +1 -1
  147. package/src/shade/renderer/shader/graph/compute/compute_binding_read_names.js +6 -0
  148. package/src/shade/renderer/shader/graph/compute/graph_compute_indirect_pass.js +1 -1
  149. package/src/shade/renderer/shader/graph/compute/graph_compute_pass.js +1 -1
  150. package/src/shade/renderer/shader/graph/graph_image_pass.js +1 -1
  151. package/src/shade/renderer/shader/graph/graph_prepare_bindings.d.ts.map +1 -1
  152. package/src/shade/renderer/shader/graph/graph_prepare_bindings.js +7 -0
  153. package/src/shade/renderer/shader/graph/graph_prepare_pass_input_data.d.ts +3 -1
  154. package/src/shade/renderer/shader/graph/graph_prepare_pass_input_data.d.ts.map +1 -1
  155. package/src/shade/renderer/shader/graph/graph_prepare_pass_input_data.js +12 -1
  156. package/src/shade/renderer/shader/pass/RenderPassDescriptor.d.ts.map +1 -1
  157. package/src/shade/renderer/shader/pass/RenderPassDescriptor.js +1 -0
  158. package/src/shade/renderer/shader/resource/IMMEDIATE_DATA.d.ts +21 -0
  159. package/src/shade/renderer/shader/resource/IMMEDIATE_DATA.d.ts.map +1 -0
  160. package/src/shade/renderer/shader/resource/IMMEDIATE_DATA.js +21 -0
  161. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts +59 -1
  162. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  163. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +195 -2
  164. package/src/shade/renderer/shader/type/type_has_arrays.d.ts +14 -0
  165. package/src/shade/renderer/shader/type/type_has_arrays.d.ts.map +1 -0
  166. package/src/shade/renderer/shader/type/type_has_arrays.js +33 -0
  167. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_point2.d.ts +14 -13
  168. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_point2.d.ts.map +1 -1
  169. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_point2.js +133 -129
  170. package/src/shade/renderer/view/GPUViewSkyContext.d.ts.map +1 -1
  171. package/src/shade/renderer/view/GPUViewSkyContext.js +169 -173
  172. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  173. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +480 -315
  174. package/src/shade/renderer/volumetrics/NOTES.md +887 -8
  175. package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.d.ts +5 -0
  176. package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.d.ts.map +1 -1
  177. package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.js +21 -2
  178. package/src/shade/renderer/volumetrics/SceneVolumetrics.d.ts +26 -0
  179. package/src/shade/renderer/volumetrics/SceneVolumetrics.d.ts.map +1 -1
  180. package/src/shade/renderer/volumetrics/SceneVolumetrics.js +64 -21
  181. package/src/shade/renderer/volumetrics/VOLUMETRICS_METADATA_STRUCT.d.ts.map +1 -1
  182. package/src/shade/renderer/volumetrics/VOLUMETRICS_METADATA_STRUCT.js +84 -28
  183. package/src/shade/renderer/volumetrics/VOLUMETRICS_SUN_SHADOW_RESOLUTION.d.ts +98 -0
  184. package/src/shade/renderer/volumetrics/VOLUMETRICS_SUN_SHADOW_RESOLUTION.d.ts.map +1 -0
  185. package/src/shade/renderer/volumetrics/VOLUMETRICS_SUN_SHADOW_RESOLUTION.js +111 -0
  186. package/src/shade/renderer/volumetrics/build_volumetrics_sun_shadow_transform.d.ts +84 -0
  187. package/src/shade/renderer/volumetrics/build_volumetrics_sun_shadow_transform.d.ts.map +1 -0
  188. package/src/shade/renderer/volumetrics/build_volumetrics_sun_shadow_transform.js +252 -0
  189. package/src/shade/renderer/volumetrics/chunk_integrate_optical_depth.js +75 -75
  190. package/src/shade/renderer/volumetrics/chunk_volumetrics_local_light_shadow.d.ts +43 -0
  191. package/src/shade/renderer/volumetrics/chunk_volumetrics_local_light_shadow.d.ts.map +1 -0
  192. package/src/shade/renderer/volumetrics/chunk_volumetrics_local_light_shadow.js +145 -0
  193. package/src/shade/renderer/volumetrics/chunk_volumetrics_sample_froxel_extinction.d.ts +20 -0
  194. package/src/shade/renderer/volumetrics/chunk_volumetrics_sample_froxel_extinction.d.ts.map +1 -0
  195. package/src/shade/renderer/volumetrics/chunk_volumetrics_sample_froxel_extinction.js +48 -0
  196. package/src/shade/renderer/volumetrics/chunk_volumetrics_sun_optical_depth.d.ts +38 -0
  197. package/src/shade/renderer/volumetrics/chunk_volumetrics_sun_optical_depth.d.ts.map +1 -0
  198. package/src/shade/renderer/volumetrics/chunk_volumetrics_sun_optical_depth.js +130 -0
  199. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +18 -3
  200. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
  201. package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +193 -70
  202. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts +16 -0
  203. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  204. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +83 -15
  205. package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.d.ts.map +1 -1
  206. package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.js +29 -18
  207. package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.js +260 -260
  208. package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.d.ts +58 -0
  209. package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.d.ts.map +1 -0
  210. package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.js +290 -0
  211. package/src/shade/wgsl/emulator/CPUBitmapData.d.ts +25 -0
  212. package/src/shade/wgsl/emulator/CPUBitmapData.d.ts.map +1 -1
  213. package/src/shade/wgsl/emulator/CPUBitmapData.js +33 -0
  214. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +2228 -2215
  215. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  216. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +210 -2
  217. package/src/shade/wgsl/emulator/cpu_texture_gather.d.ts +69 -0
  218. package/src/shade/wgsl/emulator/cpu_texture_gather.d.ts.map +1 -0
  219. package/src/shade/wgsl/emulator/cpu_texture_gather.js +148 -0
  220. package/src/shade/wgsl/emulator/cpu_texture_sample.d.ts +16 -0
  221. package/src/shade/wgsl/emulator/cpu_texture_sample.d.ts.map +1 -1
  222. package/src/shade/wgsl/emulator/cpu_texture_sample.js +176 -172
  223. package/src/shade/renderer/volumetrics/VOLUMETRICS_WORKGROUP_RESOLUTION.d.ts +0 -2
  224. package/src/shade/renderer/volumetrics/VOLUMETRICS_WORKGROUP_RESOLUTION.d.ts.map +0 -1
  225. package/src/shade/renderer/volumetrics/VOLUMETRICS_WORKGROUP_RESOLUTION.js +0 -1
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Name of the texture holding cascade `index` of the sun's optical-depth volume.
3
+ *
4
+ * Generated rather than written out because the cascade count is a constant and everything that
5
+ * touches the structure — this chunk, the lighting pass's resource set, the frame graph — has to
6
+ * agree with it. A name spelled by hand in one of those places is the way a fourth cascade turns
7
+ * into a silent black frame.
8
+ *
9
+ * @param {number} index
10
+ * @returns {string}
11
+ */
12
+ export function volumetrics_sun_shadow_texture_name(index: number): string;
13
+ /**
14
+ * Optical depth of the participating medium between a world position and the sun, in one fetch.
15
+ *
16
+ * Same quantity `integrate_optical_depth` returns for a directional light, and deliberately the
17
+ * same signature shape, so the two are interchangeable at the call site. What it does not expose is
18
+ * how the answer was produced: the caller passes a world position and gets an integral back, and
19
+ * whether that came from a light-aligned prefix scan, a Fourier basis or a march is not its
20
+ * business. Swapping the representation should not touch `shader_volumetrics_build_lighting`.
21
+ *
22
+ * Cascades are selected on **view depth**, not on containment in each box. The two agree — every
23
+ * box is sized from the bounding sphere of the sub-frustum out to that depth, so a froxel at or
24
+ * inside it is inside the box — and only the first gives a scalar to blend along. It also makes the
25
+ * branch uniform across a workgroup: the lighting pass dispatches one froxel slice per workgroup in
26
+ * z, and a slice is a surface of constant depth.
27
+ *
28
+ * The `saturate` in each lookup is a statement about the domain rather than a clamp that fires.
29
+ * Selection has already established the position is inside the cascade it reads; outside, the
30
+ * sensible reading of a clamped fetch is still the right one, since the outermost box's faces sit
31
+ * in empty space and the value there is the column's total.
32
+ *
33
+ * @see shader_volumetrics_build_sun_shadow_volume, build_volumetrics_sun_shadow_transform
34
+ * @type {CodeChunk}
35
+ */
36
+ export const chunk_volumetrics_sun_optical_depth: CodeChunk;
37
+ import { CodeChunk } from "../shader/compiler/CodeChunk.js";
38
+ //# sourceMappingURL=chunk_volumetrics_sun_optical_depth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_volumetrics_sun_optical_depth.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/volumetrics/chunk_volumetrics_sun_optical_depth.js"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,2DAHW,MAAM,GACJ,MAAM,CAIlB;AA2ED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,kDAFU,SAAS,CAgBjB;0BAhIwB,iCAAiC"}
@@ -0,0 +1,130 @@
1
+ import { CAMERA_UNIFORM_STRUCT } from "../camera/CAMERA_UNIFORM_STRUCT.js";
2
+ import { CodeChunk } from "../shader/compiler/CodeChunk.js";
3
+ import { VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT } from "./VOLUMETRICS_SUN_SHADOW_RESOLUTION.js";
4
+
5
+ /**
6
+ * Name of the texture holding cascade `index` of the sun's optical-depth volume.
7
+ *
8
+ * Generated rather than written out because the cascade count is a constant and everything that
9
+ * touches the structure — this chunk, the lighting pass's resource set, the frame graph — has to
10
+ * agree with it. A name spelled by hand in one of those places is the way a fourth cascade turns
11
+ * into a silent black frame.
12
+ *
13
+ * @param {number} index
14
+ * @returns {string}
15
+ */
16
+ export function volumetrics_sun_shadow_texture_name(index) {
17
+ return `tSunShadowCascade${index}`;
18
+ }
19
+
20
+ /**
21
+ * Fraction of a cascade's range at which it starts handing over to the next one out.
22
+ *
23
+ * The two cascades do not agree where they meet — that is the entire point of having two, one is
24
+ * more accurate than the other — so a hard switch is a visible edge at a fixed view depth, which is
25
+ * to say a ring around the screen that the 0.95-blend froxel TAA would smear rather than remove.
26
+ * Cascaded shadow maps blend across a band for the same reason.
27
+ *
28
+ * @type {number}
29
+ */
30
+ const CASCADE_BLEND_START = 0.9;
31
+
32
+ /**
33
+ * Outermost cascade. It is where the selection ladder falls out to, so it is the one cascade with
34
+ * no successor to hand over to, and therefore the bound on the ladder rather than a step in it.
35
+ *
36
+ * @type {number}
37
+ */
38
+ const LAST_CASCADE = VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT - 1;
39
+
40
+ /**
41
+ * One `volumetrics_sun_optical_depth_cascade_<index>` per cascade.
42
+ *
43
+ * @type {string}
44
+ */
45
+ let cascade_lookups = "";
46
+
47
+ for (let index = 0; index < VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT; index++) {
48
+
49
+ //language=WGSL
50
+ cascade_lookups += `
51
+ fn volumetrics_sun_optical_depth_cascade_${index}(position_ws: vec3<f32>) -> vec3<f32> {
52
+
53
+ let uvw = (volumetrics_metadata.sun_shadow_ws_to_uvw[${index}] * vec4<f32>(position_ws, 1.0)).xyz;
54
+
55
+ return textureSampleLevel(${volumetrics_sun_shadow_texture_name(index)}, sLinear, saturate(uvw), 0.0).rgb;
56
+ }
57
+ `;
58
+ }
59
+
60
+ /**
61
+ * The ladder that picks between those lookups, one block per hand-over, spliced into the body of
62
+ * `volumetrics_sun_optical_depth`. Indexed over the same cascades and one short, so a cascade
63
+ * declared above and never reached here is a function nothing samples, and a block here naming a
64
+ * cascade not declared above is a call to a function that does not exist.
65
+ *
66
+ * @type {string}
67
+ */
68
+ let cascade_selection = "";
69
+
70
+ for (let index = 0; index < LAST_CASCADE; index++) {
71
+
72
+ //language=WGSL
73
+ cascade_selection += `
74
+ {
75
+ let far = volumetrics_metadata.sun_shadow_cascade_far[${index}];
76
+ let blend_start = far * ${CASCADE_BLEND_START};
77
+
78
+ if (view_depth < blend_start) {
79
+ return volumetrics_sun_optical_depth_cascade_${index}(position_ws);
80
+ }
81
+
82
+ if (view_depth < far) {
83
+ return mix(
84
+ volumetrics_sun_optical_depth_cascade_${index}(position_ws),
85
+ volumetrics_sun_optical_depth_cascade_${index + 1}(position_ws),
86
+ (view_depth - blend_start) / (far - blend_start)
87
+ );
88
+ }
89
+ }
90
+ `;
91
+ }
92
+
93
+ /**
94
+ * Optical depth of the participating medium between a world position and the sun, in one fetch.
95
+ *
96
+ * Same quantity `integrate_optical_depth` returns for a directional light, and deliberately the
97
+ * same signature shape, so the two are interchangeable at the call site. What it does not expose is
98
+ * how the answer was produced: the caller passes a world position and gets an integral back, and
99
+ * whether that came from a light-aligned prefix scan, a Fourier basis or a march is not its
100
+ * business. Swapping the representation should not touch `shader_volumetrics_build_lighting`.
101
+ *
102
+ * Cascades are selected on **view depth**, not on containment in each box. The two agree — every
103
+ * box is sized from the bounding sphere of the sub-frustum out to that depth, so a froxel at or
104
+ * inside it is inside the box — and only the first gives a scalar to blend along. It also makes the
105
+ * branch uniform across a workgroup: the lighting pass dispatches one froxel slice per workgroup in
106
+ * z, and a slice is a surface of constant depth.
107
+ *
108
+ * The `saturate` in each lookup is a statement about the domain rather than a clamp that fires.
109
+ * Selection has already established the position is inside the cascade it reads; outside, the
110
+ * sensible reading of a clamped fetch is still the right one, since the outermost box's faces sit
111
+ * in empty space and the value there is the column's total.
112
+ *
113
+ * @see shader_volumetrics_build_sun_shadow_volume, build_volumetrics_sun_shadow_transform
114
+ * @type {CodeChunk}
115
+ */
116
+ export const chunk_volumetrics_sun_optical_depth = CodeChunk.from(
117
+ //language=WGSL
118
+ `
119
+ ${cascade_lookups}
120
+ fn volumetrics_sun_optical_depth(position_ws: vec3<f32>) -> vec3<f32> {
121
+
122
+ // view space looks down -Z
123
+ let view_depth = -(camera.view_matrix * vec4<f32>(position_ws, 1.0)).z;
124
+ ${cascade_selection}
125
+ return volumetrics_sun_optical_depth_cascade_${LAST_CASCADE}(position_ws);
126
+ }
127
+ `, [
128
+ CAMERA_UNIFORM_STRUCT.declaration_chunk,
129
+ ]
130
+ );
@@ -1,3 +1,15 @@
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 {FrameGraph} graph
7
+ * @returns {{transmittance_lut: number, multiscatted_lut: number}} resource handles
8
+ */
9
+ export function graph_integrate_sky({ graph }: FrameGraph): {
10
+ transmittance_lut: number;
11
+ multiscatted_lut: number;
12
+ };
1
13
  /**
2
14
  *
3
15
  * @param {FrameGraph} graph
@@ -9,14 +21,17 @@
9
21
  * @param {number} light_cluster_parameters
10
22
  * @param {number} shadowmap_atlas
11
23
  * @param {number[]} volumetric_resolution
24
+ * @param {number[]} sun_shadow_resolution voxel counts of one Q-04 sun optical-depth cascade;
25
+ * `[1, 1, 1]` when the froxels are marching instead, which keeps the passes in the graph without
26
+ * doing any work
12
27
  * @param {number} volumetrics_metadata
13
28
  * @param {number} [taa_history] imported previous-frame accumulated scattering volume
14
29
  * @param {number} [taa_output] imported destination for this frame's accumulated scattering volume
15
30
  * @param {GPUCameraContext} [camera_previous] previous-frame camera, for temporal reprojection
16
31
  */
17
- export function graph_build_volumetrics({ graph, camera, lights, view, light_cluster_data, light_cluster_lookup, light_cluster_parameters, shadowmap_atlas, volumetric_resolution, volumetrics_metadata, taa_history, taa_output, camera_previous, }: FrameGraph): {
18
- lut_transmittance: any;
19
- lut_multiple_scattering: any;
32
+ 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, taa_history, taa_output, camera_previous, }: FrameGraph): {
33
+ lut_transmittance: number;
34
+ lut_multiple_scattering: number;
20
35
  lut_aerial: any;
21
36
  volumetrics_metadata: FrameGraph;
22
37
  };
@@ -1 +1 @@
1
- {"version":3,"file":"graph_build_volumetrics.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/volumetrics/graph_build_volumetrics.js"],"names":[],"mappings":"AA6SA;;;;;;;;;;;;;;;GAeG;AACH;;;;;EA0JC"}
1
+ {"version":3,"file":"graph_build_volumetrics.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/volumetrics/graph_build_volumetrics.js"],"names":[],"mappings":"AA4BA;;;;;;;GAOG;AACH,4DAFa;IAAC,iBAAiB,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAC,CAgEjE;AAqTD;;;;;;;;;;;;;;;;;;GAkBG;AACH;;;;;EAwKC"}
@@ -1,25 +1,43 @@
1
-
2
-
3
1
  import { assert } from "../../../core/assert.js";
4
2
  import { SamplerDescriptor } from "../../descriptor/texture/SamplerDescriptor.js";
5
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
+ import { graph_compute_pass } from "../shader/graph/compute/graph_compute_pass.js";
7
+ import { graph_import_buffer } from "../shader/graph/graph_import_buffer.js";
6
8
  import { SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR } from "../shadow/map/SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR.js";
7
9
  import { STATIC_GRAPHICS_ENGINE_ASSETS } from "../STATIC_GRAPHICS_ENGINE_ASSETS.js";
8
10
  import { DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR } from "../texture/DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR.js";
9
- import { graph_compute_pass } from "../shader/graph/compute/graph_compute_pass.js";
10
- import { graph_import_buffer } from "../shader/graph/graph_import_buffer.js";
11
- import { shader_multiscatter_lut } from "../atmosphere/shader_multiscatter_lut.js";
12
- import { shader_transmittance_lut } from "../atmosphere/shader_transmittance_lut.js";
13
- import { shader_volumetrics_build_lighting } from "./shader_volumetrics_build_lighting.js";
11
+ import { volumetrics_sun_shadow_texture_name } from "./chunk_volumetrics_sun_optical_depth.js";
12
+ import {
13
+ shader_volumetrics_build_lighting,
14
+ VOLUMETRICS_LIGHTING_WORKGROUP_RESOLUTION
15
+ } from "./shader_volumetrics_build_lighting.js";
14
16
  import { shader_volumetrics_build_participating_media } from "./shader_volumetrics_build_participating_media.js";
15
17
  import { shader_volumetrics_build_scattering_lut } from "./shader_volumetrics_build_scattering_lut.js";
18
+ import {
19
+ shader_volumetrics_build_sun_shadow_volume_outermost,
20
+ shader_volumetrics_build_sun_shadow_volume_seeded
21
+ } from "./shader_volumetrics_build_sun_shadow_volume.js";
16
22
  import { shader_volumetrics_taa } from "./taa/shader_volumetrics_taa.js";
23
+ import {
24
+ VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT,
25
+ VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION,
26
+ volumetrics_sun_shadow_sub_steps
27
+ } from "./VOLUMETRICS_SUN_SHADOW_RESOLUTION.js";
17
28
 
18
29
  /**
30
+ * Transmittance LUT, then the multiple-scattering LUT that reads it. Exported for
31
+ * `graph_integrate_sky.spec.js`, which pins the dispatch shape and the transient's usage
32
+ * flags -- neither of which the WGSL validity gate can see.
19
33
  *
20
34
  * @param {FrameGraph} graph
35
+ * @returns {{transmittance_lut: number, multiscatted_lut: number}} resource handles
21
36
  */
22
- function graph_integrate_sky({ graph }) {
37
+ export function graph_integrate_sky({ graph }) {
38
+
39
+ graph.push_scope("integrate sky");
40
+
23
41
  const t_data = {};
24
42
 
25
43
  const t_pass = graph.add("transmittance", t_data, (data, resources, context) => {
@@ -31,7 +49,10 @@ function graph_integrate_sky({ graph }) {
31
49
  const settings_type = shader_transmittance_lut.descriptor.resources.getResourceByName("settings").buffer_type;
32
50
 
33
51
  const settings = encoder.allocateTransientValueBuffer(settings_type, {
34
- steps: 40
52
+ steps: 40,
53
+ // taken off the target being drawn into, so the generator cannot be told a size
54
+ // the texture does not have
55
+ resolution: [output.width, output.height],
35
56
  });
36
57
 
37
58
  shader_transmittance_lut.draw({
@@ -53,46 +74,28 @@ function graph_integrate_sky({ graph }) {
53
74
  usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
54
75
  }));
55
76
 
56
- const m_data = {};
57
-
58
- const m_pass = graph.add("multiscatter lut", m_data, (data, resources, context) => {
59
- const output = resources.get(data.output);
60
-
61
- const settings_type = shader_multiscatter_lut.descriptor.resources.getResourceByName("settings").buffer_type;
62
-
63
- const encoder = context.encoder;
64
-
65
- const settings = encoder.allocateTransientValueBuffer(settings_type, {
66
- steps: 20,
67
- sqrt_samples: 8,
68
- });
77
+ // The transient does not exist yet at graph-build time, so the dispatch cannot be
78
+ // counted off it the way GPUSky does; one local value feeds both instead.
79
+ const multiscatter_resolution = [32, 32];
69
80
 
70
- const tSkyLutTransmittance = resources.get(data.tSkyLutTransmittance);
71
-
72
- shader_multiscatter_lut.draw({
73
- encoder: encoder,
74
- bindings: {
75
- settings,
76
- tSkyLutTransmittance
77
- },
78
- colorAttachments: [{
79
- view: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
80
- loadOp: "clear",
81
- storeOp: "store",
82
- }]
83
- })
81
+ const multiscatter_outputs = graph_compute_pass({
82
+ graph,
83
+ shader: shader_multiscatter_lut,
84
+ // one workgroup per LUT texel, each thread integrating one direction
85
+ group_count: [multiscatter_resolution[0], multiscatter_resolution[1], 1],
86
+ bindings: {
87
+ tSkyLutTransmittance: t_data.output,
88
+ tSkyLutMultiscatterOut: TextureResourceDescriptor.from({
89
+ resolution: multiscatter_resolution,
90
+ format: "rgba16float",
91
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING
92
+ })
93
+ }
84
94
  });
85
95
 
86
- m_data.output = m_pass.create("multiscatter lut", TextureResourceDescriptor.from({
87
- resolution: [32, 32],
88
- format: "rgba16float",
89
- usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
90
- }))
91
-
92
- m_data.tSkyLutTransmittance = m_pass.read(t_data.output);
96
+ graph.pop_scope();
93
97
 
94
-
95
- return { transmittance_lut: t_data.output, multiscatted_lut: m_data.output };
98
+ return { transmittance_lut: t_data.output, multiscatted_lut: multiscatter_outputs.tSkyLutMultiscatterOut };
96
99
  }
97
100
 
98
101
 
@@ -182,6 +185,97 @@ function graph_integrate_participating_media({
182
185
  };
183
186
  }
184
187
 
188
+ /**
189
+ * Q-04. The sun's optical depth, integrated once per frame into cascaded light-aligned volumes so
190
+ * the lighting pass can read it in a single fetch instead of marching toward the sun from every
191
+ * froxel.
192
+ *
193
+ * Sits between the participating-media build and the lighting pass because it reads the former and
194
+ * is read by the latter; the frame graph derives that ordering from the handles alone. The cascades
195
+ * are ordered among themselves for the same reason: each one is seeded from the value the cascade
196
+ * outside it already computed at its entry face, so the outermost is built first and the handle it
197
+ * returns is what makes the next pass wait for it.
198
+ *
199
+ * A texture per cascade rather than one texture with the cascades stacked along w. Stacking would
200
+ * put a pass's own output and its input in the same texture, which WebGPU rejects — a subresource
201
+ * cannot be bound as writable storage and as a sampled texture at once — and there is no
202
+ * subresource finer than the whole 3D texture to split it on.
203
+ *
204
+ * Always present, even with the mode off — the volumes are then dispatched at 1x1x1 (see
205
+ * `GPUViewVolumetrics`), which keeps the graph's topology identical on both sides of the A/B. A
206
+ * pass appearing and disappearing would change resource aliasing and pass scheduling along with the
207
+ * thing being measured, and this subsystem has already produced one confident wrong answer from a
208
+ * measurement where the two sides did not pay the same fixed costs.
209
+ *
210
+ * @param {FrameGraph} graph
211
+ * @param {GPUCameraContext} camera
212
+ * @param {number} participating_media1
213
+ * @param {number} volumetrics_metadata
214
+ * @param {number[]} resolution voxel counts of one cascade
215
+ * @returns {number[]} handles of the cascades, innermost first
216
+ */
217
+ function graph_build_sun_shadow_volume({
218
+ graph,
219
+ camera,
220
+ participating_media1,
221
+ volumetrics_metadata,
222
+ resolution,
223
+ }) {
224
+
225
+ const camera_buffer = graph_import_buffer(graph, camera.buffer.buffer, "volumetrics sun shadow camera");
226
+
227
+ const group_count = [
228
+ // one invocation per COLUMN along the sun axis, so only x and y are dispatched
229
+ Math.ceil(resolution[0] / VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION[0]),
230
+ Math.ceil(resolution[1] / VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION[1]),
231
+ 1,
232
+ ];
233
+
234
+ const cascades = [];
235
+
236
+ for (let cascade = VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT - 1; cascade >= 0; cascade--) {
237
+
238
+ // Every cascade but the outermost starts its scan from the one outside it — which the
239
+ // descending loop has already added, and which is the one difference the two build shaders
240
+ // exist for.
241
+ const seeded = cascade < VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT - 1;
242
+
243
+ const bindings = {
244
+ // which cascade this dispatch is building; the shader is shared across all of them
245
+ settings: {
246
+ cascade,
247
+ sub_steps: volumetrics_sun_shadow_sub_steps(cascade),
248
+ },
249
+ camera: camera_buffer,
250
+ volumetrics_metadata,
251
+ tParticipatingMedia1: participating_media1,
252
+ tSunShadowVolume: TextureResourceDescriptor.from({
253
+ resolution,
254
+ dimension: "3d",
255
+ format: "rgba16float",
256
+ usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
257
+ }),
258
+ };
259
+
260
+ if (seeded) {
261
+ bindings.tSunShadowOuter = cascades[cascade + 1];
262
+ }
263
+
264
+ const outputs = graph_compute_pass({
265
+ graph,
266
+ shader: seeded
267
+ ? shader_volumetrics_build_sun_shadow_volume_seeded
268
+ : shader_volumetrics_build_sun_shadow_volume_outermost,
269
+ group_count,
270
+ bindings,
271
+ });
272
+
273
+ cascades[cascade] = outputs.tSunShadowVolume;
274
+ }
275
+
276
+ return cascades;
277
+ }
278
+
185
279
  /**
186
280
  *
187
281
  * @param {FrameGraph} graph
@@ -194,6 +288,7 @@ function graph_integrate_participating_media({
194
288
  * @param shadowmap_atlas
195
289
  * @param sun_transmittance_lut
196
290
  * @param sun_multiple_scattering_lut
291
+ * @param {number[]} sun_shadow_cascades handles of the Q-04 optical-depth cascades, innermost first
197
292
  * @param lights
198
293
  * @param view
199
294
  * @param camera
@@ -210,6 +305,7 @@ function graph_integrate_light_scattering({
210
305
  shadowmap_atlas,
211
306
  sun_transmittance_lut,
212
307
  sun_multiple_scattering_lut,
308
+ sun_shadow_cascades,
213
309
  lights,
214
310
  view,
215
311
  camera,
@@ -233,6 +329,7 @@ function graph_integrate_light_scattering({
233
329
 
234
330
  const sun_transmittance_lut = resources.get(data.sun_transmittance_lut);
235
331
  const sun_multiple_scattering_lut = resources.get(data.sun_multiple_scattering_lut);
332
+ const sun_shadow_cascades = data.sun_shadow_cascades.map(handle => resources.get(handle));
236
333
 
237
334
  const sampler_shadowmap = context.graphics.samplers.obtain(SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR);
238
335
  const sLinear = context.graphics.samplers.obtain(SamplerDescriptor.from({
@@ -246,32 +343,40 @@ function graph_integrate_light_scattering({
246
343
 
247
344
  const encoder = context.encoder;
248
345
 
346
+ const bindings = {
347
+ camera: camera.buffer.buffer,
348
+ view: view.uniform_buffer.buffer,
349
+ volumetrics_metadata,
350
+ sLinear,
351
+ tSunTransmittance: sun_transmittance_lut.obtainView(),
352
+ tMultiScattering: sun_multiple_scattering_lut.obtainView(),
353
+ tSTBN_vec3: tSTBN_vec3.obtainView(),
354
+ tParticipatingMedia0: participating_media0.obtainView(),
355
+ tParticipatingMedia1: participating_media1.obtainView(),
356
+ tLighting: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
357
+ //
358
+ light_data: lights.buffer_data,
359
+
360
+ cluster_data: light_cluster_data,
361
+ cluster_lookup: light_cluster_lookup,
362
+ cluster_parameters: light_cluster_parameters,
363
+
364
+ shadowmapAtlas: shadowmap_atlas.obtainView(),
365
+ sCompareLinear: sampler_shadowmap,
366
+ };
367
+
368
+ // One texture per cascade, under the names the read side declares. Bound here rather than
369
+ // above because the count is a constant of the structure, not of this pass.
370
+ for (let cascade = 0; cascade < sun_shadow_cascades.length; cascade++) {
371
+ bindings[volumetrics_sun_shadow_texture_name(cascade)] = sun_shadow_cascades[cascade].obtainView();
372
+ }
373
+
249
374
  shader_volumetrics_build_lighting.dispatch({
250
375
  encoder,
251
- group_count_x: Math.ceil(output.width / 16),
252
- group_count_y: Math.ceil(output.height / 16),
253
- group_count_z: output.depth,
254
- bindings: {
255
- camera: camera.buffer.buffer,
256
- view: view.uniform_buffer.buffer,
257
- volumetrics_metadata,
258
- sLinear,
259
- tSunTransmittance: sun_transmittance_lut.obtainView(),
260
- tMultiScattering: sun_multiple_scattering_lut.obtainView(),
261
- tSTBN_vec3: tSTBN_vec3.obtainView(),
262
- tParticipatingMedia0: participating_media0.obtainView(),
263
- tParticipatingMedia1: participating_media1.obtainView(),
264
- tLighting: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
265
- //
266
- light_data: lights.buffer_data,
267
-
268
- cluster_data: light_cluster_data,
269
- cluster_lookup: light_cluster_lookup,
270
- cluster_parameters: light_cluster_parameters,
271
-
272
- shadowmapAtlas: shadowmap_atlas.obtainView(),
273
- sCompareLinear: sampler_shadowmap,
274
- }
376
+ group_count_x: Math.ceil(output.width / VOLUMETRICS_LIGHTING_WORKGROUP_RESOLUTION[0]),
377
+ group_count_y: Math.ceil(output.height / VOLUMETRICS_LIGHTING_WORKGROUP_RESOLUTION[1]),
378
+ group_count_z: Math.ceil(output.depth / VOLUMETRICS_LIGHTING_WORKGROUP_RESOLUTION[2]),
379
+ bindings
275
380
  })
276
381
  });
277
382
 
@@ -286,6 +391,7 @@ function graph_integrate_light_scattering({
286
391
 
287
392
  data.sun_transmittance_lut = pass.read(sun_transmittance_lut);
288
393
  data.sun_multiple_scattering_lut = pass.read(sun_multiple_scattering_lut);
394
+ data.sun_shadow_cascades = sun_shadow_cascades.map(handle => pass.read(handle));
289
395
 
290
396
  data.output = pass.create("Light Scattering LUT", TextureResourceDescriptor.from({
291
397
  resolution,
@@ -310,6 +416,9 @@ function graph_integrate_light_scattering({
310
416
  * @param {number} light_cluster_parameters
311
417
  * @param {number} shadowmap_atlas
312
418
  * @param {number[]} volumetric_resolution
419
+ * @param {number[]} sun_shadow_resolution voxel counts of one Q-04 sun optical-depth cascade;
420
+ * `[1, 1, 1]` when the froxels are marching instead, which keeps the passes in the graph without
421
+ * doing any work
313
422
  * @param {number} volumetrics_metadata
314
423
  * @param {number} [taa_history] imported previous-frame accumulated scattering volume
315
424
  * @param {number} [taa_output] imported destination for this frame's accumulated scattering volume
@@ -325,6 +434,7 @@ export function graph_build_volumetrics({
325
434
  light_cluster_parameters,
326
435
  shadowmap_atlas,
327
436
  volumetric_resolution,
437
+ sun_shadow_resolution,
328
438
  volumetrics_metadata,
329
439
  taa_history,
330
440
  taa_output,
@@ -333,6 +443,9 @@ export function graph_build_volumetrics({
333
443
 
334
444
  assert.defined(view, 'view');
335
445
  assert.defined(volumetric_resolution, 'volumetric_resolution');
446
+ assert.defined(sun_shadow_resolution, 'sun_shadow_resolution');
447
+
448
+ graph.push_scope("build volumetrics");
336
449
 
337
450
  const { transmittance_lut, multiscatted_lut } = graph_integrate_sky({ graph: graph });
338
451
 
@@ -348,6 +461,14 @@ export function graph_build_volumetrics({
348
461
  camera,
349
462
  });
350
463
 
464
+ const sun_shadow_cascades = graph_build_sun_shadow_volume({
465
+ graph,
466
+ camera,
467
+ participating_media1,
468
+ volumetrics_metadata,
469
+ resolution: sun_shadow_resolution,
470
+ });
471
+
351
472
  const light_scattering_lut = graph_integrate_light_scattering({
352
473
  graph,
353
474
  resolution: volumetric_resolution,
@@ -355,6 +476,7 @@ export function graph_build_volumetrics({
355
476
  view,
356
477
  sun_transmittance_lut: transmittance_lut,
357
478
  sun_multiple_scattering_lut: multiscatted_lut,
479
+ sun_shadow_cascades,
358
480
  participating_media0,
359
481
  participating_media1,
360
482
  volumetrics_metadata,
@@ -409,7 +531,6 @@ export function graph_build_volumetrics({
409
531
 
410
532
 
411
533
  const graphics = context.graphics;
412
- const device = graphics.device;
413
534
 
414
535
  const sLinear = graphics.samplers.obtain(SamplerDescriptor.from({
415
536
  magFilter: "linear",
@@ -463,6 +584,8 @@ export function graph_build_volumetrics({
463
584
 
464
585
  // TODO add temporal reprojection
465
586
 
587
+ graph.pop_scope();
588
+
466
589
  return {
467
590
  lut_transmittance: transmittance_lut,
468
591
  lut_multiple_scattering: multiscatted_lut,
@@ -1,3 +1,19 @@
1
+ /**
2
+ * Workgroup shape of this pass, `[x, y, z]` in froxels, read by both the `@workgroup_size` below
3
+ * and the dispatch in `graph_build_volumetrics` so the two cannot drift.
4
+ *
5
+ * Flat in z. Lights are binned into 3D clusters and the largest distance between neighbouring
6
+ * clusters is along depth, so a group spanning z is the one spanning the most unrelated light
7
+ * lists.
8
+ *
9
+ * 64 invocations — one wave64, two warps — is a deliberate trade: 16x16x1 measures faster on the
10
+ * RTX 4090 this was benchmarked on, and is kept off because that part's register file is unusually
11
+ * large and the result is not expected to generalize (AMD favours smaller groups). NOTES.md carries
12
+ * the numbers and the reasoning.
13
+ *
14
+ * @type {number[]}
15
+ */
16
+ export const VOLUMETRICS_LIGHTING_WORKGROUP_RESOLUTION: number[];
1
17
  export const shader_volumetrics_build_lighting: ComputeShader;
2
18
  import { ComputeShader } from "../shader/ComputeShader.js";
3
19
  //# sourceMappingURL=shader_volumetrics_build_lighting.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shader_volumetrics_build_lighting.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js"],"names":[],"mappings":"AA0WA,8DAIE;8BA1V4B,4BAA4B"}
1
+ {"version":3,"file":"shader_volumetrics_build_lighting.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js"],"names":[],"mappings":"AA6CA;;;;;;;;;;;;;;GAcG;AACH,wDAFU,MAAM,EAAE,CAEiD;AAkXnE,8DAIE;8BA9Z4B,4BAA4B"}