@woosh/meep-engine 3.36.0 → 3.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/package.json +1 -1
  2. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  3. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +2 -0
  4. package/src/engine/ecs/transform/TRANSFORM64_EVENT_PLACED.d.ts +11 -0
  5. package/src/engine/ecs/transform/TRANSFORM64_EVENT_PLACED.d.ts.map +1 -0
  6. package/src/engine/ecs/transform/TRANSFORM64_EVENT_PLACED.js +10 -0
  7. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts.map +1 -1
  8. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +16 -0
  9. package/src/engine/graphics/ecs/water/Water.d.ts +30 -0
  10. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  11. package/src/engine/graphics/ecs/water/Water.js +125 -104
  12. package/src/engine/graphics/ecs/water/WaterSerializationAdapter.d.ts.map +1 -1
  13. package/src/engine/graphics/ecs/water/WaterSerializationAdapter.js +13 -1
  14. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_1_2.d.ts +6 -0
  15. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_1_2.d.ts.map +1 -0
  16. package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_1_2.js +18 -0
  17. package/src/engine/graphics3/WaterSystem.d.ts +22 -6
  18. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  19. package/src/engine/graphics3/WaterSystem.js +314 -293
  20. package/src/engine/input/devices/XRInputDevice.d.ts +51 -23
  21. package/src/engine/input/devices/XRInputDevice.d.ts.map +1 -1
  22. package/src/engine/input/devices/XRInputDevice.js +145 -52
  23. package/src/engine/input/devices/xr/XRGamepadMapping.d.ts +14 -0
  24. package/src/engine/input/devices/xr/XRGamepadMapping.d.ts.map +1 -0
  25. package/src/engine/input/devices/xr/XRGamepadMapping.js +9 -0
  26. package/src/engine/input/devices/xr/XRHandedness.d.ts +15 -0
  27. package/src/engine/input/devices/xr/XRHandedness.d.ts.map +1 -0
  28. package/src/engine/input/devices/xr/XRHandedness.js +10 -0
  29. package/src/engine/input/devices/xr/XRInputAction.d.ts +24 -11
  30. package/src/engine/input/devices/xr/XRInputAction.d.ts.map +1 -1
  31. package/src/engine/input/devices/xr/XRInputAction.js +55 -24
  32. package/src/engine/input/devices/xr/XRInputButton.d.ts +7 -9
  33. package/src/engine/input/devices/xr/XRInputButton.d.ts.map +1 -1
  34. package/src/engine/input/devices/xr/XRInputButton.js +18 -8
  35. package/src/engine/input/devices/xr/XRInputCoordinates.d.ts +11 -3
  36. package/src/engine/input/devices/xr/XRInputCoordinates.d.ts.map +1 -1
  37. package/src/engine/input/devices/xr/XRInputCoordinates.js +17 -3
  38. package/src/engine/input/devices/xr/XRInputHandle.d.ts +41 -11
  39. package/src/engine/input/devices/xr/XRInputHandle.d.ts.map +1 -1
  40. package/src/engine/input/devices/xr/XRInputHandle.js +129 -32
  41. package/src/engine/input/devices/xr/XRInputPose.d.ts +41 -5
  42. package/src/engine/input/devices/xr/XRInputPose.d.ts.map +1 -1
  43. package/src/engine/input/devices/xr/XRInputPose.js +57 -16
  44. package/src/engine/input/devices/xr/XRInputTypes.d.ts +18 -18
  45. package/src/engine/input/devices/xr/XRInputTypes.js +3 -3
  46. package/src/engine/input/devices/xr/XRTargetRayMode.d.ts +17 -0
  47. package/src/engine/input/devices/xr/XRTargetRayMode.d.ts.map +1 -0
  48. package/src/engine/input/devices/xr/XRTargetRayMode.js +12 -0
  49. package/src/engine/input/devices/xr/XRVisibilityState.d.ts +15 -0
  50. package/src/engine/input/devices/xr/XRVisibilityState.d.ts.map +1 -0
  51. package/src/engine/input/devices/xr/XRVisibilityState.js +10 -0
  52. package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.d.ts +3 -1
  53. package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.d.ts.map +1 -1
  54. package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.js +5 -1
  55. package/src/engine/input/ecs/ism/device/XRInputDeviceAdapter.d.ts +19 -5
  56. package/src/engine/input/ecs/ism/device/XRInputDeviceAdapter.d.ts.map +1 -1
  57. package/src/engine/input/ecs/ism/device/XRInputDeviceAdapter.js +42 -9
  58. package/src/engine/input/ecs/ism/device/XR_INPUT_DEVICE_IDS.d.ts +8 -2
  59. package/src/engine/input/ecs/ism/device/XR_INPUT_DEVICE_IDS.d.ts.map +1 -1
  60. package/src/engine/input/ecs/ism/device/XR_INPUT_DEVICE_IDS.js +19 -9
  61. package/src/engine/input/ecs/ism/trigger/InputTriggerXRButton.d.ts +10 -2
  62. package/src/engine/input/ecs/ism/trigger/InputTriggerXRButton.d.ts.map +1 -1
  63. package/src/engine/input/ecs/ism/trigger/InputTriggerXRButton.js +12 -2
  64. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +13 -14
  65. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
  66. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +137 -36
  67. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts +30 -0
  68. package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -1
  69. package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +33 -0
  70. package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +2 -1
  71. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +10 -1
  72. package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -1
  73. package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +36 -14
  74. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +15 -2
  75. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  76. package/src/engine/physics/cloth/ecs/ClothInstance.js +17 -2
  77. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  78. package/src/engine/physics/cloth/ecs/ClothWorld.js +19 -6
  79. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +18 -20
  80. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  81. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +139 -89
  82. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  83. package/src/engine/physics/ecs/PhysicsSystem.js +32 -16
  84. package/src/shade/playground/water_refraction/README.md +149 -0
  85. package/src/shade/playground/water_refraction/index.html +42 -0
  86. package/src/shade/playground/water_refraction/main.d.ts +2 -0
  87. package/src/shade/playground/water_refraction/main.d.ts.map +1 -0
  88. package/src/shade/playground/water_refraction/main.js +201 -0
  89. package/src/shade/playground/water_refraction/world.d.ts +37 -0
  90. package/src/shade/playground/water_refraction/world.d.ts.map +1 -0
  91. package/src/shade/playground/water_refraction/world.js +137 -0
  92. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  93. package/src/shade/renderer/Renderer.js +4 -0
  94. package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts +2 -3
  95. package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts.map +1 -1
  96. package/src/shade/renderer/animation/chunk_pose_accumulator.js +14 -24
  97. package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_reduce.d.ts.map +1 -1
  98. package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_reduce.js +16 -15
  99. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.js +1 -1
  100. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +1123 -1122
  101. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +202 -201
  102. package/src/shade/renderer/light/environment/chunk_roughness_to_mip_ratio.d.ts +8 -0
  103. package/src/shade/renderer/light/environment/chunk_roughness_to_mip_ratio.d.ts.map +1 -0
  104. package/src/shade/renderer/light/environment/chunk_roughness_to_mip_ratio.js +24 -0
  105. package/src/shade/renderer/light/environment/chunk_sphere_probe_roughness_to_lod.d.ts +0 -6
  106. package/src/shade/renderer/light/environment/chunk_sphere_probe_roughness_to_lod.d.ts.map +1 -1
  107. package/src/shade/renderer/light/environment/chunk_sphere_probe_roughness_to_lod.js +2 -25
  108. package/src/shade/renderer/light/environment/shader_project_environment_sh.d.ts +2 -2
  109. package/src/shade/renderer/light/environment/shader_project_environment_sh.d.ts.map +1 -1
  110. package/src/shade/renderer/light/environment/shader_project_environment_sh.js +50 -19
  111. package/src/shade/renderer/particles/DESIGN.md +1 -1
  112. package/src/shade/renderer/particles/bounds/chunk_particle_bounds.d.ts +1 -1
  113. package/src/shade/renderer/particles/bounds/chunk_particle_bounds.d.ts.map +1 -1
  114. package/src/shade/renderer/particles/bounds/chunk_particle_bounds.js +10 -9
  115. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +17 -0
  116. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  117. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +7 -0
  118. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.d.ts +4 -0
  119. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.d.ts.map +1 -0
  120. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.js +11 -0
  121. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.d.ts +4 -0
  122. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.d.ts.map +1 -0
  123. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.js +19 -0
  124. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.d.ts.map +1 -1
  125. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +5 -3
  126. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.d.ts +4 -0
  127. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.d.ts.map +1 -0
  128. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.js +8 -0
  129. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts +1 -1
  130. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  131. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +21 -2
  132. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.d.ts.map +1 -1
  133. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.js +4 -8
  134. package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.d.ts.map +1 -1
  135. package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.js +10 -8
  136. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_add_f32_storage.d.ts +12 -0
  137. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_add_f32_storage.d.ts.map +1 -0
  138. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_add_f32_storage.js +25 -0
  139. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_max_f32_storage.d.ts +12 -0
  140. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_max_f32_storage.d.ts.map +1 -0
  141. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_max_f32_storage.js +28 -0
  142. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_min_f32_storage.d.ts +12 -0
  143. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_min_f32_storage.d.ts.map +1 -0
  144. package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_min_f32_storage.js +28 -0
  145. package/src/shade/renderer/shader/chunk/geometry/plane/{plane_ray_raycast.d.ts → chunk_plane_ray_raycast.d.ts} +2 -2
  146. package/src/shade/renderer/shader/chunk/geometry/plane/chunk_plane_ray_raycast.d.ts.map +1 -0
  147. package/src/shade/renderer/shader/chunk/geometry/plane/{plane_ray_raycast.js → chunk_plane_ray_raycast.js} +1 -1
  148. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_newton_ray.d.ts +4 -0
  149. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_newton_ray.d.ts.map +1 -0
  150. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_newton_ray.js +101 -0
  151. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.js +3 -3
  152. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +62 -29
  153. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  154. package/src/shade/renderer/water/GPUWaterRenderer.js +235 -147
  155. package/src/shade/renderer/water/chunk_water_transport.d.ts +5 -0
  156. package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -0
  157. package/src/shade/renderer/water/chunk_water_transport.js +94 -0
  158. package/src/shade/renderer/water/shader_water.d.ts +9 -26
  159. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  160. package/src/shade/renderer/water/shader_water.js +384 -246
  161. package/src/shade/renderer/water/shader_water_avboit.d.ts +12 -0
  162. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -0
  163. package/src/shade/renderer/water/shader_water_avboit.js +258 -0
  164. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  165. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +13 -0
  166. package/src/shade/renderer/animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.d.ts +0 -29
  167. package/src/shade/renderer/animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.d.ts.map +0 -1
  168. package/src/shade/renderer/animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.js +0 -59
  169. package/src/shade/renderer/shader/chunk/geometry/plane/plane_ray_raycast.d.ts.map +0 -1
