@woosh/meep-engine 3.11.2 → 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 (168) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.d.ts +16 -2
  4. package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.d.ts.map +1 -1
  5. package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.js +28 -4
  6. package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.d.ts +1 -1
  7. package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.d.ts.map +1 -1
  8. package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.js +5 -2
  9. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +564 -451
  10. package/src/shade/device/ShadeGPUCommandContext.d.ts +18 -2
  11. package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
  12. package/src/shade/device/ShadeGPUCommandContext.js +994 -940
  13. package/src/shade/device/immediate_data_supported.d.ts +33 -0
  14. package/src/shade/device/immediate_data_supported.d.ts.map +1 -0
  15. package/src/shade/device/immediate_data_supported.js +53 -0
  16. package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts +18 -0
  17. package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts.map +1 -1
  18. package/src/shade/device/mock/SoftwareGPUCommandEncoder.js +24 -0
  19. package/src/shade/device/mock/SoftwareGPUComputePassEncoder.d.ts +7 -0
  20. package/src/shade/device/mock/SoftwareGPUComputePassEncoder.d.ts.map +1 -1
  21. package/src/shade/device/mock/SoftwareGPUComputePassEncoder.js +49 -1
  22. package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
  23. package/src/shade/device/mock/SoftwareGPUDevice.js +20 -2
  24. package/src/shade/device/mock/SoftwareGPUImmediateData.d.ts +65 -0
  25. package/src/shade/device/mock/SoftwareGPUImmediateData.d.ts.map +1 -0
  26. package/src/shade/device/mock/SoftwareGPUImmediateData.js +160 -0
  27. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts +7 -0
  28. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts.map +1 -1
  29. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.js +50 -0
  30. package/src/shade/device/mock/pipeline_immediate_size.d.ts +11 -0
  31. package/src/shade/device/mock/pipeline_immediate_size.d.ts.map +1 -0
  32. package/src/shade/device/mock/pipeline_immediate_size.js +18 -0
  33. package/src/shade/device/pipeline/PipelineLayoutManager.d.ts.map +1 -1
  34. package/src/shade/device/pipeline/PipelineLayoutManager.js +1 -0
  35. package/src/shade/renderer/GraphicsContext.d.ts +9 -2
  36. package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
  37. package/src/shade/renderer/GraphicsContext.js +13 -1
  38. package/src/shade/renderer/atmosphere/GPUSky.d.ts.map +1 -1
  39. package/src/shade/renderer/atmosphere/GPUSky.js +145 -142
  40. package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.d.ts +34 -0
  41. package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.d.ts.map +1 -0
  42. package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.js +36 -0
  43. package/src/shade/renderer/atmosphere/SAMPLER_SKY_LUT.d.ts +20 -0
  44. package/src/shade/renderer/atmosphere/SAMPLER_SKY_LUT.d.ts.map +1 -0
  45. package/src/shade/renderer/atmosphere/SAMPLER_SKY_LUT.js +25 -0
  46. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts +14 -1
  47. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts.map +1 -1
  48. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.js +163 -177
  49. package/src/shade/renderer/atmosphere/chunk_multiscatter_sample_direction.d.ts +20 -0
  50. package/src/shade/renderer/atmosphere/chunk_multiscatter_sample_direction.d.ts.map +1 -0
  51. package/src/shade/renderer/atmosphere/chunk_multiscatter_sample_direction.js +46 -0
  52. package/src/shade/renderer/atmosphere/chunk_sample_multiscatter_lut.d.ts +11 -1
  53. package/src/shade/renderer/atmosphere/chunk_sample_multiscatter_lut.d.ts.map +1 -1
  54. package/src/shade/renderer/atmosphere/chunk_sample_multiscatter_lut.js +57 -27
  55. package/src/shade/renderer/atmosphere/chunk_sample_transmittance_lut.d.ts +19 -1
  56. package/src/shade/renderer/atmosphere/chunk_sample_transmittance_lut.d.ts.map +1 -1
  57. package/src/shade/renderer/atmosphere/chunk_sample_transmittance_lut.js +69 -33
  58. package/src/shade/renderer/atmosphere/chunk_sky_lut_compute_uv.d.ts +13 -0
  59. package/src/shade/renderer/atmosphere/chunk_sky_lut_compute_uv.d.ts.map +1 -1
  60. package/src/shade/renderer/atmosphere/chunk_sky_lut_compute_uv.js +35 -35
  61. package/src/shade/renderer/atmosphere/chunk_sky_lut_params.d.ts +13 -0
  62. package/src/shade/renderer/atmosphere/chunk_sky_lut_params.d.ts.map +1 -0
  63. package/src/shade/renderer/atmosphere/chunk_sky_lut_params.js +38 -0
  64. package/src/shade/renderer/atmosphere/chunk_sky_lut_texel_to_unit.d.ts +17 -0
  65. package/src/shade/renderer/atmosphere/chunk_sky_lut_texel_to_unit.d.ts.map +1 -0
  66. package/src/shade/renderer/atmosphere/chunk_sky_lut_texel_to_unit.js +29 -0
  67. package/src/shade/renderer/atmosphere/chunk_sky_lut_uv.d.ts +21 -0
  68. package/src/shade/renderer/atmosphere/chunk_sky_lut_uv.d.ts.map +1 -0
  69. package/src/shade/renderer/atmosphere/chunk_sky_lut_uv.js +42 -0
  70. package/src/shade/renderer/atmosphere/shader_multiscatter_lut.d.ts +2 -2
  71. package/src/shade/renderer/atmosphere/shader_multiscatter_lut.d.ts.map +1 -1
  72. package/src/shade/renderer/atmosphere/shader_multiscatter_lut.js +165 -84
  73. package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.d.ts.map +1 -1
  74. package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.js +215 -204
  75. package/src/shade/renderer/atmosphere/shader_transmittance_lut.d.ts.map +1 -1
  76. package/src/shade/renderer/atmosphere/shader_transmittance_lut.js +79 -67
  77. package/src/shade/renderer/light/cluster/graph_assign_clsuters.d.ts.map +1 -1
  78. package/src/shade/renderer/light/cluster/graph_assign_clsuters.js +6 -2
  79. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
  80. package/src/shade/renderer/postprocess/gtao/GTAO.js +4 -0
  81. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  82. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +341 -345
  83. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +0 -2
  84. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
  85. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +58 -57
  86. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
  87. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +7 -3
  88. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
  89. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +77 -81
  90. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
  91. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +5 -1
  92. package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
  93. package/src/shade/renderer/shader/ComputeShader.js +6 -2
  94. package/src/shade/renderer/shader/ImageShader.d.ts.map +1 -1
  95. package/src/shade/renderer/shader/ImageShader.js +4 -1
  96. package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
  97. package/src/shade/renderer/shader/ShaderDescriptor.js +26 -0
  98. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_RADII_DECLARATION.d.ts +18 -0
  99. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_RADII_DECLARATION.d.ts.map +1 -0
  100. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_RADII_DECLARATION.js +32 -0
  101. package/src/shade/renderer/shader/chunk/atmosphere/PLANET_CENTER_DECLARATION.d.ts +7 -0
  102. package/src/shade/renderer/shader/chunk/atmosphere/PLANET_CENTER_DECLARATION.d.ts.map +1 -1
  103. package/src/shade/renderer/shader/chunk/atmosphere/PLANET_CENTER_DECLARATION.js +17 -6
  104. package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_ray_bounds.d.ts +21 -0
  105. package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_ray_bounds.d.ts.map +1 -0
  106. package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_ray_bounds.js +69 -0
  107. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_contains_aabb3.d.ts +9 -0
  108. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_contains_aabb3.d.ts.map +1 -0
  109. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_contains_aabb3.js +22 -0
  110. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_from_transformed_corners.d.ts +16 -0
  111. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_from_transformed_corners.d.ts.map +1 -0
  112. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_from_transformed_corners.js +41 -0
  113. package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_m4.d.ts +11 -0
  114. package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_m4.d.ts.map +1 -1
  115. package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_m4.js +15 -19
  116. package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_plane_matrix.d.ts +23 -0
  117. package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_plane_matrix.d.ts.map +1 -0
  118. package/src/shade/renderer/shader/chunk/geometry/frustum/chunk_frustum_transform_plane_matrix.js +44 -0
  119. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_uv_octahedral_unit_decode.d.ts.map +1 -1
  120. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_uv_octahedral_unit_decode.js +1 -4
  121. package/src/shade/renderer/shader/compiler/CodeChunk.d.ts +7 -1
  122. package/src/shade/renderer/shader/compiler/CodeChunk.d.ts.map +1 -1
  123. package/src/shade/renderer/shader/compiler/CodeChunk.js +37 -2
  124. package/src/shade/renderer/shader/graph/compute/compute_binding_read_names.d.ts.map +1 -1
  125. package/src/shade/renderer/shader/graph/compute/compute_binding_read_names.js +6 -0
  126. package/src/shade/renderer/shader/graph/compute/graph_compute_indirect_pass.js +1 -1
  127. package/src/shade/renderer/shader/graph/compute/graph_compute_pass.js +1 -1
  128. package/src/shade/renderer/shader/graph/graph_image_pass.js +1 -1
  129. package/src/shade/renderer/shader/graph/graph_prepare_bindings.d.ts.map +1 -1
  130. package/src/shade/renderer/shader/graph/graph_prepare_bindings.js +7 -0
  131. package/src/shade/renderer/shader/graph/graph_prepare_pass_input_data.d.ts +3 -1
  132. package/src/shade/renderer/shader/graph/graph_prepare_pass_input_data.d.ts.map +1 -1
  133. package/src/shade/renderer/shader/graph/graph_prepare_pass_input_data.js +12 -1
  134. package/src/shade/renderer/shader/pass/RenderPassDescriptor.d.ts.map +1 -1
  135. package/src/shade/renderer/shader/pass/RenderPassDescriptor.js +1 -0
  136. package/src/shade/renderer/shader/resource/IMMEDIATE_DATA.d.ts +21 -0
  137. package/src/shade/renderer/shader/resource/IMMEDIATE_DATA.d.ts.map +1 -0
  138. package/src/shade/renderer/shader/resource/IMMEDIATE_DATA.js +21 -0
  139. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts +59 -1
  140. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  141. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +195 -2
  142. package/src/shade/renderer/shader/type/type_has_arrays.d.ts +14 -0
  143. package/src/shade/renderer/shader/type/type_has_arrays.d.ts.map +1 -0
  144. package/src/shade/renderer/shader/type/type_has_arrays.js +33 -0
  145. package/src/shade/renderer/view/GPUViewSkyContext.d.ts.map +1 -1
  146. package/src/shade/renderer/view/GPUViewSkyContext.js +169 -173
  147. package/src/shade/renderer/volumetrics/NOTES.md +238 -0
  148. package/src/shade/renderer/volumetrics/chunk_volumetrics_local_light_shadow.js +145 -145
  149. package/src/shade/renderer/volumetrics/chunk_volumetrics_sun_optical_depth.d.ts.map +1 -1
  150. package/src/shade/renderer/volumetrics/chunk_volumetrics_sun_optical_depth.js +38 -15
  151. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +14 -2
  152. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
  153. package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +594 -577
  154. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts +16 -0
  155. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  156. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +19 -2
  157. package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.d.ts.map +1 -1
  158. package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.js +29 -18
  159. package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.js +260 -260
  160. package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.d.ts +53 -3
  161. package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.d.ts.map +1 -1
  162. package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.js +175 -59
  163. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +8 -1
  164. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  165. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +1325 -1297
  166. package/src/shade/renderer/volumetrics/VOLUMETRICS_WORKGROUP_RESOLUTION.d.ts +0 -2
  167. package/src/shade/renderer/volumetrics/VOLUMETRICS_WORKGROUP_RESOLUTION.d.ts.map +0 -1
  168. package/src/shade/renderer/volumetrics/VOLUMETRICS_WORKGROUP_RESOLUTION.js +0 -1
