@woosh/meep-engine 3.61.1 → 3.61.2

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 (114) hide show
  1. package/package.json +1 -1
  2. package/src/engine/network/sim/SimActionExecutor.d.ts +4 -0
  3. package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
  4. package/src/engine/network/sim/SimActionExecutor.js +4 -0
  5. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts.map +1 -1
  6. package/src/generation/foliage/material/foliage_atlas_cutout.js +21 -5
  7. package/src/generation/foliage/mesh/tree_cluster_representatives.d.ts +8 -0
  8. package/src/generation/foliage/mesh/tree_cluster_representatives.d.ts.map +1 -1
  9. package/src/generation/foliage/mesh/tree_cluster_representatives.js +178 -78
  10. package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
  11. package/src/generation/foliage/mesh/tree_mesh_build_bark.js +178 -97
  12. package/src/generation/foliage/skeleton/ShootLightField.d.ts +1 -0
  13. package/src/generation/foliage/skeleton/ShootLightField.d.ts.map +1 -1
  14. package/src/generation/foliage/skeleton/ShootLightField.js +88 -17
  15. package/src/generation/foliage/skeleton/ShootWoodHash.d.ts +5 -2
  16. package/src/generation/foliage/skeleton/ShootWoodHash.d.ts.map +1 -1
  17. package/src/generation/foliage/skeleton/ShootWoodHash.js +191 -25
  18. package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
  19. package/src/shade/playground/probe_clipmap/main.js +4 -0
  20. package/src/shade/playground/probe_clipmap_box/README.md +55 -0
  21. package/src/shade/playground/probe_clipmap_box/index.html +185 -0
  22. package/src/shade/playground/probe_clipmap_box/main.d.ts +8 -0
  23. package/src/shade/playground/probe_clipmap_box/main.d.ts.map +1 -0
  24. package/src/shade/playground/probe_clipmap_box/main.js +323 -0
  25. package/src/shade/playground/probe_clipmap_box/scene.d.ts +93 -0
  26. package/src/shade/playground/probe_clipmap_box/scene.d.ts.map +1 -0
  27. package/src/shade/playground/probe_clipmap_box/scene.js +256 -0
  28. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  29. package/src/shade/renderer/Renderer.js +6 -1
  30. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_decode.d.ts +12 -0
  31. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_decode.d.ts.map +1 -1
  32. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_decode.js +49 -24
  33. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_encode.d.ts +12 -0
  34. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_encode.d.ts.map +1 -1
  35. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_encode.js +50 -19
  36. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_sh3_compress.d.ts.map +1 -1
  37. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_sh3_compress.js +6 -2
  38. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +5 -1
  39. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  40. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +7 -3
  41. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +6 -4
  42. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  43. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +10 -9
  44. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +12 -0
  45. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
  46. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +14 -0
  47. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +17 -22
  48. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
  49. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +53 -65
  50. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts +2 -3
  51. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts.map +1 -1
  52. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.js +9 -20
  53. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts +2 -2
  54. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -1
  55. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +14 -19
  56. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +1 -1
  57. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts.map +1 -1
  58. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js +8 -4
  59. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.js +1 -1
  60. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.d.ts +2 -1
  61. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.d.ts.map +1 -1
  62. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.js +13 -18
  63. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_candidate.d.ts +1 -1
  64. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_candidate.d.ts.map +1 -1
  65. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_candidate.js +4 -2
  66. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_diffuse.d.ts.map +1 -1
  67. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_diffuse.js +4 -6
  68. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.d.ts.map +1 -1
  69. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.js +4 -7
  70. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts +4 -3
  71. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts.map +1 -1
  72. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.js +14 -13
  73. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts +3 -4
  74. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
  75. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +7 -15
  76. package/src/shade/renderer/light/environment/shader_downsample_environment_map.d.ts.map +1 -1
  77. package/src/shade/renderer/light/environment/shader_downsample_environment_map.js +5 -1
  78. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts +26 -8
  79. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts.map +1 -1
  80. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.js +170 -142
  81. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.d.ts +1 -1
  82. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.d.ts.map +1 -1
  83. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.js +5 -8
  84. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts +15 -4
  85. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts.map +1 -1
  86. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.js +33 -7
  87. package/src/shade/renderer/shader/chunk/noise/chunk_sobol_sample_vec2.d.ts +40 -0
  88. package/src/shade/renderer/shader/chunk/noise/chunk_sobol_sample_vec2.d.ts.map +1 -0
  89. package/src/shade/renderer/shader/chunk/noise/chunk_sobol_sample_vec2.js +75 -0
  90. package/src/shade/renderer/shader/chunk/noise/chunk_vdc_radical_inverse.d.ts.map +1 -1
  91. package/src/shade/renderer/shader/chunk/noise/chunk_vdc_radical_inverse.js +3 -1
  92. package/src/shade/renderer/shader/chunk/random/chunk_hash_lk.d.ts +28 -0
  93. package/src/shade/renderer/shader/chunk/random/chunk_hash_lk.d.ts.map +1 -0
  94. package/src/shade/renderer/shader/chunk/random/chunk_hash_lk.js +41 -0
  95. package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh3_color_add_scaled.d.ts +12 -0
  96. package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh3_color_add_scaled.d.ts.map +1 -0
  97. package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh3_color_add_scaled.js +24 -0
  98. package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts +3 -2
  99. package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts.map +1 -1
  100. package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.js +4 -0
  101. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts +2 -5
  102. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts.map +1 -1
  103. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.js +3 -20
  104. package/src/shade/renderer/water/chunk_water_gi.d.ts +1 -1
  105. package/src/shade/renderer/water/chunk_water_gi.d.ts.map +1 -1
  106. package/src/shade/renderer/water/chunk_water_gi.js +6 -8
  107. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  108. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +76 -32
  109. package/src/core/math/hash/squirrel3.d.ts +0 -17
  110. package/src/core/math/hash/squirrel3.d.ts.map +0 -1
  111. package/src/core/math/hash/squirrel3.js +0 -30
  112. package/src/shade/renderer/shader/chunk/random/chunk_hash_squirrel3.d.ts +0 -12
  113. package/src/shade/renderer/shader/chunk/random/chunk_hash_squirrel3.d.ts.map +0 -1
  114. package/src/shade/renderer/shader/chunk/random/chunk_hash_squirrel3.js +0 -30
