@woosh/meep-engine 3.61.0 → 3.61.1

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 (61) 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 +4 -0
  4. package/src/engine/graphics/ecs/decal/v2/Decal.d.ts +46 -2
  5. package/src/engine/graphics/ecs/decal/v2/Decal.d.ts.map +1 -1
  6. package/src/engine/graphics/ecs/decal/v2/Decal.js +74 -5
  7. package/src/engine/graphics/ecs/decal/v2/DecalSerializationAdapter.d.ts.map +1 -1
  8. package/src/engine/graphics/ecs/decal/v2/DecalSerializationAdapter.js +13 -1
  9. package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_1_2.d.ts +9 -0
  10. package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_1_2.d.ts.map +1 -0
  11. package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_1_2.js +37 -0
  12. package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
  13. package/src/engine/graphics3/DecalSystem.js +462 -447
  14. package/src/engine/graphics3/decal/DECAL_GPU_RECORD.d.ts +14 -0
  15. package/src/engine/graphics3/decal/DECAL_GPU_RECORD.d.ts.map +1 -1
  16. package/src/engine/graphics3/decal/DECAL_GPU_RECORD.js +53 -13
  17. package/src/engine/graphics3/decal/chunk_decal_record.d.ts +6 -1
  18. package/src/engine/graphics3/decal/chunk_decal_record.d.ts.map +1 -1
  19. package/src/engine/graphics3/decal/chunk_decal_record.js +28 -9
  20. package/src/engine/graphics3/decal/decal_gpu_records.d.ts +2 -1
  21. package/src/engine/graphics3/decal/decal_gpu_records.d.ts.map +1 -1
  22. package/src/engine/graphics3/decal/decal_gpu_records.js +26 -5
  23. package/src/engine/graphics3/decal/decal_material_samplers.d.ts +6 -0
  24. package/src/engine/graphics3/decal/decal_material_samplers.d.ts.map +1 -1
  25. package/src/engine/graphics3/decal/decal_material_samplers.js +13 -0
  26. package/src/engine/graphics3/decal/shader_cluster_assign_decals.js +1 -1
  27. package/src/engine/graphics3/decal/shader_cull_decals_frustum.js +1 -1
  28. package/src/engine/graphics3/decal/shader_decal_composite.d.ts +5 -0
  29. package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
  30. package/src/engine/graphics3/decal/shader_decal_composite.js +69 -28
  31. package/src/generation/foliage/skeleton/ShootWoodHash.d.ts +3 -2
  32. package/src/generation/foliage/skeleton/ShootWoodHash.d.ts.map +1 -1
  33. package/src/generation/foliage/skeleton/ShootWoodHash.js +25 -2
  34. package/src/shade/renderer/buffer/graph_read_buffer.d.ts +3 -1
  35. package/src/shade/renderer/buffer/graph_read_buffer.d.ts.map +1 -1
  36. package/src/shade/renderer/buffer/graph_read_buffer.js +9 -6
  37. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  38. package/src/shade/renderer/particles/GPUParticleSystem.js +1 -7
  39. package/src/shade/renderer/restir/di/chunk_restir_resolve.d.ts.map +1 -1
  40. package/src/shade/renderer/restir/di/chunk_restir_resolve.js +91 -94
  41. package/src/shade/renderer/restir/reservoir/chunk_rtxdi_stream_sample.js +1 -1
  42. package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.d.ts +14 -0
  43. package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.d.ts.map +1 -1
  44. package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.js +36 -21
  45. package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.d.ts +22 -0
  46. package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.d.ts.map +1 -0
  47. package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.js +64 -0
  48. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_vertex_normal.d.ts.map +1 -1
  49. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_vertex_normal.js +13 -18
  50. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_encode_vertex_normal.d.ts.map +1 -1
  51. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_encode_vertex_normal.js +28 -30
  52. package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_u32_to_vec2.d.ts.map +1 -1
  53. package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_u32_to_vec2.js +15 -16
  54. package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_vec2_to_u32.d.ts +0 -1
  55. package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_vec2_to_u32.d.ts.map +1 -1
  56. package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_vec2_to_u32.js +15 -18
  57. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +8 -1
  58. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +3 -3
  59. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_sh3_color_encode.d.ts +0 -2
  60. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_sh3_color_encode.d.ts.map +0 -1
  61. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_sh3_color_encode.js +0 -6
@@ -1,3 +1,4 @@
1
+ import { aabb3_intersects_segment3 } from "../../../core/geom/3d/aabb/aabb3_intersects_segment3.js";
1
2
  import { line3_compute_segment_segment_closest_points } from "../../../core/geom/3d/line/line3_compute_segment_segment_closest_points.js";
2
3
  import { shoot_radius } from "./shoot_geometry.js";
3
4
 
@@ -20,6 +21,14 @@ const CLEARANCE = 0.001;
20
21
  */
21
22
  const KEY_SPAN = 2048;
22
23
 