@@ -1,3 +1,4 @@
1
+ import { WebGPUExtensionType } from "../../../descriptor/WebGPUExtensionType.js";
1
2
  import { chunk_get_ibl_irradiance } from "../../deferred/indirect/chunk_get_ibl_irradiance.js";
2
3
  import { PI_DECLARATION } from "../../shader/chunk/math/PI_DECLARATION.js";
3
4
  import { chunk_sphere_fibonacci_point } from "../../shader/chunk/geometry/sphere/chunk_sphere_fibonacci_point.js";
@@ -21,12 +22,12 @@ export const ENVIRONMENT_SH_TYPE = WebGPUArray.from(vec4f, 4);
21
22
 
22
23
  /**
23
24
  * Directions the projection samples, spread evenly over the sphere (`sphere_fibonacci_point`).
24
- * The field is the environment at the roughness diffuse reads it at, so this is far more than its
25
- * two bands can hold, and it costs nothing that recurs: the pass runs when the environment changes.
25
+ * The field is already prefiltered at the roughness diffuse reads it at; these samples project
26
+ * that smooth field into two bands. The pass runs only when the environment changes.
26
27
  *
27
28
  * @type {number}
28
29
  */
29
- export const ENVIRONMENT_SH_SAMPLE_COUNT = 1024;
30
+ export const ENVIRONMENT_SH_SAMPLE_COUNT = 256;
30
31
 
31
32
  const resources = new ShaderResourceSetDescriptor();
32
33
 