@@ -1,14 +1,13 @@
1
1
  import { CAMERA_UNIFORM_STRUCT } from "../camera/CAMERA_UNIFORM_STRUCT.js";
2
+ import { chunk_texel_coordinate_to_uv } from "../shader/chunk/texture/chunk_texel_coordinate_to_uv.js";
2
3
  import { CodeChunk } from "../shader/compiler/CodeChunk.js";
3
4
  import { ComputeShader } from "../shader/ComputeShader.js";
4
5
  import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
6
+ import { u32 } from "../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
7
+ import { WebGPUStruct } from "../shader/type/WebGPUStruct.js";
5
8
  import { SAMPLER_LINEAR_UPSCALE } from "../texture/SAMPLER_LINEAR_UPSCALE.js";
6
9
  import { chunk_volumetrics_sample_froxel_extinction } from "./chunk_volumetrics_sample_froxel_extinction.js";
7
- import {
8
- VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT,
9
- VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION,
10
- volumetrics_sun_shadow_sub_steps
11
- } from "./VOLUMETRICS_SUN_SHADOW_RESOLUTION.js";
10
+ import { VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION } from "./VOLUMETRICS_SUN_SHADOW_RESOLUTION.js";
12
11
  import { VOLUMETRICS_METADATA_STRUCT } from "./VOLUMETRICS_METADATA_STRUCT.js";