@@ -1,6 +1,6 @@
1
1
  /**
2
- * A probe's record (PROBE_CLIPMAP_PROPOSAL_2026_10_27.md §8.2), 48 bytes a slot: where it is, when it
3
- * was wanted and traced, its last update's back faces, and its irradiance. Where
2
+ * A probe's record (PROBE_CLIPMAP_PROPOSAL_2026_10_27.md §8.2), 64 bytes a slot: where it is, when it
3
+ * was wanted and traced, its last update's back faces, and the radiance its rays saw. Where
4
4
  * relocation moved it is the state's second word, which readers weighing it load with the state.
5
5
  *
6
6
  * @type {WebGPUStruct}
@@ -274,7 +274,7 @@ export const PROBE_CANDIDATES_WRITE_RESOURCE: ShaderResourceDescriptor;
274
274
  */
275
275
  export const PROBE_CANDIDATES_READ_RESOURCE: ShaderResourceDescriptor;
276
276
  /**
277
- * A row of a listed probe's radiance map, projected: its irradiance SH, and its rays this update.
277
+ * A row of a listed probe's radiance map, projected: its radiance SH3, and its rays this update.
278
278
  * @type {WebGPUStruct}
279
279
  */
280
280
  export const PROBE_PROJECTION_ROW_STRUCT: WebGPUStruct;
@@ -326,8 +326,9 @@ export const PROBE_DEPTH_STORE_RESOURCE: ShaderResourceDescriptor;
326
326
  * fn probe_clipmap_age_bucket(age: u32) -> u32 // the bucket of frames unwanted that eviction orders by
327
327
  * fn probe_record_flags(back_face: f32, cascade: u32) -> u32
328
328
  * fn probe_record_cascade(flags: u32) -> u32
329
- * fn probe_record_sh_encode(sh: MetroL1) -> vec3<u32> // held to the half float's largest, ±65,504
330
- * fn probe_record_sh_decode(sh: vec3<u32>) -> MetroL1
329
+ * fn probe_record_sh_encode(sh: array<vec3<f32>, 9>) -> array<u32, 7> // sh: radiance SH3
330
+ * fn probe_record_sh_decode(words: array<u32, 7>) -> array<vec3<f32>, 9> // radiance SH3
331
+ * fn probe_record_mean_radiance(words: array<u32, 7>) -> vec3<f32> // over the sphere
331
332
  * fn probe_clipmap_offset_encode(offset: vec3<f32>, spacing: f32) -> u32 // the state's second word
332
333
  * fn probe_clipmap_offset_decode(word: u32, spacing: f32) -> vec3<f32>
333
334
  * fn probe_clipmap_maps_words(radiance_resolution: u32, depth_resolution: u32) -> u32 // a listed probe's, in probe_maps
@@ -374,17 +375,23 @@ export const chunk_probe_clipmap_ray_layout: CodeChunk;
374
375
  */
375
376
  export const chunk_probe_clipmap_ray_texel: CodeChunk;
376
377
  /**
377
- * The STBN jitter of a ray in its texel (§8.6): the noise moved by the slot's hash so that neighbouring
378
- * probes do not jitter alike, and a fresh sample for each update and each round of a texel's rays. The
379
- * trace aims its ray by it, and the light pass picks the probes at its hit with it (§8.7).
378
+ * A ray's noise (§8.6, §8.7): a hash of the probe's slot, its update count, the ray's place among the
379
+ * update's rays and a stream, the same in every pass that knows the ray. It never repeats over a probe's
380
+ * updates. Uniform and guided updates alike, the trace jitters its ray inside its texel by stream
381
+ * `PROBE_RAY_NOISE_JITTER`, and the bounce picks the probes at its hit by `PROBE_RAY_NOISE_PICK`, which is
382
+ * independent of the jitter that placed the hit.
383
+ *
384
+ * This is white noise. Nothing stratifies it across texels, across updates, or across a texel's rays,
385
+ * which may clump. Each component lies inside (0, 1), at the centre of one of 2^23 bins, so a weighted
386
+ * draw by it never meets either end.
380
387
  *
381
388
  * ```wgsl
382
- * fn probe_clipmap_ray_jitter(slot: u32, texel: u32, ray: u32, updates: u32, rays: u32, n: u32) -> vec2<f32> // ray: its index among the probe's R; n: n_r
389
+ * fn probe_clipmap_ray_noise(slot: u32, updates: u32, ray: u32, stream: u32) -> vec2<f32> // ray: its index among the update's rays
383
390
  * ```
384
391
  *
385
392
  * @type {CodeChunk}
386
393
  */
387
- export const chunk_probe_clipmap_ray_jitter: CodeChunk;
394
+ export const chunk_probe_clipmap_ray_noise: CodeChunk;
388
395
  /**
389
396
  * Where a ray of an update starts (§8.6): a point of the ball of `PROBE_RAY_ORIGIN_JITTER` of the spacing
390
397
  * around the probe, uniform in its volume, as Brick4's bake jitters its probes. The point is drawn from the
@@ -469,18 +476,6 @@ export const chunk_probe_clipmap_guide_expected: CodeChunk;
469
476
  * @type {CodeChunk}
470
477
  */
471
478
  export const chunk_probe_clipmap_listed: CodeChunk;
472
- /**
473
- * The jitter of a guided update's ray in its texel. The first ray takes the texel's STBN jitter
474
- * (`probe_clipmap_ray_jitter` at round 0). The rest rotate it by the R2 sequence, so a texel's rays
475
- * spread over it the way a lattice does.
476
- *
477
- * ```wgsl
478
- * fn probe_clipmap_guided_ray_jitter(slot: u32, texel: u32, round: u32, updates: u32, rays: u32, n: u32) -> vec2<f32> // round: the ray's place among its texel's
479
- * ```
480
- *
481
- * @type {CodeChunk}
482
- */
483
- export const chunk_probe_clipmap_guided_ray_jitter: CodeChunk;
484
479
  import { WebGPUStruct } from "../../../shader/type/WebGPUStruct.js";
485
480
  import { ShaderResourceDescriptor } from "../../../shader/resource/ShaderResourceDescriptor.js";
486
481
  import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_probe_clipmap.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chunk_probe_clipmap.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js"],"names":[],"mappings":"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"}
@@ -6,14 +6,12 @@ import { chunk_rgb_to_luminance } from "../../../shader/chunk/color/chunk_rgb_to
6
6
  import { chunk_sphere_sample_volume } from "../../../shader/chunk/geometry/sphere/chunk_sphere_sample_volume.js";
7
7
  import { chunk_mod_v3i } from "../../../shader/chunk/geometry/vec3/chunk_mod_v3i.js";
8
8
  import { chunk_lower_bound_branchless } from "../../../shader/chunk/math/chunk_lower_bound_branchless.js";