@@ -39,28 +40,56 @@ const body = CodeChunk.from(
39
40
  //language=WGSL
40
41
  `
41
42
  const SAMPLE_COUNT : u32 = ${ENVIRONMENT_SH_SAMPLE_COUNT}u;
43
+ // The minimum subgroup size is four, so this holds every subgroup's partial sum.
44
+ const MAX_SUBGROUP_PARTIALS : u32 = SAMPLE_COUNT / 4u;
45
+
46
+ var<workgroup> wg_partial_count: atomic<u32>;
47
+ var<workgroup> wg_sh_0: array<vec3<f32>, MAX_SUBGROUP_PARTIALS>;
48
+ var<workgroup> wg_sh_1: array<vec3<f32>, MAX_SUBGROUP_PARTIALS>;
49
+ var<workgroup> wg_sh_2: array<vec3<f32>, MAX_SUBGROUP_PARTIALS>;
50
+ var<workgroup> wg_sh_3: array<vec3<f32>, MAX_SUBGROUP_PARTIALS>;
51
+
52
+ // One workgroup projects the sphere, with one invocation per sample.
53
+ @compute @workgroup_size(${ENVIRONMENT_SH_SAMPLE_COUNT})
54
+ fn main(@builtin(local_invocation_index) thread_index: u32) {
55
+ let direction = sphere_fibonacci_point(f32(thread_index), f32(SAMPLE_COUNT));
56
+
57
+ // exactly what the forward mesh path takes as a surface's diffuse irradiance under IBL
58
+ let irradiance = get_ibl_irradiance(direction);
59
+ let basis = sh2_basis_at(direction);
60
+
61
+ let sh_0_partial = subgroupAdd(irradiance * basis[0]);
62
+ let sh_1_partial = subgroupAdd(irradiance * basis[1]);
63
+ let sh_2_partial = subgroupAdd(irradiance * basis[2]);
64
+ let sh_3_partial = subgroupAdd(irradiance * basis[3]);
65
+
66
+ // Workgroup variables start zeroed. One elected lane claims a distinct slot per subgroup;
67
+ // local invocation indices need not map to subgroups in contiguous blocks.
68
+ if (subgroupElect()) {
69
+ let slot = atomicAdd(&wg_partial_count, 1u);
70
+ wg_sh_0[slot] = sh_0_partial;
71
+ wg_sh_1[slot] = sh_1_partial;
72
+ wg_sh_2[slot] = sh_2_partial;
73
+ wg_sh_3[slot] = sh_3_partial;
74
+ }
75
+
76
+ workgroupBarrier();
77
+
78
+ if (thread_index != 0u) {
79
+ return;
80
+ }
42
81
 
43
- // One invocation: the projection is 1024 reads that happen when the environment changes and never
44
- // otherwise, and a single lane needs no reduction and runs whole on the emulator.
45
- @compute @workgroup_size(1)
46
- fn main() {
47
82
  var sh_0 = vec3<f32>(0.0);
48
83
  var sh_1 = vec3<f32>(0.0);
49
84
  var sh_2 = vec3<f32>(0.0);
50
85
  var sh_3 = vec3<f32>(0.0);
86
+ let partial_count = atomicLoad(&wg_partial_count);
51
87
 
52
- for (var i = 0u; i < SAMPLE_COUNT; i++) {
53
- let direction = sphere_fibonacci_point(f32(i), f32(SAMPLE_COUNT));
54
-
55
- // exactly what the forward mesh path takes as a surface's diffuse irradiance under IBL
56
- let irradiance = get_ibl_irradiance(direction);
57
-
58
- let basis = sh2_basis_at(direction);
59
-
60
- sh_0 += irradiance * basis[0];
61
- sh_1 += irradiance * basis[1];
62
- sh_2 += irradiance * basis[2];
63
- sh_3 += irradiance * basis[3];
88
+ for (var i = 0u; i < partial_count; i++) {
89
+ sh_0 += wg_sh_0[i];
90
+ sh_1 += wg_sh_1[i];
91
+ sh_2 += wg_sh_2[i];
92
+ sh_3 += wg_sh_3[i];
64
93
  }
65
94
 
66
95
  // each sample stands for an equal share of the sphere
@@ -83,6 +112,8 @@ fn main() {
83
112
  PI_DECLARATION,
84
113
  ]);
85
114
 
115
+ body.addExtension(WebGPUExtensionType.Subgroups);
116
+
86
117
  /**
87
118
  * The environment as RGB SH2 of radiance ({@link ENVIRONMENT_SH_TYPE}): the form the renderer's other
88
119
  * indirect lighting — Brick4, the light probe volume — already hands over, so the froxel GI stage
@@ -353,7 +353,7 @@ finished appending to the alive list:
353
353
  `particle_billboard_radius`, the largest offset `particle_billboard_offset` can produce for that
354
354
  size, velocity and projection, over every corner, every roll and any camera. The box has to hold
355
355
  the *quads*, not the centres, and it has to be camera-independent, because it is read on a later
356
- frame. The merge is `aabb_atomic_min_f32` / `aabb_atomic_max_f32`, the same CAS-spin the
356
+ frame. The merge is `atomic_min_f32_storage` / `atomic_max_f32_storage`, the same CAS-spin the
357
357
  skinned-mesh bounds refresh uses; both load first and return without a CAS once the box holds the
358
358
  contribution, so what survives is load traffic, not exchanges. Dispatched indirectly from
359
359
  `sim_dispatch_args`, the args the coherence reset wrote from the GPU's own alive count.
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * ## Why f32 in the buffer, and not an order-preserving encoding
15
15
  *
16
- * `aabb_atomic_min_f32` / `aabb_atomic_max_f32` are the engine's, shared with the skinned-mesh
16
+ * `atomic_min_f32_storage` / `atomic_max_f32_storage` are the engine's, shared with the skinned-mesh
17
17
  * bounds refresh, and they CAS-spin over the plain float so the words are readable as floats at
18
18
  * every moment of the frame. The sign-flip encoding that would let `atomicMin` do it in one
19
19
  * instruction leaves the buffer in a form only a decoder understands, and the publish pass reads
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_particle_bounds.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/bounds/chunk_particle_bounds.js"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,0CAFU,SAAS,CAwEyC;AAE5D;;;;;;;;;;;;;;;;GAgBG;AACH,8CAFU,SAAS,CA4CsC;0BApL/B,oCAAoC"}
1
+ {"version":3,"file":"chunk_particle_bounds.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/bounds/chunk_particle_bounds.js"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,0CAFU,SAAS,CAwE8E;AAEjG;;;;;;;;;;;;;;;;GAgBG;AACH,8CAFU,SAAS,CA4CsC;0BArL/B,oCAAoC"}
@@ -1,5 +1,6 @@
1
1
  import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
- import { chunk_aabb_atomic_f32 } from "../../animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.js";
2
+ import { chunk_atomic_min_f32_storage } from "../../shader/chunk/atomic/chunk_atomic_min_f32_storage.js";
3
+ import { chunk_atomic_max_f32_storage } from "../../shader/chunk/atomic/chunk_atomic_max_f32_storage.js";
3
4
  import { AABB3_STRUCT } from "../../shader/chunk/geometry/aabb3/AABB3_STRUCT.js";
4
5
  import {
5
6
  PARTICLE_BOUNDS_BASE,
@@ -26,7 +27,7 @@ import { chunk_particle_render_math } from "../shaders/chunk_particle_render_mat
26
27
  *
27
28
  * ## Why f32 in the buffer, and not an order-preserving encoding
28
29
  *
29
- * `aabb_atomic_min_f32` / `aabb_atomic_max_f32` are the engine's, shared with the skinned-mesh
30
+ * `atomic_min_f32_storage` / `atomic_max_f32_storage` are the engine's, shared with the skinned-mesh
30
31
  * bounds refresh, and they CAS-spin over the plain float so the words are readable as floats at
31
32
  * every moment of the frame. The sign-flip encoding that would let `atomicMin` do it in one
32
33
  * instruction leaves the buffer in a form only a decoder understands, and the publish pass reads
@@ -71,12 +72,12 @@ fn particle_bounds_contribute(row : u32, center : vec3<f32>, radius : f32) {
71
72
  let lo = center - vec3<f32>(radius);
72
73
  let hi = center + vec3<f32>(radius);
73
74
 
74
- aabb_atomic_min_f32(&counters[base + 0u], lo.x);
75
- aabb_atomic_min_f32(&counters[base + 1u], lo.y);
76
- aabb_atomic_min_f32(&counters[base + 2u], lo.z);
77
- aabb_atomic_max_f32(&counters[base + 3u], hi.x);
78
- aabb_atomic_max_f32(&counters[base + 4u], hi.y);
79
- aabb_atomic_max_f32(&counters[base + 5u], hi.z);
75
+ atomic_min_f32_storage(&counters[base + 0u], lo.x);
76
+ atomic_min_f32_storage(&counters[base + 1u], lo.y);
77
+ atomic_min_f32_storage(&counters[base + 2u], lo.z);
78
+ atomic_max_f32_storage(&counters[base + 3u], hi.x);
79
+ atomic_max_f32_storage(&counters[base + 4u], hi.y);
80
+ atomic_max_f32_storage(&counters[base + 5u], hi.z);
80
81
  }
81
82
 
82
83
  // What the frame accumulated for one row. Empty (see \`particle_bounds_is_empty\`) when nothing
@@ -117,7 +118,7 @@ fn particle_bounds_reset(row : u32) {
117
118
  fn particle_bounds_is_empty(box : ${AABB3_STRUCT.wgsl_ref}) -> bool {
118
119
  return any(box.min > box.max);
119
120
  }
120
- `, [chunk_aabb_atomic_f32, AABB3_STRUCT.declaration_chunk]);
121
+ `, [chunk_atomic_min_f32_storage, chunk_atomic_max_f32_storage, AABB3_STRUCT.declaration_chunk]);
121
122
 
122
123
  /**
123
124
  * One live particle's contribution to its emitter's box: where its quad is, and how far the quad
@@ -34,6 +34,23 @@
34
34
  * channel without the method is always asked.
35
35
  */
36
36
  export type AVBOITSideChannel = {
37
+ /**
38
+ * Optional optics preparation before occupancy; at most one producer per view. Inputs are
39
+ * immutable opaque resources. The returned background is read by the one shared resolve.
40
+ * Keep prepared state per graph/camera, not on an entity or in a global current-view slot.
41
+ */
42
+ avboit_prepare?: (args: {
43
+ graph: import("../../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph;
44
+ view_ctx: import("../../../view/GPUViewContext.js").GPUViewContext;
45
+ camera: number;
46
+ color_texture: number;
47
+ depth_texture: number;
48
+ normal_texture: number;
49
+ hzb_texture: number;
50
+ environment_texture: number;
51
+ }) => {
52
+ background_color?: number;
53
+ };
37
54
  /**
38
55
  * add the channel's slices to the occupancy bits; returns the bits'
39
56
  * handle after the write. `cluster_parameters` is the frame's depth curve (`avboit_build_depth_curve`).
@@ -1 +1 @@
1
- {"version":3,"file":"AVBOITSideChannel.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAoCc,CAAC,IAAI,EAAE;QACpB,KAAW,EAAE,OAAO,iEAAiE,EAAE,UAAU,CAAC;QAClG,MAAY,EAAE,MAAM,CAAC;QACrB,kBAAwB,EAAE,UAAU,MAAM,CAAC,CAAC;QAC5C,SAAe,EAAE,MAAM,CAAC;KACrB,KAAK,MAAM;;;;;;;;kBAED,CAAC,IAAI,EAAE;QACpB,KAAW,EAAE,OAAO,iEAAiE,EAAE,UAAU,CAAC;QAClG,MAAY,EAAE,MAAM,CAAC;QACrB,IAAU,EAAE,MAAM,CAAC;QACnB,aAAmB,EAAE,MAAM,CAAC;QAC5B,gBAAsB,EAAE,MAAM,EAAE,CAAC;QACjC,MAAY,EAAE;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAC,CAAC;KACjE,KAAK;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC;;;;;;;;;iBAKhD,CAAC,IAAI,EAAE;QACpB,KAAW,EAAE,OAAO,iEAAiE,EAAE,UAAU,CAAC;QAClG,QAAc,EAAE,OAAO,iCAAiC,EAAE,cAAc,CAAC;QACzE,MAAY,EAAE,MAAM,CAAC;QACrB,aAAmB,EAAE,MAAM,CAAC;QAC5B,IAAU,EAAE,MAAM,CAAC;QACnB,QAAc,EAAE,MAAM,CAAC;QACvB,eAAqB,EAAE,MAAM,CAAC;QAC9B,oBAA0B,EAAE,MAAM,CAAC;QACnC,sBAA4B,EAAE;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAC,CAAC;QACxD,YAAkB,EAAE;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAC,CAAC;KACrF,KAAK;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC;;;;;;sBAM9D,MAAM,OAAO"}
1
+ {"version":3,"file":"AVBOITSideChannel.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAoCc,CAAC,IAAI,EAAE;QAAC,KAAK,EAAE,OAAO,iEAAiE,EAAE,UAAU,CAAC;QACjH,QAAc,EAAE,OAAO,iCAAiC,EAAE,cAAc,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QACzF,aAAmB,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAC3E,WAAiB,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAA;KAAC,KAAK;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAC;;;;;sBAI1E,CAAC,IAAI,EAAE;QACpB,KAAW,EAAE,OAAO,iEAAiE,EAAE,UAAU,CAAC;QAClG,MAAY,EAAE,MAAM,CAAC;QACrB,kBAAwB,EAAE,UAAU,MAAM,CAAC,CAAC;QAC5C,SAAe,EAAE,MAAM,CAAC;KACrB,KAAK,MAAM;;;;;;;;kBAED,CAAC,IAAI,EAAE;QACpB,KAAW,EAAE,OAAO,iEAAiE,EAAE,UAAU,CAAC;QAClG,MAAY,EAAE,MAAM,CAAC;QACrB,IAAU,EAAE,MAAM,CAAC;QACnB,aAAmB,EAAE,MAAM,CAAC;QAC5B,gBAAsB,EAAE,MAAM,EAAE,CAAC;QACjC,MAAY,EAAE;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAC,CAAC;KACjE,KAAK;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC;;;;;;;;;iBAKhD,CAAC,IAAI,EAAE;QACpB,KAAW,EAAE,OAAO,iEAAiE,EAAE,UAAU,CAAC;QAClG,QAAc,EAAE,OAAO,iCAAiC,EAAE,cAAc,CAAC;QACzE,MAAY,EAAE,MAAM,CAAC;QACrB,aAAmB,EAAE,MAAM,CAAC;QAC5B,IAAU,EAAE,MAAM,CAAC;QACnB,QAAc,EAAE,MAAM,CAAC;QACvB,eAAqB,EAAE,MAAM,CAAC;QAC9B,oBAA0B,EAAE,MAAM,CAAC;QACnC,sBAA4B,EAAE;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAC,CAAC;QACxD,YAAkB,EAAE;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAC,CAAC;KACrF,KAAK;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC;;;;;;sBAM9D,MAAM,OAAO"}
@@ -34,6 +34,13 @@
34
34
  * channel without the method is always asked.
35
35
  *
36
36
  * @typedef {object} AVBOITSideChannel
37
+ * @property {(args: {graph: import("../../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph,
38
+ * view_ctx: import("../../../view/GPUViewContext.js").GPUViewContext, camera: number,
39
+ * color_texture: number, depth_texture: number, normal_texture: number,
40
+ * hzb_texture: number, environment_texture: number}) => {background_color?: number}} [avboit_prepare]
41
+ * Optional optics preparation before occupancy; at most one producer per view. Inputs are
42
+ * immutable opaque resources. The returned background is read by the one shared resolve.
43
+ * Keep prepared state per graph/camera, not on an entity or in a global current-view slot.
37
44
  * @property {(args: {
38
45
  * graph: import("../../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph,
39
46
  * camera: number,
@@ -0,0 +1,4 @@
1
+ /** Stable lost throughput at tiny extinction; a fixed norm cutoff drops bright faint surfaces. */
2
+ export const chunk_avboit_renormalization: CodeChunk;
3
+ import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
4
+ //# sourceMappingURL=chunk_avboit_renormalization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_avboit_renormalization.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.js"],"names":[],"mappings":"AAEA,kGAAkG;AAClG,qDAOG;0BAVuB,uCAAuC"}
@@ -0,0 +1,11 @@
1
+ import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
2
+
3
+ /** Stable lost throughput at tiny extinction; a fixed norm cutoff drops bright faint surfaces. */
4
+ export const chunk_avboit_renormalization = CodeChunk.from(/* language=WGSL */ `
5
+ fn avboit_renormalization(extinction: vec3f, norm: vec3f) -> vec3f {
6
+ let x = max(extinction, vec3f(0.0));
7
+ let small_loss = x * (1.0 - 0.5 * x + x * x / 6.0);
8
+ let loss = select(vec3f(1.0) - exp(-x), small_loss, x < vec3f(0.001));
9
+ return select(vec3f(0.0), min(loss / max(norm, vec3f(1e-20)), vec3f(65504.0)), norm > vec3f(0.0));
10
+ }
11
+ `);
@@ -0,0 +1,4 @@
1
+ /** A covering RGB-throughput surface; the existing particle/scalar entry point stays unchanged. */
2
+ export const chunk_avboit_rgb_contribution: CodeChunk;
3
+ import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
4
+ //# sourceMappingURL=chunk_avboit_rgb_contribution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_avboit_rgb_contribution.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.js"],"names":[],"mappings":"AAGA,mGAAmG;AACnG,sDAc8C;0BAlBpB,uCAAuC"}
@@ -0,0 +1,19 @@
1
+ import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
2
+ import { chunk_avboit_premultiplied_contribution } from "./chunk_avboit_premultiplied_contribution.js";
3
+
4
+ /** A covering RGB-throughput surface; the existing particle/scalar entry point stays unchanged. */
5
+ export const chunk_avboit_rgb_contribution = CodeChunk.from(/* language=WGSL */ `
6
+ fn avboit_rgb_contribution(
7
+ radiance: vec3<f32>, self_transmittance: vec3<f32>,
8
+ front_transmittance: vec3<f32>, fog: vec4<f32>,
9
+ ) -> AVBOITContribution {
10
+ let t = clamp(self_transmittance, vec3<f32>(1e-6), vec3<f32>(1.0));
11
+ let loss = vec3<f32>(1.0) - t;
12
+ var out: AVBOITContribution;
13
+ out.color = vec4<f32>((radiance * fog.w + loss * fog.xyz) * front_transmittance, 0.0);
14
+ out.norm = vec4<f32>(loss * front_transmittance, 0.0);
15
+ out.extinction = vec4<f32>(-log(t), 0.0);
16
+ out.emission = vec4<f32>(0.0);
17
+ return out;
18
+ }
19
+ `, [chunk_avboit_premultiplied_contribution]);
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_avboit_splat_slice.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;GAcG;AACH,uCAFU,SAAS,CAuCjB;0BAzDwB,uCAAuC"}
1
+ {"version":3,"file":"chunk_avboit_splat_slice.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;GAcG;AACH,uCAFU,SAAS,CAyCjB;0BA3DwB,uCAAuC"}
@@ -21,12 +21,10 @@ import { chunk_avboit_pack_counts } from "./chunk_avboit_pack_counts.js";
21
21
  export const chunk_avboit_splat_slice = CodeChunk.from(
22
22
  //language=WGSL
23
23
  `