13
12
 
14
13
  /**
@@ -30,37 +29,166 @@ import { VOLUMETRICS_METADATA_STRUCT } from "./VOLUMETRICS_METADATA_STRUCT.js";
30
29
  * with ringing at sharp density transitions. This engine's medium is already a 3D texture with a
31
30
  * defined order along any axis, so the scan is available, exact, and has nothing to ring.
32
31
  *
33
- * One shader per cascade rather than one shader taking a cascade index, because the two things that
34
- * vary which cascade's transform to read, and whether there is an outer cascade to start from —
35
- * both change the *bindings*, and a variant that declares an outer texture it never samples would
36
- * have to be handed one.
32
+ * Two shaders, written out: the outermost cascade, whose scan starts at zero, and every cascade
33
+ * inside it, whose scan starts from the cascade outside. That is a difference in *bindings* the
34
+ * second reads a texture the first does not have so it cannot be data. Which cascade is being
35
+ * built can be, and is: it arrives as immediate data, so the inner cascades share one pipeline.
37
36
  *
38
- * @param {number} index innermost cascade is 0
39
- * @returns {ComputeShader}
40
37
  * @see chunk_volumetrics_sun_optical_depth for the read side
41
38
  * @see build_volumetrics_sun_shadow_transform for where each box is placed, and why it is stable
42
39
  */