24
+ /**
25
+ * Margin (m) a cell is widened by when asking whether an axis line crosses it: far above the rounding of a point at
26
+ * the key's 205 m span, far below any wood, so a line along a cell's face or through its edge is under the cells either
27
+ * side of it.
28
+ * @type {number}
29
+ */
30
+ const CROSSING_TOLERANCE = WOOD_CELL * 2 ** -20;
31
+
23
32
  const SCRATCH_ST = new Float64Array(2);
24
33
 
25
34
  /**
@@ -27,7 +36,7 @@ const SCRATCH_ST = new Float64Array(2);
27
36
  * wood, and thinner wood that thicker wood has grown into can be found. A unit is added once, when it has grown, under
28
37
  * the cells its axis line crosses; a query reads every unit's place and radius from its axis as they are then, and
29
38
  * reaches as far round as the thickest wood ({@link max_radius}), so wood that thickens needs no re-adding. The units
30
- * of an axis that has died are passed over.
39
+ * of an axis that has died are passed over, and leave the hash at the next {@link refresh}.
31
40
  */
32
41
  export class ShootWoodHash {
33
42
  /** @type {Map<number, number[]>} */
@@ -89,6 +98,11 @@ export class ShootWoodHash {
89
98
  const y0 = Math.floor(Math.min(p[a + 1], p[b + 1]) / WOOD_CELL), y1 = Math.floor(Math.max(p[a + 1], p[b + 1]) / WOOD_CELL);
90
99
  const z0 = Math.floor(Math.min(p[a + 2], p[b + 2]) / WOOD_CELL), z1 = Math.floor(Math.max(p[a + 2], p[b + 2]) / WOOD_CELL);
91
100
  for (let x = x0; x <= x1; x++) for (let y = y0; y <= y1; y++) for (let z = z0; z <= z1; z++) {
101
+ if (!aabb3_intersects_segment3(
102
+ x * WOOD_CELL - CROSSING_TOLERANCE, y * WOOD_CELL - CROSSING_TOLERANCE, z * WOOD_CELL - CROSSING_TOLERANCE,
103
+ (x + 1) * WOOD_CELL + CROSSING_TOLERANCE, (y + 1) * WOOD_CELL + CROSSING_TOLERANCE, (z + 1) * WOOD_CELL + CROSSING_TOLERANCE,
104
+ p[a], p[a + 1], p[a + 2], p[b], p[b + 1], p[b + 2]
105
+ )) continue;
92
106
  const key = ((x + KEY_SPAN / 2) * KEY_SPAN + (y + KEY_SPAN / 2)) * KEY_SPAN + (z + KEY_SPAN / 2);
93
107
  let list = this.cells.get(key);
94
108
  if (list === undefined) {
@@ -102,21 +116,30 @@ export class ShootWoodHash {
102
116
 
103
117
  /**
104
118
  * Records each cell's thickest living unit, after the wood has thickened, and the thickest of all
105
- * ({@link max_radius}).
119
+ * ({@link max_radius}). A dead axis does not live again, so its units leave their cells, in the order the rest
120
+ * were added, and a cell left empty leaves the hash.
106
121
  */
107
122
  refresh() {
108
123
  const axes = this.axes;
109
124
  let most = 0;
110
125
  for (const [key, list] of this.cells) {
111
126
  let max = 0;
127
+ let kept = 0;
112
128
  for (let i = 0; i < list.length; i++) {
113
129
  const id = list[i];
114
130
  const axis = axes[this.unit_axis[id]];
115
131
  if (!axis.alive) continue;
132
+ list[kept++] = id;
116
133
  const k = this.unit_index[id];
117
134
  const thickest = axis.radii.length > k + 1 ? Math.max(axis.radii[k], axis.radii[k + 1]) : shoot_radius(axis.units[k], 0);
118
135
  if (thickest > max) max = thickest;
119
136
  }
137
+ if (kept === 0) {
138
+ this.cells.delete(key);
139
+ this.cell_max.delete(key);
140
+ continue;
141
+ }
142
+ list.length = kept;
120
143
  this.cell_max.set(key, max);
121
144
  if (max > most) most = max;
122
145
  }
@@ -5,7 +5,9 @@
5
5
  * @param {number} buffer
6
6
  * @param {number} [offset=0]
7
7
  * @param {number} [size] defaults to buffer.size - offset
8
- * @param {number} [timeout] in milliseconds, 0 for no timeout. Timeout will start immediately, meaning that if you don't schedule the graph immediately - you might see unexpected behaviour.
8
+ * @param {number} [timeout] in milliseconds, 0 for no timeout: how long the read waits for its pass to run, starting
9
+ * now. A graph that is never run, or stops at a throwing pass before this one, rejects the read here. Once the pass has
10
+ * run, the read waits for the device however far behind it is, and settles when the mapping does.
9
11
  * @returns {Promise<Reference<ArrayBuffer>>} don't forget to release the reference
10
12
  */
11
13
  export function graph_read_buffer({ graph, buffer, offset, size, timeout }: FrameGraph): Promise<Reference<ArrayBuffer>>;
@@ -1 +1 @@
1
- {"version":3,"file":"graph_read_buffer.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/buffer/graph_read_buffer.js"],"names":[],"mappings":"AAOA;;;;;;;;;GASG;AACH,yFAFa,QAAQ,UAAU,WAAW,CAAC,CAAC,CAuH3C;0BApIyB,2CAA2C"}
1
+ {"version":3,"file":"graph_read_buffer.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/buffer/graph_read_buffer.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;GAWG;AACH,yFAFa,QAAQ,UAAU,WAAW,CAAC,CAAC,CAwH3C;0BAvIyB,2CAA2C"}
@@ -12,7 +12,9 @@ const scratch_buffer_descriptor = new BufferResourceDescriptor();
12
12
  * @param {number} buffer
13
13
  * @param {number} [offset=0]
14
14
  * @param {number} [size] defaults to buffer.size - offset
15
- * @param {number} [timeout] in milliseconds, 0 for no timeout. Timeout will start immediately, meaning that if you don't schedule the graph immediately - you might see unexpected behaviour.
15
+ * @param {number} [timeout] in milliseconds, 0 for no timeout: how long the read waits for its pass to run, starting
16
+ * now. A graph that is never run, or stops at a throwing pass before this one, rejects the read here. Once the pass has
17
+ * run, the read waits for the device however far behind it is, and settles when the mapping does.
16
18
  * @returns {Promise<Reference<ArrayBuffer>>} don't forget to release the reference
17
19
  */
18
20
  export function graph_read_buffer({
@@ -47,6 +49,12 @@ export function graph_read_buffer({
47
49
  * @param {GraphicsExecutionContext} context
48
50
  */
49
51
  function execute(data, resources, context) {
52
+ // the copy is recorded: the mapping lands, or is refused, however long the device takes
53
+ if (timeout_handle !== -1) {
54
+ clearTimeout(timeout_handle);
55
+ timeout_handle = -1;
56
+ }
57
+
50
58
  /**
51
59
  * @type {GPUBuffer}
52
60
  */
@@ -94,11 +102,6 @@ export function graph_read_buffer({
94
102
  return;
95
103
  }
96
104
 
97
- if (timeout_handle !== -1) {
98
- clearTimeout(timeout_handle);
99
- timeout_handle = -1;
100
- }
101
-
102
105
  const data = destination.getMappedRange(0, _size);
103
106
 
104
107
  ref = new Reference();
@@ -1 +1 @@
1
- {"version":3,"file":"GPUParticleSystem.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/GPUParticleSystem.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GPUParticleSystem.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/particles/GPUParticleSystem.js"],"names":[],"mappings":"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"}
@@ -68,13 +68,7 @@ const STORAGE_GROWABLE = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUB
68
68
  */
69
69
  const INDIRECT = GPUBufferUsage.STORAGE | GPUBufferUsage.INDIRECT | GPUBufferUsage.COPY_SRC;
70
70
 
71
- /**
72
- * Particles a scene holds at once unless the constructor is told otherwise — and the renderer never
73
- * tells it ({@link ../Renderer.js Renderer#particles}), so this is every scene's pool. 2^17: about
74
- * 18 MB of pool, free list, alive list and coherence scratch at a 128-byte record, which a game with
75
- * dense bursts (a body dissolving into thousands of motes) fills before 65,536 does.
76
- */
77
- const DEFAULT_CAPACITY = 131072;
71
+ const DEFAULT_CAPACITY = 65536;
78
72
 
79
73
  /**
80
74
  * What {@link GPUParticleSystem#read_stats} decodes: the counts the GPU keeps between frames, named.
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_restir_resolve.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/restir/di/chunk_restir_resolve.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,mCAFU,SAAS,CA+DjB;0BAvFwB,oCAAoC"}
1
+ {"version":3,"file":"chunk_restir_resolve.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/restir/di/chunk_restir_resolve.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,mCAFU,SAAS,CA4DjB;0BApFwB,oCAAoC"}
@@ -1,94 +1,91 @@
1
- import { REFLECTED_LIGHT_STRUCT } from "../../shader/chunk/light/REFLECTED_LIGHT_STRUCT.js";
2
- import { chunk_re_direct_multiscatter } from "../../shader/chunk/material/chunk_re_direct_multiscatter.js";
3
- import { chunk_re_direct_physical } from "../../shader/chunk/material/chunk_re_direct_physical.js";
4
- import { GEOMETRIC_SHADING_INFO_STRUCT } from "../../shader/chunk/material/GEOMETRIC_SHADING_INFO_STRUCT.js";
5
- import { MATERIAL_SHADING_INFO_STRUCT } from "../../shader/chunk/material/MATERIAL_SHADING_INFO_STRUCT.js";
6
- import { RTXDI_Reservoir } from "../reservoir/RTXDI_Reservoir.js";
7
- import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
8
- import { chunk_restir_get_light_info } from "./chunk_restir_get_light_info.js";
9
- import { chunk_restir_light_ref } from "./chunk_restir_light_ref.js";
10
- import { chunk_restir_sample_light_record } from "./chunk_restir_sample_light_record.js";
11
- import { chunk_restir_trace_visibility } from "./chunk_restir_trace_visibility.js";
12
-
13
- /**
14
- * Resolve a finalized reservoir to outgoing radiance for the selected light:
15
- *
16
- * radiance = BRDF·Le·G (full RGB, unshadowed) · W · V
17
- *
18
- * where W == reservoir.weightSum after FinalizeResampling (it already folds in
19
- * 1/p_hat and 1/M) and V is the traced visibility (the RTXDI `f_rgb · weightSum`
20
- * identity). p_hat is the luminance of the single-scattering BRDF·Le·G; this
21
- * BRDF also carries `re_direct_multiscatter`'s per-pixel scale of the specular,
22
- * so f / p_hat is no longer 1 but stays within [1, that scale]. The estimate is
23
- * unbiased either way: f and p_hat are positive on the same lights.
24
- *
25
- * Visibility is a single opaque shadow ray toward the survivor's sampled emitter
26
- * point — matching the brute-force NEE reference (`ray_sample_light`), which also
27
- * uses `ray_query_occluded`. Requires the RTX resource group to be bound.
28
- *
29
- * Emissive is intentionally excluded; the deferred pass adds it once.
30
- *
31
- * @type {CodeChunk}
32
- */
33
- export const chunk_restir_resolve = CodeChunk.from(
34
- //language=WGSL
35
- `
36
- fn restir_resolve(
37
- i_coord: vec2<u32>,
38
- reservoir: ${RTXDI_Reservoir.wgsl_ref},
39
- geometry: ${GEOMETRIC_SHADING_INFO_STRUCT.wgsl_ref},
40
- material: ${MATERIAL_SHADING_INFO_STRUCT.wgsl_ref},
41
- use_screen_space_shadow: u32
42
- ) -> vec3<f32> {
43
- if (!restir_light_ref_is_valid(reservoir.lightData) || reservoir.weightSum <= 0.0) {
44
- return vec3<f32>(0.0);
45
- }
46
-
47
- let light_type = restir_light_ref_type(reservoir.lightData);
48
- let light_index = restir_light_ref_index(reservoir.lightData);
49
-
50
- // Full RGB unshadowed contribution via the representative-point incident light.
51
- let incident = restir_get_light_info(light_type, light_index, geometry.position);
52
- var reflected: ${REFLECTED_LIGHT_STRUCT.wgsl_ref};
53
- re_direct_physical(incident, geometry, material, &reflected);
54
- re_direct_multiscatter(geometry, material, &reflected);
55
- let radiance = reflected.diffuse + reflected.specular;
56
-
57
- if (all(radiance <= vec3<f32>(0.0))) {
58
- return vec3<f32>(0.0);
59
- }
60
-
61
- // Decode the stored 16-bit-fixed-point area-light sample point.
62
- let uv = vec2<f32>(
63
- f32(reservoir.uvData & 0xFFFFu) / 65535.0,
64
- f32((reservoir.uvData >> 16u) & 0xFFFFu) / 65535.0
65
- );
66
- let record = restir_sample_light_record(light_type, light_index, geometry.position, uv);
67
-
68
- var visibility = 1.0;
69
- if (record.distance > 0.0) {
70
- visibility = restir_trace_visibility(
71
- i_coord,
72
- geometry.position,
73
- geometry.geometric_normal,
74
- record.direction,
75
- record.distance,
76
- use_screen_space_shadow != 0u,
77
- );
78
- }
79
-
80
- return radiance * reservoir.weightSum * visibility;
81
- }
82
- `, [
83
- RTXDI_Reservoir.declaration_chunk,
84
- REFLECTED_LIGHT_STRUCT.declaration_chunk,
85
- GEOMETRIC_SHADING_INFO_STRUCT.declaration_chunk,
86
- MATERIAL_SHADING_INFO_STRUCT.declaration_chunk,
87
- chunk_re_direct_physical,
88
- chunk_re_direct_multiscatter,
89
- chunk_restir_get_light_info,
90
- chunk_restir_light_ref,
91
- chunk_restir_sample_light_record,
92
- chunk_restir_trace_visibility,
93
- ]
94
- );
1
+ import { REFLECTED_LIGHT_STRUCT } from "../../shader/chunk/light/REFLECTED_LIGHT_STRUCT.js";
2
+ import { chunk_re_direct_multiscatter } from "../../shader/chunk/material/chunk_re_direct_multiscatter.js";
3
+ import { chunk_re_direct_physical } from "../../shader/chunk/material/chunk_re_direct_physical.js";
4
+ import { GEOMETRIC_SHADING_INFO_STRUCT } from "../../shader/chunk/material/GEOMETRIC_SHADING_INFO_STRUCT.js";
5
+ import { MATERIAL_SHADING_INFO_STRUCT } from "../../shader/chunk/material/MATERIAL_SHADING_INFO_STRUCT.js";
6
+ import { RTXDI_Reservoir } from "../reservoir/RTXDI_Reservoir.js";
7
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
8
+ import { chunk_restir_get_light_info } from "./chunk_restir_get_light_info.js";
9
+ import { chunk_restir_light_ref } from "./chunk_restir_light_ref.js";
10
+ import { chunk_restir_sample_light_record } from "./chunk_restir_sample_light_record.js";
11
+ import { chunk_restir_trace_visibility } from "./chunk_restir_trace_visibility.js";
12
+
13
+ /**
14
+ * Resolve a finalized reservoir to outgoing radiance for the selected light:
15
+ *
16
+ * radiance = BRDF·Le·G (full RGB, unshadowed) · W · V
17
+ *
18
+ * where W == reservoir.weightSum after FinalizeResampling (it already folds in
19
+ * 1/p_hat and 1/M) and V is the traced visibility (the RTXDI `f_rgb · weightSum`
20
+ * identity). p_hat is the luminance of the single-scattering BRDF·Le·G; this
21
+ * BRDF also carries `re_direct_multiscatter`'s per-pixel scale of the specular,
22
+ * so f / p_hat is no longer 1 but stays within [1, that scale]. The estimate is
23
+ * unbiased either way: f and p_hat are positive on the same lights.
24
+ *
25
+ * Visibility is a single opaque shadow ray toward the survivor's sampled emitter
26
+ * point — matching the brute-force NEE reference (`ray_sample_light`), which also
27
+ * uses `ray_query_occluded`. Requires the RTX resource group to be bound.
28
+ *
29
+ * Emissive is intentionally excluded; the deferred pass adds it once.
30
+ *
31
+ * @type {CodeChunk}
32
+ */
33
+ export const chunk_restir_resolve = CodeChunk.from(
34
+ //language=WGSL
35
+ `
36
+ fn restir_resolve(
37
+ i_coord: vec2<u32>,
38
+ reservoir: ${RTXDI_Reservoir.wgsl_ref},
39
+ geometry: ${GEOMETRIC_SHADING_INFO_STRUCT.wgsl_ref},
40
+ material: ${MATERIAL_SHADING_INFO_STRUCT.wgsl_ref},
41
+ use_screen_space_shadow: u32
42
+ ) -> vec3<f32> {
43
+ if (!restir_light_ref_is_valid(reservoir.lightData) || reservoir.weightSum <= 0.0) {
44
+ return vec3<f32>(0.0);
45
+ }
46
+
47
+ let light_type = restir_light_ref_type(reservoir.lightData);
48
+ let light_index = restir_light_ref_index(reservoir.lightData);
49
+
50
+ // Full RGB unshadowed contribution via the representative-point incident light.
51
+ let incident = restir_get_light_info(light_type, light_index, geometry.position);
52
+ var reflected: ${REFLECTED_LIGHT_STRUCT.wgsl_ref};
53
+ re_direct_physical(incident, geometry, material, &reflected);
54
+ re_direct_multiscatter(geometry, material, &reflected);
55
+ let radiance = reflected.diffuse + reflected.specular;
56
+
57
+ if (all(radiance <= vec3<f32>(0.0))) {
58
+ return vec3<f32>(0.0);
59
+ }
60
+
61
+ // Decode the stored 16-bit-fixed-point area-light sample point.
62
+ let uv = unpack2x16unorm(reservoir.uvData);
63
+ let record = restir_sample_light_record(light_type, light_index, geometry.position, uv);
64
+
65
+ var visibility = 1.0;
66
+ if (record.distance > 0.0) {
67
+ visibility = restir_trace_visibility(
68
+ i_coord,
69
+ geometry.position,
70
+ geometry.geometric_normal,
71
+ record.direction,
72
+ record.distance,
73
+ use_screen_space_shadow != 0u,
74
+ );
75
+ }
76
+
77
+ return radiance * reservoir.weightSum * visibility;
78
+ }
79
+ `, [
80
+ RTXDI_Reservoir.declaration_chunk,
81
+ REFLECTED_LIGHT_STRUCT.declaration_chunk,
82
+ GEOMETRIC_SHADING_INFO_STRUCT.declaration_chunk,
83
+ MATERIAL_SHADING_INFO_STRUCT.declaration_chunk,
84
+ chunk_re_direct_physical,
85
+ chunk_re_direct_multiscatter,
86
+ chunk_restir_get_light_info,
87
+ chunk_restir_light_ref,
88
+ chunk_restir_sample_light_record,
89
+ chunk_restir_trace_visibility,
90
+ ]
91
+ );
@@ -36,7 +36,7 @@ fn rtxdi_stream_sample(
36
36
  if (selectSample)
37
37
  {
38
38
  reservoir.lightData = lightIndex | RTXDI_Reservoir_LightValidBit;
39
- reservoir.uvData = u32(saturate(uv.x) * 0xffff) | (u32(saturate(uv.y) * 0xffff) << 16);
39
+ reservoir.uvData = pack2x16unorm(uv);
40
40
  reservoir.targetPdf = targetPdf;
41
41
  }
42
42
 
@@ -1,4 +1,18 @@
1
1
  /**
2
+ * Decodes a packed RGBE 9-9-9-5 (`u32`) word into linear RGB (`vec3<f32>`).
3
+ *
4
+ * Bit layout:
5
+ * - `[0..8]`: 9-bit R mantissa
6
+ * - `[9..17]`: 9-bit G mantissa
7
+ * - `[18..26]`: 9-bit B mantissa
8
+ * - `[27..31]`: 5-bit biased exponent E (bias = 15, mantissa bits = 9)
9
+ *
10
+ * Rather than evaluating a transcendental `exp2(E - 24.0)` on the SFU, `2^(E - 24)` is
11
+ * constructed directly in IEEE-754 binary32 bits: shifting E from `[27..31]` down to the
12
+ * float exponent field `[23..27]` and adding the combined exponent bias `(127 - 24) << 23 = 0x33800000u`.
13
+ * Because `E` is in `[0, 31]`, the biased IEEE-754 exponent `E + 103` is in `[103, 134]`,
14
+ * which is always a normal positive float.
15
+ *
2
16
  * @see https://en.wikipedia.org/wiki/RGBE_image_format
3
17
  * @see https://github.com/zhangjiangen11/godot/blob/b64ac6341347906dacdda712dc78b574334ff4af/servers/rendering/renderer_rd/shaders/environment/hddagi_direct_light.glsl#L331
4
18
  * @type {CodeChunk}
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_rgbe9995_decode.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.js"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,oCAFU,SAAS,CAejB;0BApBwB,gCAAgC"}
1
+ {"version":3,"file":"chunk_rgbe9995_decode.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH,oCAFU,SAAS,CAgBjB;0BAnCwB,gCAAgC"}
@@ -1,21 +1,36 @@
1
- import { CodeChunk } from "../../../compiler/CodeChunk.js";
2
-
3
- /**
4
- * @see https://en.wikipedia.org/wiki/RGBE_image_format
5
- * @see https://github.com/zhangjiangen11/godot/blob/b64ac6341347906dacdda712dc78b574334ff4af/servers/rendering/renderer_rd/shaders/environment/hddagi_direct_light.glsl#L331
6
- * @type {CodeChunk}
7
- */
8
- export const chunk_rgbe9995_decode = CodeChunk.from(
9
- //language=WGSL
10
- `
11
- fn rgbe9995_decode(p_rgbe:u32) -> vec3<f32>{
12
- // shift and mask
13
- let rgbef = vec4<f32>(
14
- (vec4(p_rgbe) >> vec4<u32>(0, 9, 18, 27))
15
- & vec4<u32>(0x1FF, 0x1FF, 0x1FF, 0x1F)
16
- );
17
-
18
- return rgbef.rgb * exp2(rgbef.a - 15.0 - 9.0);
19
- }
20
- `
21
- );
1
+ import { CodeChunk } from "../../../compiler/CodeChunk.js";
2
+
3
+ /**
4
+ * Decodes a packed RGBE 9-9-9-5 (`u32`) word into linear RGB (`vec3<f32>`).
5
+ *
6
+ * Bit layout:
7
+ * - `[0..8]`: 9-bit R mantissa
8
+ * - `[9..17]`: 9-bit G mantissa
9
+ * - `[18..26]`: 9-bit B mantissa
10
+ * - `[27..31]`: 5-bit biased exponent E (bias = 15, mantissa bits = 9)
11
+ *
12
+ * Rather than evaluating a transcendental `exp2(E - 24.0)` on the SFU, `2^(E - 24)` is
13
+ * constructed directly in IEEE-754 binary32 bits: shifting E from `[27..31]` down to the
14
+ * float exponent field `[23..27]` and adding the combined exponent bias `(127 - 24) << 23 = 0x33800000u`.
15
+ * Because `E` is in `[0, 31]`, the biased IEEE-754 exponent `E + 103` is in `[103, 134]`,
16
+ * which is always a normal positive float.
17
+ *
18
+ * @see https://en.wikipedia.org/wiki/RGBE_image_format
19
+ * @see https://github.com/zhangjiangen11/godot/blob/b64ac6341347906dacdda712dc78b574334ff4af/servers/rendering/renderer_rd/shaders/environment/hddagi_direct_light.glsl#L331
20
+ * @type {CodeChunk}
21
+ */
22
+ export const chunk_rgbe9995_decode = CodeChunk.from(
23
+ //language=WGSL
24
+ `
25
+ fn rgbe9995_decode(p_rgbe: u32) -> vec3<f32> {
26
+ let rgb = vec3<f32>(
27
+ (vec3<u32>(p_rgbe) >> vec3<u32>(0u, 9u, 18u))
28
+ & vec3<u32>(0x1FFu)
29
+ );
30
+ let exp_bits = ((p_rgbe >> 4u) & 0x0F800000u) + 0x33800000u;
31
+ let scale = bitcast<f32>(exp_bits);
32
+
33
+ return rgb * scale;
34
+ }
35
+ `
36
+ );
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Software-bilinear sample of an RGBE 9-9-9-5 (`r32uint`) 2D texture using a single `textureGather`.
3
+ *
4
+ * WebGPU's `rgb9e5ufloat` format is hardware-filterable, but cannot be written as a storage texture
5
+ * (`STORAGE_BINDING`) or render attachment, nor view-aliased with `r32uint`. When an HDR texture is
6
+ * produced on the GPU via `textureStore` into `r32uint`, this function performs a 4-texel bilinear
7
+ * tap using one `textureGather`:
8
+ *
9
+ * 1. Snaps the gather UV to `(floor(uv * tex_size - 0.5) + 1.0) * inv_tex_size` (dead-center
10
+ * between the 4 texels) so the TMU's 16.8 fixed-point floor never disagrees with the ALU's
11
+ * `f32` fractional weights near half-texel boundaries.
12
+ * 2. Constructs the four `2^(E - 24)` scale factors directly in IEEE-754 float bits via shift,
13
+ * mask, bias addition (`103 << 23 = 0x33800000u`), and `bitcast<vec4<f32>>`, avoiding 4 SFU
14
+ * `exp2` instructions.
15
+ * 3. Folds the 4 shared-exponent scales into the 4 bilinear weights (`w = bilinear * scale`) and
16
+ * evaluates each RGB channel as a single `dot(mantissa, w)`.
17
+ *
18
+ * @type {CodeChunk}
19
+ */
20
+ export const chunk_rgbe9995_sample_gather: CodeChunk;
21
+ import { CodeChunk } from "../../../compiler/CodeChunk.js";
22
+ //# sourceMappingURL=chunk_rgbe9995_sample_gather.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_rgbe9995_sample_gather.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH,2CAFU,SAAS,CA4CjB;0BA/DwB,gCAAgC"}
@@ -0,0 +1,64 @@
1
+ import { CodeChunk } from "../../../compiler/CodeChunk.js";
2
+
3
+ /**
4
+ * Software-bilinear sample of an RGBE 9-9-9-5 (`r32uint`) 2D texture using a single `textureGather`.
5
+ *
6
+ * WebGPU's `rgb9e5ufloat` format is hardware-filterable, but cannot be written as a storage texture
7
+ * (`STORAGE_BINDING`) or render attachment, nor view-aliased with `r32uint`. When an HDR texture is
8
+ * produced on the GPU via `textureStore` into `r32uint`, this function performs a 4-texel bilinear
9
+ * tap using one `textureGather`:
10
+ *
11
+ * 1. Snaps the gather UV to `(floor(uv * tex_size - 0.5) + 1.0) * inv_tex_size` (dead-center
12
+ * between the 4 texels) so the TMU's 16.8 fixed-point floor never disagrees with the ALU's
13
+ * `f32` fractional weights near half-texel boundaries.
14
+ * 2. Constructs the four `2^(E - 24)` scale factors directly in IEEE-754 float bits via shift,
15
+ * mask, bias addition (`103 << 23 = 0x33800000u`), and `bitcast<vec4<f32>>`, avoiding 4 SFU
16
+ * `exp2` instructions.
17
+ * 3. Folds the 4 shared-exponent scales into the 4 bilinear weights (`w = bilinear * scale`) and
18
+ * evaluates each RGB channel as a single `dot(mantissa, w)`.
19
+ *
20
+ * @type {CodeChunk}
21
+ */
22
+ export const chunk_rgbe9995_sample_gather = CodeChunk.from(
23
+ //language=WGSL
24
+ `
25
+ fn rgbe9995_sample_gather(
26
+ tex: texture_2d<u32>,
27
+ samp: sampler,
28
+ uv: vec2<f32>,
29
+ tex_size: vec2<f32>,
30
+ inv_tex_size: vec2<f32>
31
+ ) -> vec3<f32> {
32
+ // 1. Align UV to prevent 16.8 fixed-point TMU vs f32 ALU boundary mismatch
33
+ let coord = uv * tex_size - 0.5;
34
+ let base = floor(coord);
35
+ let f = coord - base;
36
+ let gather_uv = (base + 1.0) * inv_tex_size;
37
+
38
+ // WebGPU textureGather component order:
39
+ // .x = (u0, v1) [bottom-left], .y = (u1, v1) [bottom-right]
40
+ // .z = (u1, v0) [top-right], .w = (u0, v0) [top-left]
41
+ let raw: vec4<u32> = textureGather(0, tex, samp, gather_uv);
42
+
43
+ // 2. Construct 2^(E - 24) directly in IEEE-754 float bits:
44
+ // Shift E from [27..31] to [23..27] and add bias (103 << 23 = 0x33800000u)
45
+ let exp_bits = ((raw >> vec4<u32>(4u)) & vec4<u32>(0x0F800000u)) + vec4<u32>(0x33800000u);
46
+ let scale = bitcast<vec4<f32>>(exp_bits);
47
+
48
+ // 3. Fold bilinear weights and shared-exponent scales into a single vec4 weight
49
+ let w = vec4<f32>(
50
+ (1.0 - f.x) * f.y, // .x: (u0, v1)
51
+ f.x * f.y, // .y: (u1, v1)
52
+ f.x * (1.0 - f.y), // .z: (u1, v0)
53
+ (1.0 - f.x) * (1.0 - f.y)// .w: (u0, v0)
54
+ ) * scale;
55
+
56
+ // 4. Extract 9-bit mantissas and dot with combined weights
57
+ let r = vec4<f32>(raw & vec4<u32>(0x1FFu));
58
+ let g = vec4<f32>((raw >> vec4<u32>(9u)) & vec4<u32>(0x1FFu));
59
+ let b = vec4<f32>((raw >> vec4<u32>(18u)) & vec4<u32>(0x1FFu));
60
+
61
+ return vec3<f32>(dot(r, w), dot(g, w), dot(b, w));
62
+ }
63
+ `
64
+ );
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_decode_vertex_normal.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_vertex_normal.js"],"names":[],"mappings":"AAGA,mDAcE;0BAjBwB,gCAAgC"}
1
+ {"version":3,"file":"chunk_decode_vertex_normal.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_vertex_normal.js"],"names":[],"mappings":"AAGA,mDASE;0BAZwB,gCAAgC"}
@@ -1,18 +1,13 @@
1
- import { CodeChunk } from "../../../compiler/CodeChunk.js";
2
- import { chunk_uv_octahedral_unit_decode } from "../octahedron/chunk_uv_octahedral_unit_decode.js";
3
-
4
- export const chunk_decode_vertex_normal = CodeChunk.from(
5
- //language=WGSL
6
- `
7
- fn decode_vertex_normal(base: u32) -> vec3<f32>{
8
-
9
- let decode = (vec2(base) >> vec2(0u, 16u)) & vec2(0xFFFFu, 0xFFFFu);
10
-
11
- let norm = vec2<f32>(decode) / vec2(65535.0, 65535.0);
12
-
13
- return uv_octahedral_unit_decode(norm);
14
- }
15
- `, [
16
- chunk_uv_octahedral_unit_decode,
17
- ]
18
- );
1
+ import { CodeChunk } from "../../../compiler/CodeChunk.js";
2
+ import { chunk_uv_octahedral_unit_decode } from "../octahedron/chunk_uv_octahedral_unit_decode.js";
3
+
4
+ export const chunk_decode_vertex_normal = CodeChunk.from(
5
+ //language=WGSL
6
+ `
7
+ fn decode_vertex_normal(base: u32) -> vec3<f32>{
8
+ return uv_octahedral_unit_decode(unpack2x16unorm(base));
9
+ }
10
+ `, [
11
+ chunk_uv_octahedral_unit_decode,
12
+ ]
13
+ );
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_encode_vertex_normal.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/shader/chunk/geometry/normal/chunk_encode_vertex_normal.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AACH,yCAFU,SAAS,CAajB;0BA7BwB,gCAAgC"}
1
+ {"version":3,"file":"chunk_encode_vertex_normal.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/shader/chunk/geometry/normal/chunk_encode_vertex_normal.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AACH,yCAFU,SAAS,CAWjB;0BA3BwB,gCAAgC"}
@@ -1,30 +1,28 @@
1
- import { CodeChunk } from "../../../compiler/CodeChunk.js";
2
- import { chunk_uv_octahedral_unit_encode } from "../octahedron/chunk_uv_octahedral_unit_encode.js";
3
-
4
- /**
5
- * Inverse of `decode_vertex_normal` — packs a unit normal into a single
6
- * `u32` via octahedral-unit encoding into two 16-bit u-norms (one per
7
- * u32 half).
8
- *
9
- * Layout matches the decoder:
10
- * - bits [0, 15]: oct.x (16-bit u-norm of `uv_octahedral_unit_encode(n).x`)
11
- * - bits [16, 31]: oct.y
12
- *
13
- * Round-trips lossily — the 16-bit quantization gives ~1.5° worst-case
14
- * angular error, which is what the format buys us in exchange for the
15
- * 4-byte stride.
16
- *
17
- * @type {CodeChunk}
18
- */
19
- export const chunk_encode_vertex_normal = CodeChunk.from(
20
- //language=WGSL
21
- `
22
- fn encode_vertex_normal(n: vec3<f32>) -> u32 {
23
- let oct = uv_octahedral_unit_encode(n);
24
- let q = vec2<u32>(oct * 65535.0) & vec2<u32>(0xFFFFu, 0xFFFFu);
25
- return q.x | (q.y << 16u);
26
- }
27
- `, [
28
- chunk_uv_octahedral_unit_encode,
29
- ]
30
- );
1
+ import { CodeChunk } from "../../../compiler/CodeChunk.js";
2
+ import { chunk_uv_octahedral_unit_encode } from "../octahedron/chunk_uv_octahedral_unit_encode.js";
3
+
4
+ /**
5
+ * Inverse of `decode_vertex_normal` — packs a unit normal into a single
6
+ * `u32` via octahedral-unit encoding into two 16-bit u-norms (one per
7
+ * u32 half).
8
+ *
9
+ * Layout matches the decoder:
10
+ * - bits [0, 15]: oct.x (16-bit u-norm of `uv_octahedral_unit_encode(n).x`)
11
+ * - bits [16, 31]: oct.y
12
+ *
13
+ * Round-trips lossily — the 16-bit quantization gives ~1.5° worst-case
14
+ * angular error, which is what the format buys us in exchange for the
15
+ * 4-byte stride.
16
+ *
17
+ * @type {CodeChunk}
18
+ */
19
+ export const chunk_encode_vertex_normal = CodeChunk.from(
20
+ //language=WGSL
21
+ `
22
+ fn encode_vertex_normal(n: vec3<f32>) -> u32 {
23
+ return pack2x16unorm(uv_octahedral_unit_encode(n));
24
+ }
25
+ `, [
26
+ chunk_uv_octahedral_unit_encode,
27
+ ]
28
+ );