24
- fn avboit_splat_slice(column: u32, slice: i32, extinction: vec3<f32>, texel: vec2<u32>) {
24
+ fn avboit_splat_counts(column: u32, slice: i32, counts: vec3<u32>, texel: vec2<u32>) {
25
25
  let physical = i32(warp.physical_count);
26
26
  let s = clamp(slice, 0, physical - 1);
27
27
 
28
- let counts = avboit_extinction_to_counts(extinction);
29
-
30
28
  if (all(counts == vec3<u32>(0u))) {
31
29
  return;
32
30
  }
@@ -50,6 +48,10 @@ fn avboit_splat_slice(column: u32, slice: i32, extinction: vec3<f32>, texel: vec
50
48
  }
51
49
  }
52
50
  }
51
+
52
+ fn avboit_splat_slice(column: u32, slice: i32, extinction: vec3<f32>, texel: vec2<u32>) {
53
+ avboit_splat_counts(column, slice, avboit_extinction_to_counts(extinction), texel);
54
+ }
53
55
  `, [
54
56
  chunk_avboit_extinction_to_counts,
55
57
  chunk_avboit_overflows,
@@ -0,0 +1,4 @@
1
+ /** Partition already quantized counts. Rounding two fractional extinctions can erase both. */
2
+ export const chunk_avboit_split_counts: CodeChunk;
3
+ import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
4
+ //# sourceMappingURL=chunk_avboit_split_counts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_avboit_split_counts.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.js"],"names":[],"mappings":"AAEA,8FAA8F;AAC9F,kDAIG;0BAPuB,uCAAuC"}
@@ -0,0 +1,8 @@
1
+ import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
2
+
3
+ /** Partition already quantized counts. Rounding two fractional extinctions can erase both. */
4
+ export const chunk_avboit_split_counts = CodeChunk.from(/* language=WGSL */ `
5
+ fn avboit_split_counts(counts: vec3<u32>, fraction: f32) -> vec3<u32> {
6
+ return min(counts, vec3<u32>(vec3<f32>(counts) * clamp(fraction, 0.0, 1.0) + 0.5));
7
+ }
8
+ `);
@@ -164,7 +164,7 @@ export function avboit_create_accumulators(pass: FramePassBuilder, resolution: A
164
164
  * sources of transparent fragments; the MBOIT orchestrator ignores them
165
165
  * @returns {number} resource ID of the composited color texture
166
166
  */
167
- export function graph_rasterize_meshes_transparent_avboit({ graph, buckets, view_ctx, viewport, depth_texture, color_texture, limits, light_cluster_parameters, light_cluster_lookup, light_cluster_data, shadowmap_atlas, volumetrics_lut, volumetrics_metadata, volumetrics_irradiance, indirect_lighting_mode, avboit, side_channels, }: {
167
+ export function graph_rasterize_meshes_transparent_avboit({ graph, buckets, view_ctx, viewport, depth_texture, color_texture, normal_texture, hzb_texture, environment_texture, limits, light_cluster_parameters, light_cluster_lookup, light_cluster_data, shadowmap_atlas, volumetrics_lut, volumetrics_metadata, volumetrics_irradiance, indirect_lighting_mode, avboit, side_channels, }: {
168
168
  graph: FrameGraph;
169
169
  buckets: number;
170
170
  view_ctx: GPUViewContext;
@@ -1 +1 @@
1
- {"version":3,"file":"graph_rasterize_meshes_transparent_avboit.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js"],"names":[],"mappings":"AA4DA;;;;;GAKG;AACH,oDAHW,UAAU,MAAM,CAAC,GACf,MAAM,EAAE,CAOpB;AAED;;;;;;;;;;;;GAYG;AACH;IAT+B,KAAK;IACA,KAAK;IACd,MAAM,EAAtB,MAAM;IACqB,kBAAkB,EAA7C,UAAU,MAAM,CAAC;IACD,kBAAkB,EAAlC,MAAM;IACU,wBAAwB,EAAxC,MAAM;IACW,SAAS,GAA1B,MAAM;IACJ,MAAM,CA4DlB;AAED;;;;;;;;;;GAUG;AACH;IAP+B,KAAK;IACT,SAAS,EAAzB,MAAM;IACY,gBAAgB,EAAlC,MAAM,EAAE;IACmB,kBAAkB,EAA7C,UAAU,MAAM,CAAC;IACQ,MAAM,GAA/B,cAAc;IACZ,MAAM,CAsDlB;AAED;;;;;;;;;;;;;;;GAeG;AACH,6KAFa;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAiJjE;AAED;;;;;;;;;;GAUG;AACH;IAP+B,KAAK;IACT,IAAI,EAApB,MAAM;IACU,UAAU,EAA1B,MAAM;IACU,QAAQ,EAAxB,MAAM;IACY,gBAAgB,EAAlC,MAAM,EAAE;IACN,MAAM,CAoClB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qUAFa;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAC,CAwN7D;AAED;;;;;;;;GAQG;AACH,+EAHW,UAAU,MAAM,CAAC,GACf;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,CAe/E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH;IAtB+B,KAAK;IACT,OAAO,EAAvB,MAAM;IACkB,QAAQ;IACd,QAAQ,EAA1B,MAAM,EAAE;IACQ,aAAa,EAA7B,MAAM;IACU,aAAa,EAA7B,MAAM;IACuB,MAAM;IACnB,wBAAwB,EAAxC,MAAM;IACU,oBAAoB,EAApC,MAAM;IACU,kBAAkB,EAAlC,MAAM;IACU,eAAe,EAA/B,MAAM;IACU,eAAe,EAA/B,MAAM;IACU,oBAAoB,EAApC,MAAM;IAC6B,sBAAsB,EAAzD;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC;IAGU,sBAAsB,EAAzD,yBAAyB;IACA,MAAM,GAA/B,cAAc;IACiD,aAAa,GAA5E,OAAO,wBAAwB,EAAE,iBAAiB,EAAE;IAElD,MAAM,CA8RlB;+BAr8B8B,qBAAqB;0CA9BV,uCAAuC"}
1
+ {"version":3,"file":"graph_rasterize_meshes_transparent_avboit.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js"],"names":[],"mappings":"AA4DA;;;;;GAKG;AACH,oDAHW,UAAU,MAAM,CAAC,GACf,MAAM,EAAE,CAOpB;AAED;;;;;;;;;;;;GAYG;AACH;IAT+B,KAAK;IACA,KAAK;IACd,MAAM,EAAtB,MAAM;IACqB,kBAAkB,EAA7C,UAAU,MAAM,CAAC;IACD,kBAAkB,EAAlC,MAAM;IACU,wBAAwB,EAAxC,MAAM;IACW,SAAS,GAA1B,MAAM;IACJ,MAAM,CA4DlB;AAED;;;;;;;;;;GAUG;AACH;IAP+B,KAAK;IACT,SAAS,EAAzB,MAAM;IACY,gBAAgB,EAAlC,MAAM,EAAE;IACmB,kBAAkB,EAA7C,UAAU,MAAM,CAAC;IACQ,MAAM,GAA/B,cAAc;IACZ,MAAM,CAsDlB;AAED;;;;;;;;;;;;;;;GAeG;AACH,6KAFa;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAiJjE;AAED;;;;;;;;;;GAUG;AACH;IAP+B,KAAK;IACT,IAAI,EAApB,MAAM;IACU,UAAU,EAA1B,MAAM;IACU,QAAQ,EAAxB,MAAM;IACY,gBAAgB,EAAlC,MAAM,EAAE;IACN,MAAM,CAoClB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qUAFa;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAC,CAwN7D;AAED;;;;;;;;GAQG;AACH,+EAHW,UAAU,MAAM,CAAC,GACf;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,CAe/E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH;IAtB+B,KAAK;IACT,OAAO,EAAvB,MAAM;IACkB,QAAQ;IACd,QAAQ,EAA1B,MAAM,EAAE;IACQ,aAAa,EAA7B,MAAM;IACU,aAAa,EAA7B,MAAM;IACuB,MAAM;IACnB,wBAAwB,EAAxC,MAAM;IACU,oBAAoB,EAApC,MAAM;IACU,kBAAkB,EAAlC,MAAM;IACU,eAAe,EAA/B,MAAM;IACU,eAAe,EAA/B,MAAM;IACU,oBAAoB,EAApC,MAAM;IAC6B,sBAAsB,EAAzD;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC;IAGU,sBAAsB,EAAzD,yBAAyB;IACA,MAAM,GAA/B,cAAc;IACiD,aAAa,GAA5E,OAAO,wBAAwB,EAAE,iBAAiB,EAAE;IAElD,MAAM,CAiTlB;+BAx9B8B,qBAAqB;0CA9BV,uCAAuC"}
@@ -724,6 +724,9 @@ export function graph_rasterize_meshes_transparent_avboit({
724
724
  viewport,
725
725
  depth_texture,
726
726
  color_texture,
727
+ normal_texture,
728
+ hzb_texture,
729
+ environment_texture,
727
730
  limits,
728
731
  light_cluster_parameters,
729
732
  light_cluster_lookup,
@@ -809,7 +812,7 @@ export function graph_rasterize_meshes_transparent_avboit({
809
812
  const primitive_front = construct_primitive_state(ShadeDrawMode.Triangles, ShadeDrawSide.Front);
810
813
  const primitive_double = construct_primitive_state(ShadeDrawMode.Triangles, ShadeDrawSide.Double);
811
814
 
812
- const gr_hzb = graph_import_texture(graph, view_ctx.hierarchical_z_buffer.texture);
815
+ const gr_hzb = hzb_texture ?? graph_import_texture(graph, view_ctx.hierarchical_z_buffer.texture);
813
816
  const gr_camera = graph_import_buffer(graph, view_ctx.camera.buffer.buffer);
814
817
 
815
818
  const voxel_resolution = avboit_voxel_resolution(view_ctx.resolution);
@@ -819,6 +822,22 @@ export function graph_rasterize_meshes_transparent_avboit({
819
822
  const camera = view_ctx.camera.camera;
820
823
  const cluster_parameters = avboit_build_depth_curve(camera.near, camera.far);
821
824
 
825
+ // A background producer transports only immutable opaque radiance. Reject ambiguity before
826
+ // recording any preparation rather than letting channel registration order choose a winner.
827
+ const preparers = side_channels.filter(channel => typeof channel.avboit_prepare === "function");
828
+ if (preparers.length > 1) {
829
+ throw new Error("AVBOIT supports one refractive background producer per view");
830
+ }
831
+ let background_color = color_texture;
832
+ for (const channel of preparers) {
833
+ const prepared = channel.avboit_prepare({ graph, view_ctx, camera: gr_camera, color_texture,
834
+ depth_texture, normal_texture, hzb_texture: gr_hzb, environment_texture });
835
+ if (prepared?.background_color !== undefined) {
836
+ assert.isNonNegativeInteger(prepared.background_color, 'prepared.background_color');
837
+ background_color = prepared.background_color;
838
+ }
839
+ }
840
+
822
841
  // Draw artifacts (shared with MBOIT)
823
842
  // ======
824
843
 
@@ -992,7 +1011,7 @@ export function graph_rasterize_meshes_transparent_avboit({
992
1011
  shader: shader_avboit_resolve,
993
1012
  output_resolution: view_ctx.resolution,
994
1013
  inputs: {
995
- tScene: color_texture,
1014
+ tScene: background_color,
996
1015
  tColor: accumulators.color,
997
1016
  tNorm: accumulators.norm,
998
1017
  tExtinction: accumulators.extinction,
@@ -1 +1 @@
1
- {"version":3,"file":"shader_avboit_resolve.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.js"],"names":[],"mappings":"AA4EA,gDAUE;4BApF0B,gCAAgC"}
1
+ {"version":3,"file":"shader_avboit_resolve.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.js"],"names":[],"mappings":"AAwEA,gDAUE;4BAhF0B,gCAAgC"}
@@ -3,6 +3,7 @@ import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
3
3
  import { ImageShader } from "../../../shader/ImageShader.js";
4
4
  import { ShaderResourceSetDescriptor } from "../../../shader/resource/ShaderResourceSetDescriptor.js";
5
5
  import { ShaderDescriptor } from "../../../shader/ShaderDescriptor.js";
6
+ import { chunk_avboit_renormalization } from "./chunk_avboit_renormalization.js";
6
7
 
7
8
  const resources = new ShaderResourceSetDescriptor();
8
9
  resources.createGroup()
@@ -19,7 +20,7 @@ resources.createGroup()
19
20
  *
20
21
  * ```