43
- function make_shader(index) {
44
40
 
45
- const seeded = index < VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT - 1;
41
+ /**
42
+ * Which cascade a dispatch is building.
43
+ *
44
+ * Per-dispatch, uniform, read-only and eight bytes, which is the shape immediate data exists for:
45
+ * no pooled buffer, no staging copy, no bind group.
46
+ *
47
+ * `sub_steps` travels with it rather than being derived in the shader because it is a property of
48
+ * the cascade ladder rather than of the box: {@link volumetrics_sun_shadow_sub_steps} is where the
49
+ * rule that it is even and at least two lives, and nothing in the metadata lets the shader
50
+ * re-derive it.
51
+ *
52
+ * @type {WebGPUStruct}
53
+ */
54
+ export const VOLUMETRICS_SUN_SHADOW_BUILD_SETTINGS = WebGPUStruct.from({
55
+ cascade: u32,
56
+ sub_steps: u32,
57
+ }, 'VolumetricsSunShadowBuildSettings');
58
+
59
+ const outermost_resources = new ShaderResourceSetDescriptor();
46
60
 
47
- const sub_steps = volumetrics_sun_shadow_sub_steps(index);
61
+ outermost_resources.setImmediate("settings", VOLUMETRICS_SUN_SHADOW_BUILD_SETTINGS);
48
62
 
49
- const resources = new ShaderResourceSetDescriptor();
63
+ outermost_resources.createGroup()
64
+ .addUniform("volumetrics_metadata", VOLUMETRICS_METADATA_STRUCT)
65
+ .addUniform("camera", CAMERA_UNIFORM_STRUCT)
66
+ .addSampler("sLinear", "filtering", SAMPLER_LINEAR_UPSCALE)
67
+ .addTexture("tParticipatingMedia1", "float", "3d")
68
+ .addStorageTexture("tSunShadowVolume", "rgba16float", "3d", "write-only");
50
69
 
51
- const group = resources.createGroup()
52
- .addUniform("volumetrics_metadata", VOLUMETRICS_METADATA_STRUCT)
53
- .addUniform("camera", CAMERA_UNIFORM_STRUCT)
54
- .addSampler("sLinear", "filtering", SAMPLER_LINEAR_UPSCALE)
55
- .addTexture("tParticipatingMedia1", "float", "3d");
70
+ /**
71
+ * The outermost cascade. Nothing is outside it, so its scan starts from zero and it binds no outer
72
+ * volume.
73
+ *
74
+ * @type {ComputeShader}
75
+ */
76
+ export const shader_volumetrics_build_sun_shadow_volume_outermost = ComputeShader.from({
77
+ label: 'Volumetrics / build sun shadow volume (outermost)',
78
+ resources: outermost_resources,
79
+ body: CodeChunk.from(
80
+ //language=WGSL
81
+ `
82
+ @compute @workgroup_size(${VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION.join(",")})
83
+ fn main(
84
+ @builtin(global_invocation_id) column : vec3<u32>
85
+ ){
86
+ let resolution = textureDimensions(tSunShadowVolume);
56
87
 
57
- if (seeded) {
58
- group.addTexture("tSunShadowOuter", "float", "3d");
88
+ if(any(column.xy >= resolution.xy)){
89
+ // overflow
90
+ return;
59
91
  }
60
92
 
61
- group.addStorageTexture("tSunShadowVolume", "rgba16float", "3d", "write-only");
93
+ // The volume's z axis is the direction light TRAVELS, so this column is one sun ray and slice 0
94
+ // is its end nearest the sun. Walking it in order turns the per-froxel integral into a running
95
+ // sum: every voxel's optical depth is its predecessor's plus one slab. That is the whole point
96
+ // of the pass — the same information the 16-step march produces, in O(voxels) instead of
97
+ // O(froxels * steps), and produced once rather than once per froxel that happens to lie on the
98
+ // ray.
99
+ //
100
+ // One invocation per column rather than a cooperative scan. The dependency chain is one
101
+ // cascade's depth long and each link is a texture fetch, so a Hillis-Steele or Blinn-Sengupta
102
+ // scan would trade this pass's perfectly coherent, register-resident accumulator for log(n)
103
+ // rounds of shared memory and barriers to speed up something that is already bandwidth-bound.
104
+ // The aerial pass has the same shape for the same reason.
105
+ //
106
+ // Immediate data, so this is uniform across the dispatch.
107
+ let cascade = settings.cascade;
108
+
109
+ let uvw_to_ws = volumetrics_metadata.sun_shadow_uvw_to_ws[cascade];
110
+
111
+ // What a voxel must hold is the medium's INTEGRAL across its slab, not the medium's value at
112
+ // its centre, and one point sample per voxel is not that. A fog volume three units thick
113
+ // crossed by a 2.3-unit lattice has its entire optical depth resting on one or two samples:
114
+ // whether they land inside it, on its fade, or just outside swings the answer by the whole
115
+ // shadow, and the per-frame column jitter under them turns that into a strobe.
116
+ //
117
+ // So sample the slab several times and store the storage-resolution result. The sampling rate
118
+ // and the resolution are separate knobs and only the first one has to beat the medium's
119
+ // features. The count is per cascade — see volumetrics_sun_shadow_sub_steps — so that every
120
+ // cascade samples at the same world-space spacing rather than at the same count per voxel.
121
+ let sub_steps = settings.sub_steps;
122
+
123
+ let sub_steps_half = sub_steps / 2u;
124
+
125
+ let sub_step_ws = volumetrics_metadata.sun_shadow_step_ws[cascade] / f32(sub_steps);
126
+
127
+ let w_per_slice = 1.0 / f32(resolution.z);
128
+ let w_per_sub_step = w_per_slice / f32(sub_steps);
129
+
130
+ let column_uv = texel_coordinate_to_uv(vec2<f32>(column.xy), resolution.xy);
62
131
 
63
- const body = CodeChunk.from(
132
+ // The outermost cascade's box contains the whole frustum, and the medium exists only inside
133
+ // the frustum, so the slab its scan starts on is empty and zero is the whole of the truth about
134
+ // what is between it and the sun.
135
+ var optical_depth = vec3<f32>(0.0);
136
+
137
+ for(var slice = 0u; slice < resolution.z; slice++){
138
+
139
+ let voxel = vec3<u32>(column.xy, slice);
140
+
141
+ let w_slice = f32(slice) * w_per_slice;
142
+
143
+ for(var sub = 0u; sub < sub_steps; sub++){
144
+
145
+ // Halfway through the slab, so the value stored at slice k is the integral from the
146
+ // box's sun-side face to the voxel's CENTRE. Linear interpolation between two stored
147
+ // values then reproduces the true integral exactly wherever extinction is constant
148
+ // across the pair. Storing the integral to the far face instead — a right-endpoint sum,
149
+ // which is what the march this replaces does — biases every reading by half a slab.
150
+ if(sub == sub_steps_half){
151
+ textureStore(tSunShadowVolume, voxel, vec4<f32>(optical_depth, 0.0));
152
+ }
153
+
154
+ let w = w_slice + (f32(sub) + 0.5) * w_per_sub_step;
155
+
156
+ let position_ws = (uvw_to_ws * vec4<f32>(column_uv, w, 1.0)).xyz;
157
+
158
+ optical_depth += volumetrics_sample_froxel_extinction(position_ws) * sub_step_ws;
159
+ }
160
+ }
161
+ }
162
+ `, [
163
+ CAMERA_UNIFORM_STRUCT.declaration_chunk,
164
+ chunk_texel_coordinate_to_uv,
165
+ chunk_volumetrics_sample_froxel_extinction,
166
+ ]
167
+ )
168
+ });
169
+
170
+ const seeded_resources = new ShaderResourceSetDescriptor();
171
+
172
+ seeded_resources.setImmediate("settings", VOLUMETRICS_SUN_SHADOW_BUILD_SETTINGS);
173
+
174
+ seeded_resources.createGroup()
175
+ .addUniform("volumetrics_metadata", VOLUMETRICS_METADATA_STRUCT)
176
+ .addUniform("camera", CAMERA_UNIFORM_STRUCT)
177
+ .addSampler("sLinear", "filtering", SAMPLER_LINEAR_UPSCALE)
178
+ .addTexture("tParticipatingMedia1", "float", "3d")
179
+ .addTexture("tSunShadowOuter", "float", "3d")
180
+ .addStorageTexture("tSunShadowVolume", "rgba16float", "3d", "write-only");
181
+
182
+ /**
183
+ * Every cascade but the outermost, seeded from the one outside it. Which one that is arrives as
184
+ * immediate data, so the whole inner ladder shares this pipeline.
185
+ *
186
+ * @type {ComputeShader}
187
+ */
188
+ export const shader_volumetrics_build_sun_shadow_volume_seeded = ComputeShader.from({
189
+ label: 'Volumetrics / build sun shadow volume (seeded)',
190
+ resources: seeded_resources,
191
+ body: CodeChunk.from(
64
192
  //language=WGSL
65
193
  `
66
194
  @compute @workgroup_size(${VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION.join(",")})
@@ -86,9 +214,11 @@ fn main(
86
214
  // scan would trade this pass's perfectly coherent, register-resident accumulator for log(n)
87
215
  // rounds of shared memory and barriers to speed up something that is already bandwidth-bound.
88
216
  // The aerial pass has the same shape for the same reason.
89
- const CASCADE = ${index}u;
217
+ //
218
+ // Immediate data, so this is uniform across the dispatch.
219
+ let cascade = settings.cascade;
90
220
 
91
- let uvw_to_ws = volumetrics_metadata.sun_shadow_uvw_to_ws[CASCADE];
221
+ let uvw_to_ws = volumetrics_metadata.sun_shadow_uvw_to_ws[cascade];
92
222
 
93
223
  // What a voxel must hold is the medium's INTEGRAL across its slab, not the medium's value at
94
224
  // its centre, and one point sample per voxel is not that. A fog volume three units thick
@@ -100,17 +230,18 @@ fn main(
100
230
  // and the resolution are separate knobs and only the first one has to beat the medium's
101
231
  // features. The count is per cascade — see volumetrics_sun_shadow_sub_steps — so that every
102
232
  // cascade samples at the same world-space spacing rather than at the same count per voxel.
103
- const SUB_STEPS = ${sub_steps}u;
233
+ let sub_steps = settings.sub_steps;
104
234
 
105
- let sub_step_ws = volumetrics_metadata.sun_shadow_step_ws[CASCADE] / f32(SUB_STEPS);
235
+ let sub_steps_half = sub_steps / 2u;
106
236
 
107
- let column_uv = vec2<f32>(
108
- (f32(column.x) + 0.5) / f32(resolution.x),
109
- (f32(column.y) + 0.5) / f32(resolution.y)
110
- );
237
+ let sub_step_ws = volumetrics_metadata.sun_shadow_step_ws[cascade] / f32(sub_steps);
111
238
 
112
- ${seeded
113
- ? ` // Seeded from the cascade outside this one, at the world position where this column enters
239
+ let w_per_slice = 1.0 / f32(resolution.z);
240
+ let w_per_sub_step = w_per_slice / f32(sub_steps);
241
+
242
+ let column_uv = texel_coordinate_to_uv(vec2<f32>(column.xy), resolution.xy);
243
+
244
+ // Seeded from the cascade outside this one, at the world position where this column enters
114
245
  // this box. Everything between the sun and that plane has already been integrated out there, at
115
246
  // that cascade's resolution, so the scan here starts from it rather than from zero and an inner
116
247
  // cascade is a refinement of the outer rather than a truncation of the medium. Enshrouded
@@ -121,30 +252,28 @@ ${seeded
121
252
  // sub-frustum of it.
122
253
  let entry_ws = (uvw_to_ws * vec4<f32>(column_uv, 0.0, 1.0)).xyz;
123
254
 
124
- let outer_uvw = (volumetrics_metadata.sun_shadow_ws_to_uvw[CASCADE + 1u] * vec4<f32>(entry_ws, 1.0)).xyz;
255
+ let outer_uvw = (volumetrics_metadata.sun_shadow_ws_to_uvw[cascade + 1u] * vec4<f32>(entry_ws, 1.0)).xyz;
125
256
 
126
- var optical_depth = textureSampleLevel(tSunShadowOuter, sLinear, saturate(outer_uvw), 0.0).rgb;`
127
- : ` // The outermost cascade's box contains the whole frustum, and the medium exists only inside
128
- // the frustum, so the slab its scan starts on is empty and zero is the whole of the truth about
129
- // what is between it and the sun.
130
- var optical_depth = vec3<f32>(0.0);`}
257
+ var optical_depth = textureSampleLevel(tSunShadowOuter, sLinear, saturate(outer_uvw), 0.0).rgb;
131
258
 
132
259
  for(var slice = 0u; slice < resolution.z; slice++){
133
260
 
134
261
  let voxel = vec3<u32>(column.xy, slice);
135
262
 
136
- for(var sub = 0u; sub < SUB_STEPS; sub++){
263
+ let w_slice = f32(slice) * w_per_slice;
264
+
265
+ for(var sub = 0u; sub < sub_steps; sub++){
137
266
 
138
267
  // Halfway through the slab, so the value stored at slice k is the integral from the
139
268
  // box's sun-side face to the voxel's CENTRE. Linear interpolation between two stored
140
269
  // values then reproduces the true integral exactly wherever extinction is constant
141
270
  // across the pair. Storing the integral to the far face instead — a right-endpoint sum,
142
271
  // which is what the march this replaces does — biases every reading by half a slab.
143
- if(sub == SUB_STEPS / 2u){
272
+ if(sub == sub_steps_half){
144
273
  textureStore(tSunShadowVolume, voxel, vec4<f32>(optical_depth, 0.0));
145
274
  }
146
275
 
147
- let w = (f32(slice) + (f32(sub) + 0.5) / f32(SUB_STEPS)) / f32(resolution.z);
276
+ let w = w_slice + (f32(sub) + 0.5) * w_per_sub_step;
148
277
 
149
278
  let position_ws = (uvw_to_ws * vec4<f32>(column_uv, w, 1.0)).xyz;
150
279
 
@@ -154,21 +283,8 @@ ${seeded
154
283
  }
155
284
  `, [
156
285
  CAMERA_UNIFORM_STRUCT.declaration_chunk,
286
+ chunk_texel_coordinate_to_uv,
157
287
  chunk_volumetrics_sample_froxel_extinction,
158
288
  ]
159
- );
160
-
161
- return ComputeShader.from({
162
- label: `Volumetrics / build sun shadow volume ${index}`,
163
- resources,
164
- body
165
- });
166
- }
167
-
168
- /**
169
- * One build shader per cascade, innermost first.
170
- *
171
- * @type {ComputeShader[]}
172
- */
173
- export const shader_volumetrics_build_sun_shadow_volume =
174
- Array.from({ length: VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT }, (_, index) => make_shader(index));
289
+ )
290
+ });
@@ -859,7 +859,14 @@ function collectGlobalVariable(c, node) {
859
859
 
860
860
  c.scope.declare(name, type);
861
861
 
862
- if (group !== null && binding !== null) {
862
+ // `var<immediate>` carries neither attribute immediate data is part of the shader interface
863
+ // but is not a bound resource, so WGSL gives it no @group/@binding. It still arrives from
864
+ // outside the shader, so it is a binding as far as the emulator is concerned, and binding here
865
+ // is what keeps it out of the `privateGlobals` branch below. Falling through to that branch
866
+ // would default-initialise it and every spec reading it would quietly see zeroes.
867
+ const is_immediate = address_space === 'immediate';
868
+
869
+ if (is_immediate || (group !== null && binding !== null)) {
863
870
  c.globalBindings.push({
864
871
  name, type, group, binding, addressSpace: address_space, accessMode: access_mode,
865
872
  });
@@ -1 +1 @@
1
- {"version":3,"file":"WGSLLanguageCore.d.ts","sourceRoot":"","sources":["../../../../../src/shade/wgsl/emulator/WGSLLanguageCore.js"],"names":[],"mappings":"AA0PA;;;;;;;;;;;;GAYG;AACH,+BAFU,MAAM,CAu8Bd"}
1
+ {"version":3,"file":"WGSLLanguageCore.d.ts","sourceRoot":"","sources":["../../../../../src/shade/wgsl/emulator/WGSLLanguageCore.js"],"names":[],"mappings":"AA0PA;;;;;;;;;;;;GAYG;AACH,+BAFU,MAAM,CAm+Bd"}