9
- import { chunk_stbn_sample_vec2 } from "../../../shader/chunk/noise/chunk_stbn_sample_vec2.js";
10
- import { chunk_r2_canonical } from "../../../shader/chunk/noise/r/chunk_r2_canonical.js";
11
- import { chunk_hash_lowbias32 } from "../../../shader/chunk/random/chunk_hash_lowbias32.js";
12
9
  import { chunk_hash_to_float01 } from "../../../shader/chunk/random/chunk_hash_to_float01.js";
13
10
  import { chunk_pcg3d } from "../../../shader/chunk/random/pcg/chunk_pcg3d.js";
11
+ import { chunk_pcg4d } from "../../../shader/chunk/random/pcg/chunk_pcg4d.js";
14
12
  import {
15
- METRO_L1_IRRADIANCE_STRUCT
16
- } from "../../../shader/chunk/spherical_harmonics/l1i/chunk_convert_to_irradiance_sh.js";
13
+ chunk_sh3_color_multiply_scalar
14
+ } from "../../../shader/chunk/spherical_harmonics/chunk_sh3_color_multiply_scalar.js";
17
15
  import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
18
16
  import { ShaderResourceDescriptor } from "../../../shader/resource/ShaderResourceDescriptor.js";
19
17
  import {
@@ -22,13 +20,15 @@ import {
22
20
  u32,
23
21
  vec2u,
24
22
  vec3i,
25
- vec3u,
23
+ vec3f,
26
24
  vec4f,
27
25
  vec4u
28
26
  } from "../../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
29
27
  import { WebGPUArray } from "../../../shader/type/WebGPUArray.js";
30
28
  import { WebGPUStruct } from "../../../shader/type/WebGPUStruct.js";
31
- import { STBN_VEC2_RESOURCE } from "../../../STATIC_GRAPHICS_ENGINE_ASSET_RESOURCES.js";
29
+ import { BRICK4_PROBE_ENCODED_SIZE } from "../../brick4/BRICK4_PROBE_ENCODED_SIZE.js";
30
+ import { chunk_brick4_sh3_color_unpack } from "../../brick4/gpu/encoding/v2/chunk_brick4_sh3_color_decode.js";
31
+ import { chunk_brick4_sh3_color_pack } from "../../brick4/gpu/encoding/v2/chunk_brick4_sh3_color_encode.js";
32
32
  import {
33
33
  PROBE_AGE_BUCKETS,
34
34
  PROBE_BLEND_SKIRT,
@@ -54,6 +54,8 @@ import {
54
54
  PROBE_RAY_CASCADE_SHIFT,
55
55
  PROBE_RAY_KIND_MASK,
56
56
  PROBE_RAY_NONE,
57
+ PROBE_RAY_NOISE_JITTER,
58
+ PROBE_RAY_NOISE_PICK,
57
59
  PROBE_RAY_ORIGIN_JITTER,
58
60
  PROBE_RAY_PROBE_SHIFT,
59
61
  PROBE_RECORD_CASCADE_SHIFT,
@@ -69,8 +71,8 @@ import {
69
71
  } from "./PROBE_CLIPMAP.js";
70
72
 
71
73
  /**
72
- * A probe's record (PROBE_CLIPMAP_PROPOSAL_2026_10_27.md §8.2), 48 bytes a slot: where it is, when it
73
- * was wanted and traced, its last update's back faces, and its irradiance. Where
74
+ * A probe's record (PROBE_CLIPMAP_PROPOSAL_2026_10_27.md §8.2), 64 bytes a slot: where it is, when it
75
+ * was wanted and traced, its last update's back faces, and the radiance its rays saw. Where
74
76
  * relocation moved it is the state's second word, which readers weighing it load with the state.
75
77
  *
76
78
  * @type {WebGPUStruct}
@@ -88,10 +90,13 @@ export const PROBE_RECORD_STRUCT = WebGPUStruct.from({
88
90
  /** the frame it was last updated */
89
91
  traced_frame: u32,
90
92
  /**
91
- * The irradiance its rays saw, the Metro L1 encoding (luma as SH2, chroma constant) in half floats:
92
- * Y's xy, Y's zw, CoCg. `probe_record_sh_decode`.
93
+ * The radiance its rays saw as RGB SH3, a quarter of every coefficient in Brick4's encoding
94
+ * (`brick4_sh3_color_pack`): band 0 RGB9E5, bands 1 and 2 eight bits a coefficient over it. A power of two
95
+ * scales RGB9E5's exponent alone, so `probe_record_sh_decode` gives the radiance SH3 to the bit as Brick4's
96
+ * codec decodes it wherever each lit channel's mean radiance is past 2·10⁻⁵, while band 0 holds a mean radiance
97
+ * to 73,804, past the rays' own largest light, 65,408.
93
98
  */
94
- sh: vec3u,
99
+ sh: WebGPUArray.from(u32, BRICK4_PROBE_ENCODED_SIZE),
95
100
  }, "ProbeRecord").pack();
96
101
 
97
102
  /**
@@ -448,11 +453,11 @@ export const PROBE_CANDIDATES_WRITE_RESOURCE = ShaderResourceDescriptor.storageB
448
453
  export const PROBE_CANDIDATES_READ_RESOURCE = ShaderResourceDescriptor.storageBuffer("probe_candidates", WebGPUArray.from(PROBE_CANDIDATE_STRUCT));
449
454
 
450
455
  /**
451
- * A row of a listed probe's radiance map, projected: its irradiance SH, and its rays this update.
456
+ * A row of a listed probe's radiance map, projected: its radiance SH3, and its rays this update.
452
457
  * @type {WebGPUStruct}
453
458
  */
454
459
  export const PROBE_PROJECTION_ROW_STRUCT = WebGPUStruct.from({
455
- sh: METRO_L1_IRRADIANCE_STRUCT,
460
+ sh: WebGPUArray.from(vec3f, 9),
456
461
  /** the update's rays that resolved, a back face's among them */
457
462
  resolved: u32,
458
463
  /** of them, the back faces */
@@ -517,8 +522,9 @@ export const PROBE_DEPTH_STORE_RESOURCE = ShaderResourceDescriptor.storageTextur
517
522
  * fn probe_clipmap_age_bucket(age: u32) -> u32 // the bucket of frames unwanted that eviction orders by
518
523
  * fn probe_record_flags(back_face: f32, cascade: u32) -> u32
519
524
  * fn probe_record_cascade(flags: u32) -> u32
520
- * fn probe_record_sh_encode(sh: MetroL1) -> vec3<u32> // held to the half float's largest, ±65,504
521
- * fn probe_record_sh_decode(sh: vec3<u32>) -> MetroL1
525
+ * fn probe_record_sh_encode(sh: array<vec3<f32>, 9>) -> array<u32, 7> // sh: radiance SH3
526
+ * fn probe_record_sh_decode(words: array<u32, 7>) -> array<vec3<f32>, 9> // radiance SH3
527
+ * fn probe_record_mean_radiance(words: array<u32, 7>) -> vec3<f32> // over the sphere
522
528
  * fn probe_clipmap_offset_encode(offset: vec3<f32>, spacing: f32) -> u32 // the state's second word
523
529
  * fn probe_clipmap_offset_decode(word: u32, spacing: f32) -> vec3<f32>
524
530
  * fn probe_clipmap_maps_words(radiance_resolution: u32, depth_resolution: u32) -> u32 // a listed probe's, in probe_maps
@@ -618,20 +624,20 @@ fn probe_record_cascade(flags: u32) -> u32 {
618
624
  return flags >> PROBE_RECORD_CASCADE_SHIFT;
619
625
  }
620
626
 
621
- fn probe_record_sh_encode(sh: ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref}) -> vec3<u32> {
622
- let y = clamp(sh.Y, vec4<f32>(-65504.0), vec4<f32>(65504.0));
623
- let cocg = clamp(sh.CoCg, vec2<f32>(-65504.0), vec2<f32>(65504.0));
627
+ // the power of two at or below band 0's basis constant, 1/√(4π): band 0 holds a mean radiance past RGB9E5's largest value
628
+ const PROBE_RECORD_SH_SCALE = 0.25;
624
629
 
625
- return vec3<u32>(pack2x16float(y.xy), pack2x16float(y.zw), pack2x16float(cocg));
630
+ fn probe_record_sh_encode(sh: array<vec3<f32>, 9>) -> array<u32, ${BRICK4_PROBE_ENCODED_SIZE}> {
631
+ return brick4_sh3_color_pack(sh3_color_multiply_scalar(sh, PROBE_RECORD_SH_SCALE));
626
632
  }
627
633
 
628
- fn probe_record_sh_decode(sh: vec3<u32>) -> ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref} {
629
- var out: ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref};
630
-
631
- out.Y = vec4<f32>(unpack2x16float(sh.x), unpack2x16float(sh.y));
632
- out.CoCg = unpack2x16float(sh.z);
634
+ fn probe_record_sh_decode(words: array<u32, ${BRICK4_PROBE_ENCODED_SIZE}>) -> array<vec3<f32>, 9> {
635
+ return brick4_sh3_color_unpack(words, 1.0 / PROBE_RECORD_SH_SCALE);
636
+ }
633
637
 
634
- return out;
638
+ fn probe_record_mean_radiance(words: array<u32, ${BRICK4_PROBE_ENCODED_SIZE}>) -> vec3<f32> {
639
+ // band 0 times its basis constant
640
+ return brick4_sh3_color_unpack_dc(words) * (0.28209479177387814 / PROBE_RECORD_SH_SCALE);
635
641
  }
636
642
 
637
643
  fn probe_clipmap_maps_words(radiance_resolution: u32, depth_resolution: u32) -> u32 {
@@ -653,7 +659,9 @@ fn probe_clipmap_offset_decode(word: u32, spacing: f32) -> vec3<f32> {
653
659
  }
654
660
  `, [
655
661
  PROBE_RECORD_STRUCT.declaration_chunk,
656
- METRO_L1_IRRADIANCE_STRUCT.declaration_chunk,
662
+ chunk_brick4_sh3_color_pack,
663
+ chunk_brick4_sh3_color_unpack,
664
+ chunk_sh3_color_multiply_scalar,
657
665
  chunk_clipmap_key,
658
666
  chunk_mod_v3i,
659
667
  ]);
@@ -751,36 +759,38 @@ fn probe_clipmap_texel_ray(texel: u32, round: u32, updates: u32, rays: u32, texe
751
759
  ]);
752
760
 
753
761
  /**
754
- * The STBN jitter of a ray in its texel (§8.6): the noise moved by the slot's hash so that neighbouring
755
- * probes do not jitter alike, and a fresh sample for each update and each round of a texel's rays. The
756
- * trace aims its ray by it, and the light pass picks the probes at its hit with it (§8.7).
762
+ * A ray's noise (§8.6, §8.7): a hash of the probe's slot, its update count, the ray's place among the
763
+ * update's rays and a stream, the same in every pass that knows the ray. It never repeats over a probe's
764
+ * updates. Uniform and guided updates alike, the trace jitters its ray inside its texel by stream
765
+ * `PROBE_RAY_NOISE_JITTER`, and the bounce picks the probes at its hit by `PROBE_RAY_NOISE_PICK`, which is
766
+ * independent of the jitter that placed the hit.
767
+ *
768
+ * This is white noise. Nothing stratifies it across texels, across updates, or across a texel's rays,
769
+ * which may clump. Each component lies inside (0, 1), at the centre of one of 2^23 bins, so a weighted
770
+ * draw by it never meets either end.
757
771
  *
758
772
  * ```wgsl
759
- * fn probe_clipmap_ray_jitter(slot: u32, texel: u32, ray: u32, updates: u32, rays: u32, n: u32) -> vec2<f32> // ray: its index among the probe's R; n: n_r
773
+ * fn probe_clipmap_ray_noise(slot: u32, updates: u32, ray: u32, stream: u32) -> vec2<f32> // ray: its index among the update's rays
760
774
  * ```
761
775
  *
762
776
  * @type {CodeChunk}
763
777
  */
764
- export const chunk_probe_clipmap_ray_jitter = CodeChunk.from(
778
+ export const chunk_probe_clipmap_ray_noise = CodeChunk.from(
765
779
  //language=WGSL
766
780
  `
767
- fn probe_clipmap_ray_jitter(slot: u32, texel: u32, ray: u32, updates: u32, rays: u32, n: u32) -> vec2<f32> {
768
- let texels = n * n;
769
- let round = select(0u, ray / texels, rays >= texels);
770
- let per_texel = max(rays / texels, 1u);
781
+ const PROBE_RAY_NOISE_JITTER = ${PROBE_RAY_NOISE_JITTER}u;
782
+ const PROBE_RAY_NOISE_PICK = ${PROBE_RAY_NOISE_PICK}u;
771
783
 
772
- let scramble = hash_lowbias32(slot);
773
- let noise_xy = vec2<u32>(texel % n, texel / n) + vec2<u32>(scramble & 127u, (scramble >> 7u) & 127u);
784
+ fn probe_clipmap_ray_noise(slot: u32, updates: u32, ray: u32, stream: u32) -> vec2<f32> {
785
+ let hash = pcg4d(vec4<u32>(slot, updates, ray, stream));
774
786
 
775
- return stbn_sample_vec2(vec3<u32>(noise_xy, updates * per_texel + round));
787
+ // 23 bits and a half fit f32's 24 exactly: the centre of the last bin stays under 1
788
+ return (vec2<f32>(hash.xy >> vec2<u32>(9u)) + 0.5) * (1.0 / 8388608.0);
776
789
  }
777
790
  `, [
778
- chunk_hash_lowbias32,
779
- chunk_stbn_sample_vec2,
791
+ chunk_pcg4d,
780
792
  ]);
781
793
 
782
- chunk_probe_clipmap_ray_jitter.requireResource(STBN_VEC2_RESOURCE);
783
-
784
794
  /**
785
795
  * Where a ray of an update starts (§8.6): a point of the ball of `PROBE_RAY_ORIGIN_JITTER` of the spacing
786
796
  * around the probe, uniform in its volume, as Brick4's bake jitters its probes. The point is drawn from the
@@ -967,25 +977,3 @@ fn probe_clipmap_listed(slot: u32, capacity: u32) -> u32 {
967
977
 
968
978
  chunk_probe_clipmap_listed.requireResource(PROBE_LISTED_READ_RESOURCE);
969
979
  chunk_probe_clipmap_listed.requireResource(PROBE_TRACE_READ_RESOURCE);
970
-
971
- /**
972
- * The jitter of a guided update's ray in its texel. The first ray takes the texel's STBN jitter
973
- * (`probe_clipmap_ray_jitter` at round 0). The rest rotate it by the R2 sequence, so a texel's rays
974
- * spread over it the way a lattice does.
975
- *
976
- * ```wgsl
977
- * fn probe_clipmap_guided_ray_jitter(slot: u32, texel: u32, round: u32, updates: u32, rays: u32, n: u32) -> vec2<f32> // round: the ray's place among its texel's
978
- * ```
979
- *
980
- * @type {CodeChunk}
981
- */
982
- export const chunk_probe_clipmap_guided_ray_jitter = CodeChunk.from(
983
- //language=WGSL
984
- `
985
- fn probe_clipmap_guided_ray_jitter(slot: u32, texel: u32, round: u32, updates: u32, rays: u32, n: u32) -> vec2<f32> {
986
- return fract(probe_clipmap_ray_jitter(slot, texel, 0u, updates, rays, n) + r2_canonical(round) - 0.5);
987
- }
988
- `, [
989
- chunk_probe_clipmap_ray_jitter,
990
- chunk_r2_canonical,
991
- ]);
@@ -47,9 +47,8 @@ export const PROBE_DEPTH_SAMPLER_RESOURCE: ShaderResourceDescriptor;
47
47
  * cascade's blend skirt, two of the next one's too, the pairs lerped by the skirt's weight. A cascade
48
48
  * whose corners weigh nothing gives way to the next coarser, without a skirt. With none left the
49
49
  * weights are zero, and the fallback is the caller's (§9.1, step 6).
50
- * - **The SH**: the picked records' Metro L1 structs mixed by their weights; resolved with
51
- * `resolve_irradiance_sh_to_diffuse` at the caller's normal, it gives E/π. `found` says whether any probe
52
- * weighed anything.
50
+ * - **The SH**: the picked records' RGB radiance SH3 mixed by their weights; `sh3_color_get_irradiance_at`
51
+ * at the caller's normal gives E. `found` says whether any probe weighed anything.
53
52
  *
54
53
  * Per cascade read: 8 indirection loads, 8 state words and 8 depth taps, then 2 indirection loads for
55
54
  * the pair; then two records a cascade read for the SH. A depth tile's place takes no integer division
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_probe_clipmap_pick.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.js"],"names":[],"mappings":"AAgCA;;;;GAIG;AACH,oCAFU,YAAY,CAuBF;AAEpB;;;GAGG;AACH,sCAFU,wBAAwB,CAE+E;AAEjH;;;GAGG;AACH,8CAFU,wBAAwB,CAEiF;AAEnH;;;GAGG;AACH,6CAFU,iBAAiB,CAQvB;AAEJ;;;GAGG;AACH,2CAFU,wBAAwB,CAE+G;AAOjJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,0CAFU,SAAS,CAyMhB;AAIH;;;;;;;;;;;;;;;;GAgBG;AACH,uCAFU,SAAS,CA0BhB;AASH;;;;;;;GAOG;AACH,2CAFU,6BAA6B,CAWG;6BA3Xb,sCAAsC;yCAH1B,sDAAsD;kCAhB7D,qDAAqD;0BAe7D,uCAAuC;8CAEnB,2DAA2D"}
1
+ {"version":3,"file":"chunk_probe_clipmap_pick.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.js"],"names":[],"mappings":"AA8BA;;;;GAIG;AACH,oCAFU,YAAY,CAuBF;AAEpB;;;GAGG;AACH,sCAFU,wBAAwB,CAE+E;AAEjH;;;GAGG;AACH,8CAFU,wBAAwB,CAEiF;AAEnH;;;GAGG;AACH,6CAFU,iBAAiB,CAQvB;AAEJ;;;GAGG;AACH,2CAFU,wBAAwB,CAE+G;AAOjJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,0CAFU,SAAS,CAiMhB;AAIH;;;;;;;;;;;;;;;;GAgBG;AACH,uCAFU,SAAS,CA0BhB;AASH;;;;;;;GAOG;AACH,2CAFU,6BAA6B,CAWG;6BAlXb,sCAAsC;yCAH1B,sDAAsD;kCAd7D,qDAAqD;0BAa7D,uCAAuC;8CAEnB,2DAA2D"}
@@ -7,9 +7,7 @@ import {
7
7
  import { chunk_index_to_grid2d_reciprocal } from "../../../shader/chunk/grid/chunk_index_to_grid2d_reciprocal.js";
8
8
  import { chunk_probe_visibility_weight } from "../../../shader/chunk/light/probe/chunk_probe_visibility_weight.js";
9
9
  import { chunk_pick2_wrs_mat2x4 } from "../../../shader/chunk/random/reservoir/chunk_pick2_wrs_mat2x4.js";
10
- import {
11
- METRO_L1_IRRADIANCE_STRUCT
12
- } from "../../../shader/chunk/spherical_harmonics/l1i/chunk_convert_to_irradiance_sh.js";
10
+ import { chunk_sh3_color_add_scaled } from "../../../shader/chunk/spherical_harmonics/chunk_sh3_color_add_scaled.js";
13
11
  import {
14
12
  chunk_texture_octahedral_skirt_uv
15
13
  } from "../../../shader/chunk/texture/octahedral/chunk_texture_octahedral_skirt_uv.js";
@@ -116,9 +114,8 @@ const RECORDS = `ptr<storage, array<${PROBE_RECORD_STRUCT.wgsl_ref}>, read>`;
116
114
  * cascade's blend skirt, two of the next one's too, the pairs lerped by the skirt's weight. A cascade
117
115
  * whose corners weigh nothing gives way to the next coarser, without a skirt. With none left the
118
116
  * weights are zero, and the fallback is the caller's (§9.1, step 6).
119
- * - **The SH**: the picked records' Metro L1 structs mixed by their weights; resolved with
120
- * `resolve_irradiance_sh_to_diffuse` at the caller's normal, it gives E/π. `found` says whether any probe
121
- * weighed anything.
117
+ * - **The SH**: the picked records' RGB radiance SH3 mixed by their weights; `sh3_color_get_irradiance_at`
118
+ * at the caller's normal gives E. `found` says whether any probe weighed anything.
122
119
  *
123
120
  * Per cascade read: 8 indirection loads, 8 state words and 8 depth taps, then 2 indirection loads for
124
121
  * the pair; then two records a cascade read for the SH. A depth tile's place takes no integer division
@@ -142,7 +139,7 @@ struct ProbeClipmapPair {
142
139
  }
143
140
 
144
141
  struct ProbeClipmapSH {
145
- sh: ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref},
142
+ sh: array<vec3<f32>, 9>,
146
143
  found: bool,
147
144
  }
148
145
 
@@ -292,24 +289,16 @@ fn probe_clipmap_sh_in(records: ${RECORDS}, pick: ProbeClipmapPick) -> ProbeClip
292
289
 
293
290
  // each by name, the slots of a weight of zero not read
294
291
  if (pick.weights.x > 0.0) {
295
- let sh = probe_record_sh_decode((*records)[pick.slots.x].sh);
296
- out.sh.CoCg += pick.weights.x * sh.CoCg;
297
- out.sh.Y += pick.weights.x * sh.Y;
292
+ out.sh = sh3_color_add_scaled(out.sh, probe_record_sh_decode((*records)[pick.slots.x].sh), pick.weights.x);
298
293
  }
299
294
  if (pick.weights.y > 0.0) {
300
- let sh = probe_record_sh_decode((*records)[pick.slots.y].sh);
301
- out.sh.CoCg += pick.weights.y * sh.CoCg;
302
- out.sh.Y += pick.weights.y * sh.Y;
295
+ out.sh = sh3_color_add_scaled(out.sh, probe_record_sh_decode((*records)[pick.slots.y].sh), pick.weights.y);
303
296
  }
304
297
  if (pick.weights.z > 0.0) {
305
- let sh = probe_record_sh_decode((*records)[pick.slots.z].sh);
306
- out.sh.CoCg += pick.weights.z * sh.CoCg;
307
- out.sh.Y += pick.weights.z * sh.Y;
298
+ out.sh = sh3_color_add_scaled(out.sh, probe_record_sh_decode((*records)[pick.slots.z].sh), pick.weights.z);
308
299
  }
309
300
  if (pick.weights.w > 0.0) {
310
- let sh = probe_record_sh_decode((*records)[pick.slots.w].sh);
311
- out.sh.CoCg += pick.weights.w * sh.CoCg;
312
- out.sh.Y += pick.weights.w * sh.Y;
301
+ out.sh = sh3_color_add_scaled(out.sh, probe_record_sh_decode((*records)[pick.slots.w].sh), pick.weights.w);
313
302
  }
314
303
 
315
304
  return out;
@@ -323,8 +312,8 @@ fn probe_clipmap_sh_in(records: ${RECORDS}, pick: ProbeClipmapPick) -> ProbeClip
323
312
  chunk_texture_octahedral_skirt_uv,
324
313
  chunk_probe_visibility_weight,
325
314
  chunk_pick2_wrs_mat2x4,
315
+ chunk_sh3_color_add_scaled,
326
316
  PROBE_SAMPLING_STRUCT.declaration_chunk,
327
- METRO_L1_IRRADIANCE_STRUCT.declaration_chunk,
328
317
  ]);
329
318
 
330
319
  chunk_probe_clipmap_pick_in.requireResource(PROBE_DEPTH_SAMPLER_RESOURCE);
@@ -18,8 +18,8 @@
18
18
  * at the cage's diagonal (§8.2), past which no parallax is taken. One bilinear tap of the tile, through
19
19
  * its skirt and the depth's sampler.
20
20
  * - **The rough end** is the probes' SH, mixed by the same shares and resolved for the GGX lobe
21
- * (`resolve_irradiance_sh_to_specular`). The two are blended by `roughness_to_mip_ratio`: SH alone from
22
- * roughness 0.7.
21
+ * (`sh3_color_get_radiance_with_GGX`, as Brick4 resolves its probes). The two are blended by
22
+ * `roughness_to_mip_ratio`: SH alone from roughness 0.7.
23
23
  * - Where no probe weighs anything, nothing is found and the fallback is the caller's.
24
24
  *
25
25
  * @type {CodeChunk}
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_probe_clipmap_sample_radiance.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js"],"names":[],"mappings":"AA8BA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,kDAFU,SAAS,CAsIZ;0BA7KmB,uCAAuC"}
1
+ {"version":3,"file":"chunk_probe_clipmap_sample_radiance.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js"],"names":[],"mappings":"AA4BA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,kDAFU,SAAS,CAmIZ;0BA1KmB,uCAAuC"}
@@ -4,12 +4,10 @@ import {
4
4
  } from "../../../shader/chunk/geometry/octahedron/chunk_uv_octahedral_unit_encode.js";
5
5
  import { chunk_index_to_grid2d_reciprocal } from "../../../shader/chunk/grid/chunk_index_to_grid2d_reciprocal.js";
6
6
  import { chunk_probe_visibility_weight } from "../../../shader/chunk/light/probe/chunk_probe_visibility_weight.js";
7
+ import { chunk_sh3_color_add_scaled } from "../../../shader/chunk/spherical_harmonics/chunk_sh3_color_add_scaled.js";
7
8
  import {
8
- METRO_L1_IRRADIANCE_STRUCT
9
- } from "../../../shader/chunk/spherical_harmonics/l1i/chunk_convert_to_irradiance_sh.js";
10
- import {
11
- chunk_resolve_irradiance_sh_to_specular
12
- } from "../../../shader/chunk/spherical_harmonics/l1i/chunk_resolve_irradiance_sh_to_specular.js";
9
+ chunk_sh3_color_get_radiance_with_GGX
10
+ } from "../../../shader/chunk/spherical_harmonics/chunk_sh3_color_get_radiance_with_GGX.js";
13
11
  import {
14
12
  chunk_texture_octahedral_skirt_uv
15
13
  } from "../../../shader/chunk/texture/octahedral/chunk_texture_octahedral_skirt_uv.js";
@@ -48,8 +46,8 @@ import { PROBE_RECEIVER_BIAS_VIEW } from "./PROBE_CLIPMAP.js";
48
46
  * at the cage's diagonal (§8.2), past which no parallax is taken. One bilinear tap of the tile, through
49
47
  * its skirt and the depth's sampler.
50
48
  * - **The rough end** is the probes' SH, mixed by the same shares and resolved for the GGX lobe
51
- * (`resolve_irradiance_sh_to_specular`). The two are blended by `roughness_to_mip_ratio`: SH alone from
52
- * roughness 0.7.
49
+ * (`sh3_color_get_radiance_with_GGX`, as Brick4 resolves its probes). The two are blended by
50
+ * `roughness_to_mip_ratio`: SH alone from roughness 0.7.
53
51
  * - Where no probe weighs anything, nothing is found and the fallback is the caller's.
54
52
  *
55
53
  * @type {CodeChunk}
@@ -66,7 +64,7 @@ struct ProbeClipmapLobe {
66
64
  // the probe's share for the lobe, before the shares are renormalised
67
65
  weight: f32,
68
66
  radiance: vec3<f32>,
69
- sh: ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref},
67
+ sh: array<vec3<f32>, 9>,
70
68
  }
71
69
 
72
70
  // a slot's radiance toward a direction, and its texels' count of samples in alpha: one bilinear tap of its
@@ -135,39 +133,35 @@ fn probe_clipmap_radiance_of(pick: ProbeClipmapPick, position: vec3<f32>, normal
135
133
 
136
134
  var weight = 0.0;
137
135
  var radiance = vec3<f32>(0.0);
138
- var sh: ${METRO_L1_IRRADIANCE_STRUCT.wgsl_ref};
136
+ var sh: array<vec3<f32>, 9>;
139
137
 
140
138
  // each by name, the slots of a share of zero not read
141
139
  if (pick.weights.x > 0.0) {
142
140
  let probe = probe_clipmap_lobe(pick.slots.x, pick.weights.x, position, normal, bias_direction, lobe);
143
141
  weight += probe.weight;
144
142
  radiance += probe.weight * probe.radiance;
145
- sh.Y += probe.weight * probe.sh.Y;
146
- sh.CoCg += probe.weight * probe.sh.CoCg;
143
+ sh = sh3_color_add_scaled(sh, probe.sh, probe.weight);
147
144
  }
148
145
  if (pick.weights.y > 0.0) {
149
146
  let probe = probe_clipmap_lobe(pick.slots.y, pick.weights.y, position, normal, bias_direction, lobe);
150
147
  weight += probe.weight;
151
148
  radiance += probe.weight * probe.radiance;
152
- sh.Y += probe.weight * probe.sh.Y;
153
- sh.CoCg += probe.weight * probe.sh.CoCg;
149
+ sh = sh3_color_add_scaled(sh, probe.sh, probe.weight);
154
150
  }
155
151
  if (pick.weights.z > 0.0) {
156
152
  let probe = probe_clipmap_lobe(pick.slots.z, pick.weights.z, position, normal, bias_direction, lobe);
157
153
  weight += probe.weight;
158
154
  radiance += probe.weight * probe.radiance;
159
- sh.Y += probe.weight * probe.sh.Y;
160
- sh.CoCg += probe.weight * probe.sh.CoCg;
155
+ sh = sh3_color_add_scaled(sh, probe.sh, probe.weight);
161
156
  }
162
157
  if (pick.weights.w > 0.0) {
163
158
  let probe = probe_clipmap_lobe(pick.slots.w, pick.weights.w, position, normal, bias_direction, lobe);
164
159
  weight += probe.weight;
165
160
  radiance += probe.weight * probe.radiance;
166
- sh.Y += probe.weight * probe.sh.Y;
167
- sh.CoCg += probe.weight * probe.sh.CoCg;
161
+ sh = sh3_color_add_scaled(sh, probe.sh, probe.weight);
168
162
  }
169
163
 
170
- let rough = resolve_irradiance_sh_to_specular(sh.Y / weight, sh.CoCg / weight, lobe, alpha);
164
+ let rough = sh3_color_get_radiance_with_GGX(sh, lobe, alpha) / weight;
171
165
 
172
166
  out.radiance = mix(radiance / weight, rough, roughness_to_mip_ratio(roughness));
173
167
 
@@ -184,7 +178,8 @@ fn probe_clipmap_sample_radiance(position: vec3<f32>, normal: vec3<f32>, view_di
184
178
  chunk_index_to_grid2d_reciprocal,
185
179
  chunk_texture_octahedral_skirt_uv,
186
180
  chunk_uv_octahedral_unit_encode,
187
- chunk_resolve_irradiance_sh_to_specular,
181
+ chunk_sh3_color_add_scaled,
182
+ chunk_sh3_color_get_radiance_with_GGX,
188
183
  chunk_roughness_to_mip_ratio,
189
184
  ]);
190
185
 
@@ -19,7 +19,7 @@ export const PROBE_ACCUMULATE_SETTINGS: WebGPUStruct;
19
19
  * so their mean needs no weight for the guide's choice.
20
20
  * - **Radiance**: the mean of the texel's resolved rays, a back face's being zero, is a sample of the
21
21
  * texel's multi-scale mean (`chunk_multiscale_mean`), its estimator in `probe_estimators` and its mean
22
- * in the atlas.
22
+ * in the atlas, at the exposure in `probe_exposure`: the display's, which the estimator's thresholds are in.
23
23
  * - The short mean blends by β = max(1/(a+1), `PROBE_SHORT_BLEND`), its variance by max(1/(a+1),
24
24
  * `PROBE_VARIANCE_BLEND`), a the texel's own count of the updates that reached it, held in its alpha.
25
25
  * A sample's blend is a sample's however long since the last one: a probe nobody wanted, or a texel the
@@ -1 +1 @@
1
- {"version":3,"file":"shader_probe_clipmap_accumulate.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js"],"names":[],"mappings":"AA8CA;;GAEG;AACH,wCAFU,YAAY,CAmBQ;AAoB9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,8CAFU,aAAa,CA0TpB;6BApb0B,sCAAsC;8BAHrC,kCAAkC"}
1
+ {"version":3,"file":"shader_probe_clipmap_accumulate.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js"],"names":[],"mappings":"AA+CA;;GAEG;AACH,wCAFU,YAAY,CAmBQ;AAsB9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,8CAFU,aAAa,CA2TpB;6BAvb0B,sCAAsC;8BAJrC,kCAAkC"}
@@ -11,6 +11,7 @@ import { chunk_pcg3d } from "../../../shader/chunk/random/pcg/chunk_pcg3d.js";
11
11
  import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
12
12
  import { ComputeShader } from "../../../shader/ComputeShader.js";
13
13
  import { ShaderResourceSetDescriptor } from "../../../shader/resource/ShaderResourceSetDescriptor.js";
14
+ import { F32_CONTAINER_STRUCT } from "../../../shader/type/F32_CONTAINER_STRUCT.js";
14
15
  import { u32 } from "../../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
15
16
  import { WebGPUStruct } from "../../../shader/type/WebGPUStruct.js";
16
17
  import { BRICK_TRACE_MISS, BRICK_TRACE_UNRESOLVED } from "../brick/BRICK_CLIPMAP.js";
@@ -82,7 +83,9 @@ resources.createGroup()
82
83
  .add(PROBE_DEPTH_HISTORY_RESOURCE)
83
84
  .add(PROBE_ESTIMATORS_RESOURCE)
84
85
  // read only where the frame re-samples (chunk_probe_clipmap_resampled)
85
- .add(PROBE_RESAMPLES_READ_RESOURCE);
86
+ .add(PROBE_RESAMPLES_READ_RESOURCE)
87
+ // the factor the display multiplies radiance by ahead of its tone curve, as the last frame was shown
88
+ .addUniform("probe_exposure", F32_CONTAINER_STRUCT);
86
89
 
87
90
  /**
88
91
  * Accumulate (PROBE_CLIPMAP_PROPOSAL_2026_10_27.md §8.8): a thread a texel of each listed probe's maps,
@@ -101,7 +104,7 @@ resources.createGroup()
101
104
  * so their mean needs no weight for the guide's choice.
102
105
  * - **Radiance**: the mean of the texel's resolved rays, a back face's being zero, is a sample of the
103
106
  * texel's multi-scale mean (`chunk_multiscale_mean`), its estimator in `probe_estimators` and its mean
104
- * in the atlas.
107
+ * in the atlas, at the exposure in `probe_exposure`: the display's, which the estimator's thresholds are in.
105
108
  * - The short mean blends by β = max(1/(a+1), `PROBE_SHORT_BLEND`), its variance by max(1/(a+1),
106
109
  * `PROBE_VARIANCE_BLEND`), a the texel's own count of the updates that reached it, held in its alpha.
107
110
  * A sample's blend is a sample's however long since the last one: a probe nobody wanted, or a texel the
@@ -282,8 +285,8 @@ fn main(
282
285
  if (history.a > 0.0) {
283
286
  let ramp = 1.0 / (history.a + 1.0);
284
287
  let before = probe_accumulate_estimator(history.rgb, probe_estimators[estimator]);
285
- // the estimator's own floor on the variance
286
- let deviation = rgb_to_luminance(sqrt(max(vec3<f32>(1e-5), before.variance)));
288
+ // the estimator's own floor on the deviation, at the display's exposure
289
+ let deviation = rgb_to_luminance(max(multiscale_mean_deviation_floor(before.short_mean, probe_exposure.value), sqrt(max(vec3<f32>(0.0), before.variance))));
287
290
 
288
291
  change = vec2<f32>(clamp(rgb_to_luminance(sample - history.rgb) / deviation, -${PROBE_CHANGE_SIGNIFICANCE}.0, ${PROBE_CHANGE_SIGNIFICANCE}.0), 1.0);
289
292
 
@@ -294,6 +297,7 @@ fn main(
294
297
  max(ramp, ${PROBE_VARIANCE_BLEND}),
295
298
  select(0.0, ramp, history.a < ${PROBE_RADIANCE_SAMPLES_LIMIT}.0),
296
299
  ramp <= ${PROBE_VARIANCE_BLEND},
300
+ probe_exposure.value,
297
301
  );
298
302
  }
299
303
 
@@ -156,7 +156,7 @@ fn main(
156
156
  probe_records[slot].flags = probe_record_flags(0.0, cascade);
157
157
  probe_records[slot].wanted_frame = settings.frame;
158
158
  probe_records[slot].traced_frame = settings.frame;
159
- probe_records[slot].sh = vec3<u32>(0u);
159
+ probe_records[slot].sh = probe_record_sh_encode(array<vec3<f32>, 9>());
160
160
 
161
161
  // at its lattice point until its first update relocates it
162
162
  probe_states[slot] = vec2<u32>(probe_state(PROBE_STATE_NEW, 0u), 0u);
@@ -4,7 +4,8 @@
4
4
  * `PROBE_DISPATCH_RAYS`. It adds ρ_d·E_ind/π to the ray's light, ρ_d the albedo shade left in its `row`.
5
5
  *
6
6
  * - **The first clipmap**: the frustum's probes, picked at the hit along its normal, the view back along
7
- * the ray, with the ray's own jitter as the noise (`probe_clipmap_pick_in`).
7
+ * the ray, with the ray's own pick noise (`probe_clipmap_ray_noise`, `PROBE_RAY_NOISE_PICK`), drawn
8
+ * apart from the jitter that placed the hit (`probe_clipmap_pick_in`).
8
9
  * - **Where it has probes**, their SH is the bounce, and the ray's `row` is cleared: a hit the first clipmap
9
10
  * serves wants nothing of the fallback (`shader_probe_clipmap_want_hits`).
10
11
  * - **Where it has none**, the fallback's, the world cache's: the same pick there, at its own spacing.
@@ -1 +1 @@
1
- {"version":3,"file":"shader_probe_clipmap_bounce.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.js"],"names":[],"mappings":"AAuEA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,0CAFU,aAAa,CAgFpB;8BAjK2B,kCAAkC"}
1
+ {"version":3,"file":"shader_probe_clipmap_bounce.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.js"],"names":[],"mappings":"AAqEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,0CAFU,aAAa,CA4EpB;8BA3J2B,kCAAkC"}