21
22
  * T_total = exp(-Σ extinction)
22
- * norm = Σ norm > ε ? (1 - T_total) / Σ norm : 0
23
+ * norm = Σ norm > 0 ? stable_lost_throughput(Σ extinction) / Σ norm : 0
23
24
  * out = scene × T_total + Σ color × norm + Σ emission
24
25
  * ```
25
26
  *
@@ -58,19 +59,14 @@ fn main(
58
59
  let total_transmittance = exp(-accum_extinction);
59
60
 
60
61
  // sum of (1 - T_self) * T at each fragment; zero where nothing transparent was drawn
61
- let safe = accum_norm > vec3<f32>(1e-4);
62
- let renormalization = select(
63
- vec3<f32>(0.0),
64
- (vec3<f32>(1.0) - total_transmittance) / max(accum_norm, vec3<f32>(1e-4)),
65
- safe
66
- );
62
+ let renormalization = avboit_renormalization(accum_extinction, accum_norm);
67
63
 
68
64
  let transparent = accum_color * renormalization;
69
65
 
70
66
  return vec4<f32>(scene.rgb * total_transmittance + transparent + accum_emission, scene.a);
71
67
  }
72
68
  `, [
73
- chunk_is_nan
69
+ chunk_is_nan, chunk_avboit_renormalization
74
70
  ]
75
71
  )
76
72
 
@@ -1 +1 @@
1
- {"version":3,"file":"shader_bvh_extract_instance_leaves.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/scene/shader_bvh_extract_instance_leaves.js"],"names":[],"mappings":"AAUA,4CAA6C;AAkH7C;;;;;;;;;;;;;;;;;GAiBG;AACH,iDAFU,aAAa,CAMpB;8BA7I2B,4BAA4B"}
1
+ {"version":3,"file":"shader_bvh_extract_instance_leaves.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/scene/shader_bvh_extract_instance_leaves.js"],"names":[],"mappings":"AAWA,4CAA6C;AAmH7C;;;;;;;;;;;;;;;;;GAiBG;AACH,iDAFU,aAAa,CAMpB;8BA9I2B,4BAA4B"}
@@ -1,7 +1,8 @@
1
1
  import { WebGPUExtensionType } from "../../descriptor/WebGPUExtensionType.js";
2
2
  import { atomic_u32, f32, u32 } from "../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
3
3
  import { WebGPUArray } from "../shader/type/WebGPUArray.js";
4
- import { chunk_aabb_atomic_f32 } from "../animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.js";
4
+ import { chunk_atomic_min_f32_storage } from "../shader/chunk/atomic/chunk_atomic_min_f32_storage.js";
5
+ import { chunk_atomic_max_f32_storage } from "../shader/chunk/atomic/chunk_atomic_max_f32_storage.js";
5
6
  import { CodeChunk } from "../shader/compiler/CodeChunk.js";
6
7
  import { ComputeShader } from "../shader/ComputeShader.js";
7
8
  import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
@@ -107,17 +108,18 @@ fn main(
107
108
  group_high = max(group_high, wg_high[s]);
108
109
  }
109
110
 
110
- aabb_atomic_min_f32(&scene_bounds[0], group_low.x);
111
- aabb_atomic_min_f32(&scene_bounds[1], group_low.y);
112
- aabb_atomic_min_f32(&scene_bounds[2], group_low.z);
113
- aabb_atomic_max_f32(&scene_bounds[3], group_high.x);
114
- aabb_atomic_max_f32(&scene_bounds[4], group_high.y);
115
- aabb_atomic_max_f32(&scene_bounds[5], group_high.z);
111
+ atomic_min_f32_storage(&scene_bounds[0], group_low.x);
112
+ atomic_min_f32_storage(&scene_bounds[1], group_low.y);
113
+ atomic_min_f32_storage(&scene_bounds[2], group_low.z);
114
+ atomic_max_f32_storage(&scene_bounds[3], group_high.x);
115
+ atomic_max_f32_storage(&scene_bounds[4], group_high.y);
116
+ atomic_max_f32_storage(&scene_bounds[5], group_high.z);
116
117
  }
117
118
  }
118
119
  `, [
119
120
  chunk_scene_database_access,
120
- chunk_aabb_atomic_f32,
121
+ chunk_atomic_min_f32_storage,
122
+ chunk_atomic_max_f32_storage,
121
123
  ]);
122
124
 
123
125
  body.addExtension(WebGPUExtensionType.Subgroups);
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Atomic f32 addition over a read-write storage atomic<u32> cell containing f32 bits.
3
+ *
4
+ * Each compare-exchange attempt adds to the current float value and writes the sum
5
+ * as plain f32 bits. Failed or spurious exchanges retry from a fresh atomic load,
6
+ * so concurrent additions are not lost.
7
+ *
8
+ * @type {CodeChunk}
9
+ */
10
+ export const chunk_atomic_add_f32_storage: CodeChunk;
11
+ import { CodeChunk } from "../../compiler/CodeChunk.js";
12
+ //# sourceMappingURL=chunk_atomic_add_f32_storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_atomic_add_f32_storage.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/shader/chunk/atomic/chunk_atomic_add_f32_storage.js"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,2CAFU,SAAS,CAehB;0BAxBuB,6BAA6B"}
@@ -0,0 +1,25 @@
1
+ import { CodeChunk } from "../../compiler/CodeChunk.js";
2
+
3
+ /**
4
+ * Atomic f32 addition over a read-write storage atomic<u32> cell containing f32 bits.
5
+ *
6
+ * Each compare-exchange attempt adds to the current float value and writes the sum
7
+ * as plain f32 bits. Failed or spurious exchanges retry from a fresh atomic load,
8
+ * so concurrent additions are not lost.
9
+ *
10
+ * @type {CodeChunk}
11
+ */
12
+ export const chunk_atomic_add_f32_storage = CodeChunk.from(
13
+ //language=WGSL
14
+ `
15
+ fn atomic_add_f32_storage(cell: ptr<storage, atomic<u32>, read_write>, value: f32) {
16
+ loop {
17
+ let old_u = atomicLoad(cell);
18
+ let old_f = bitcast<f32>(old_u);
19
+ let result = atomicCompareExchangeWeak(cell, old_u, bitcast<u32>(old_f + value));
20
+ if result.exchanged {
21
+ break;
22
+ }
23
+ }
24
+ }
25
+ `);
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Atomic f32 maximum over a read-write storage atomic<u32> cell containing f32 bits.
3
+ *
4
+ * Compare-exchange retries keep the cell in plain f32 representation. If the stored
5
+ * value already bounds the contribution, the function exits without an exchange.
6
+ * Infinities are supported; the stored value and contribution must not be NaN.
7
+ *
8
+ * @type {CodeChunk}
9
+ */
10
+ export const chunk_atomic_max_f32_storage: CodeChunk;
11
+ import { CodeChunk } from "../../compiler/CodeChunk.js";
12
+ //# sourceMappingURL=chunk_atomic_max_f32_storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_atomic_max_f32_storage.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/shader/chunk/atomic/chunk_atomic_max_f32_storage.js"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,2CAFU,SAAS,CAkBhB;0BA3BuB,6BAA6B"}
@@ -0,0 +1,28 @@
1
+ import { CodeChunk } from "../../compiler/CodeChunk.js";
2
+
3
+ /**
4
+ * Atomic f32 maximum over a read-write storage atomic<u32> cell containing f32 bits.
5
+ *
6
+ * Compare-exchange retries keep the cell in plain f32 representation. If the stored
7
+ * value already bounds the contribution, the function exits without an exchange.
8
+ * Infinities are supported; the stored value and contribution must not be NaN.
9
+ *
10
+ * @type {CodeChunk}
11
+ */
12
+ export const chunk_atomic_max_f32_storage = CodeChunk.from(
13
+ //language=WGSL
14
+ `
15
+ fn atomic_max_f32_storage(cell: ptr<storage, atomic<u32>, read_write>, value: f32) {
16
+ loop {
17
+ let old_u = atomicLoad(cell);
18
+ let old_f = bitcast<f32>(old_u);
19
+ if value <= old_f {
20
+ break;
21
+ }
22
+ let result = atomicCompareExchangeWeak(cell, old_u, bitcast<u32>(value));
23
+ if result.exchanged {
24
+ break;
25
+ }
26
+ }
27
+ }
28
+ `);
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Atomic f32 minimum over a read-write storage atomic<u32> cell containing f32 bits.
3
+ *
4
+ * Compare-exchange retries keep the cell in plain f32 representation. If the stored
5
+ * value already bounds the contribution, the function exits without an exchange.
6
+ * Infinities are supported; the stored value and contribution must not be NaN.
7
+ *
8
+ * @type {CodeChunk}
9
+ */
10
+ export const chunk_atomic_min_f32_storage: CodeChunk;
11
+ import { CodeChunk } from "../../compiler/CodeChunk.js";
12
+ //# sourceMappingURL=chunk_atomic_min_f32_storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_atomic_min_f32_storage.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/shader/chunk/atomic/chunk_atomic_min_f32_storage.js"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,2CAFU,SAAS,CAkBhB;0BA3BuB,6BAA6B"}
@@ -0,0 +1,28 @@
1
+ import { CodeChunk } from "../../compiler/CodeChunk.js";
2
+
3
+ /**
4
+ * Atomic f32 minimum over a read-write storage atomic<u32> cell containing f32 bits.
5
+ *
6
+ * Compare-exchange retries keep the cell in plain f32 representation. If the stored
7
+ * value already bounds the contribution, the function exits without an exchange.
8
+ * Infinities are supported; the stored value and contribution must not be NaN.
9
+ *
10
+ * @type {CodeChunk}
11
+ */
12
+ export const chunk_atomic_min_f32_storage = CodeChunk.from(
13
+ //language=WGSL
14
+ `
15
+ fn atomic_min_f32_storage(cell: ptr<storage, atomic<u32>, read_write>, value: f32) {
16
+ loop {
17
+ let old_u = atomicLoad(cell);
18
+ let old_f = bitcast<f32>(old_u);
19
+ if value >= old_f {
20
+ break;
21
+ }
22
+ let result = atomicCompareExchangeWeak(cell, old_u, bitcast<u32>(value));
23
+ if result.exchanged {
24
+ break;
25
+ }
26
+ }
27
+ }
28
+ `);