@woosh/meep-engine 3.60.2 → 3.60.4

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 (156) hide show
  1. package/editor/ecs/component/editors/ecs/Trail3DEditor.d.ts +3 -0
  2. package/editor/ecs/component/editors/ecs/Trail3DEditor.d.ts.map +1 -1
  3. package/editor/ecs/component/editors/ecs/Trail3DEditor.js +6 -0
  4. package/package.json +1 -1
  5. package/src/engine/ecs/ik/PLAN.md +1 -1
  6. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +1 -2
  7. package/src/engine/graphics/ecs/trail3d/TRAIL3D_FADE_LINEAR.d.ts +14 -0
  8. package/src/engine/graphics/ecs/trail3d/TRAIL3D_FADE_LINEAR.d.ts.map +1 -0
  9. package/src/engine/graphics/ecs/trail3d/TRAIL3D_FADE_LINEAR.js +22 -0
  10. package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts +19 -3
  11. package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts.map +1 -1
  12. package/src/engine/graphics/ecs/trail3d/Trail3D.js +31 -4
  13. package/src/engine/graphics/ecs/trail3d/advance_trail.js +1 -1
  14. package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.d.ts +5 -5
  15. package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.d.ts.map +1 -1
  16. package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.js +6 -6
  17. package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts +10 -0
  18. package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts.map +1 -1
  19. package/src/engine/graphics3/trail/trail_tube_write_geometry.js +13 -1
  20. package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts +2 -2
  21. package/src/engine/physics/cloth/ecs/cloth_geodesic.js +2 -2
  22. package/src/shade/playground/probe_clipmap/README.md +1 -0
  23. package/src/shade/playground/probe_clipmap/index.html +5 -0
  24. package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
  25. package/src/shade/playground/probe_clipmap/main.js +16 -2
  26. package/src/shade/playground/vgeo_scene/README.md +1 -1
  27. package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.d.ts +4 -6
  28. package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.d.ts.map +1 -1
  29. package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.js +34 -36
  30. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts +1 -1
  31. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts.map +1 -1
  32. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.js +162 -163
  33. package/src/shade/renderer/atmosphere/compute_mie_absorption.d.ts +1 -1
  34. package/src/shade/renderer/atmosphere/compute_mie_absorption.js +1 -1
  35. package/src/shade/renderer/atmosphere/hillaire/ATMOSPHERE_EARTH.js +1 -1
  36. package/src/shade/renderer/atmosphere/hillaire/ATMOSPHERE_PARAMETERS_STRUCT.js +1 -1
  37. package/src/shade/renderer/atmosphere/shader_multiscatter_lut.js +164 -164
  38. package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.js +1 -1
  39. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +2 -2
  40. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +2 -2
  41. package/src/shade/renderer/geometry/sdf/cards/mesh_cards_raster_pass_descriptor.js +2 -2
  42. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.d.ts +1 -1
  43. package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.js +1 -1
  44. package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.d.ts +4 -5
  45. package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.d.ts.map +1 -1
  46. package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.js +6 -7
  47. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +1 -1
  48. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +2 -4
  49. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +1 -1
  50. package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +3 -10
  51. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  52. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -0
  53. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +119 -38
  54. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +2 -2
  55. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +12 -0
  56. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -1
  57. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +22 -0
  58. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +4 -1
  59. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  60. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +50 -4
  61. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +6 -0
  62. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
  63. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +7 -0
  64. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_RESAMPLING.d.ts +13 -0
  65. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_RESAMPLING.d.ts.map +1 -0
  66. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_RESAMPLING.js +13 -0
  67. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +17 -0
  68. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
  69. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +20 -0
  70. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_resampled.d.ts +18 -0
  71. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_resampled.d.ts.map +1 -0
  72. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_resampled.js +42 -0
  73. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -1
  74. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +5 -4
  75. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +4 -0
  76. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts.map +1 -1
  77. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js +13 -2
  78. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_resample.d.ts +52 -0
  79. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_resample.d.ts.map +1 -0
  80. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_resample.js +250 -0
  81. package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +7 -7
  82. package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +2 -2
  83. package/src/shade/renderer/light/environment/environment_level_1_blur_plan.d.ts +39 -0
  84. package/src/shade/renderer/light/environment/environment_level_1_blur_plan.d.ts.map +1 -0
  85. package/src/shade/renderer/light/environment/environment_level_1_blur_plan.js +119 -0
  86. package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts +15 -7
  87. package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts.map +1 -1
  88. package/src/shade/renderer/light/environment/execute_filter_environment_map.js +66 -83
  89. package/src/shade/renderer/light/environment/graph_filter_environment_map.d.ts.map +1 -1
  90. package/src/shade/renderer/light/environment/graph_filter_environment_map.js +15 -6
  91. package/src/shade/renderer/light/environment/shader_blur_environment_map.d.ts +3 -0
  92. package/src/shade/renderer/light/environment/shader_blur_environment_map.d.ts.map +1 -0
  93. package/src/shade/renderer/light/environment/shader_blur_environment_map.js +111 -0
  94. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_blurred.d.ts +3 -0
  95. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_blurred.d.ts.map +1 -0
  96. package/src/shade/renderer/light/environment/{shader_convolve_reflection_map_from_averages.js → shader_convolve_reflection_map_from_blurred.js} +25 -66
  97. package/src/shade/renderer/light/environment/shader_downsample_environment_map.d.ts.map +1 -1
  98. package/src/shade/renderer/light/environment/shader_downsample_environment_map.js +0 -1
  99. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +1 -4
  100. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +2 -2
  101. package/src/shade/renderer/postprocess/nss/NOTES.md +14 -21
  102. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -3
  103. package/src/shade/renderer/postprocess/nss/NSS.d.ts.map +1 -1
  104. package/src/shade/renderer/postprocess/nss/NSS.js +1 -3
  105. package/src/shade/renderer/postprocess/nss/NSS_NETWORK_SCHEMA.d.ts +5 -6
  106. package/src/shade/renderer/postprocess/nss/NSS_NETWORK_SCHEMA.d.ts.map +1 -1
  107. package/src/shade/renderer/postprocess/nss/NSS_NETWORK_SCHEMA.js +9 -10
  108. package/src/shade/renderer/postprocess/nss/shader_nss_extract_feedback.d.ts.map +1 -1
  109. package/src/shade/renderer/postprocess/nss/shader_nss_extract_feedback.js +48 -49
  110. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
  111. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +12 -16
  112. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +246 -246
  113. package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.d.ts +1 -2
  114. package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.d.ts.map +1 -1
  115. package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.js +34 -35
  116. package/src/shade/renderer/shader/chunk/atmosphere/C_MIE_SCATTERING_DECLARATION.d.ts +2 -2
  117. package/src/shade/renderer/shader/chunk/atmosphere/C_MIE_SCATTERING_DECLARATION.js +2 -2
  118. package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +1 -1
  119. package/src/shade/renderer/shader/chunk/atmosphere/chunk_compute_extinction.js +1 -1
  120. package/src/shade/renderer/shader/chunk/atmosphere/hillaire/DENSITY_PROFILE_LAYER_STRUCT.d.ts +1 -1
  121. package/src/shade/renderer/shader/chunk/atmosphere/hillaire/DENSITY_PROFILE_LAYER_STRUCT.js +1 -1
  122. package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +4 -7
  123. package/src/shade/renderer/shader/chunk/brdf/fresnel/chunk_F_Schlick.d.ts +3 -3
  124. package/src/shade/renderer/shader/chunk/brdf/fresnel/chunk_F_Schlick.js +3 -3
  125. package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +12 -19
  126. package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.d.ts +9 -10
  127. package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.d.ts.map +1 -1
  128. package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.js +9 -10
  129. package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.d.ts +4 -4
  130. package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.js +5 -5
  131. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +1 -1
  132. package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.d.ts +1 -2
  133. package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.d.ts.map +1 -1
  134. package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.js +1 -2
  135. package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec2.d.ts +14 -1
  136. package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec2.d.ts.map +1 -1
  137. package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec2.js +19 -6
  138. package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec3.d.ts +10 -1
  139. package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec3.d.ts.map +1 -1
  140. package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec3.js +14 -6
  141. package/src/shade/renderer/shader/chunk/random/murmur/chunk_murmur3_vec3u.d.ts +1 -1
  142. package/src/shade/renderer/shader/chunk/random/murmur/chunk_murmur3_vec3u.js +1 -1
  143. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +9 -14
  144. package/src/shade/renderer/shadow/contact/FINDINGS.md +5 -5
  145. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_DYNAMIC_LOD_BIAS.d.ts +2 -3
  146. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_DYNAMIC_LOD_BIAS.d.ts.map +1 -1
  147. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_DYNAMIC_LOD_BIAS.js +7 -8
  148. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_LOAD_FACTOR.d.ts +1 -1
  149. package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_LOAD_FACTOR.js +12 -12
  150. package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts +2 -2
  151. package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts.map +1 -1
  152. package/src/shade/renderer/shadow/vsm/VSMPageManager.js +3 -4
  153. package/src/shade/renderer/texture/mipmaps/NOTES.md +1 -2
  154. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +1 -1
  155. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_averages.d.ts +0 -13
  156. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_averages.d.ts.map +0 -1
@@ -23,65 +23,42 @@ import { chunk_reflection_sample_weight } from "./chunk_reflection_sample_weight
23
23
  import { chunk_sphere_probe_lod_to_roughness } from "./chunk_sphere_probe_lod_to_roughness.js";
24
24
  import { BSDF_ROUGHNESS_MINIMUM } from "./DEFINES.js";
25
25
  import { ENVIRONMENT_MAP_SAMPLER_RESOURCE } from "./ENVIRONMENT_MAP_SAMPLER_RESOURCE.js";
26
+ import { LEVEL_1_SAMPLE_COUNT } from "./environment_level_1_blur_plan.js";
26
27
 
27
28
  const resources = new ShaderResourceSetDescriptor();
28
29
 
30
+ // the lobe's roughness once narrowed by the blur it reads through, see environment_level_1_blur_plan
31
+ resources.setImmediate("lobe_roughness", "f32");
32
+
29
33
  resources.createGroup()
30
- // the map's level 0, and its plain averages from level 1 down (see shader_downsample_environment_map)
31
- .addTexture("level_0", "float")
32
- .addTexture("averages", "float")
34
+ // level 0 blurred by a Gaussian, see shader_blur_environment_map
35
+ .addTexture("blurred", "float")
33
36
  .addStorageTexture("output", "rgba16float")
34
37
  .add(ENVIRONMENT_MAP_SAMPLER_RESOURCE)
35
38
  ;
36
39
 
37
40
  /**
38
- * Samples per texel. Each reads the average whose texel matches the solid angle it stands for, so
39
- * the count sets the noise of the lobe's shape, not whether a bright texel is counted. Measured on a
40
- * single bright texel of a 1024 map at 48 places, level 1 over level 0 in solid-angle energy:
41
- * 32 → 0.995 ± 0.014, 64 → 0.998 ± 0.008 (at most 1.005), 196 → 1.001 ± 0.019 — 196 asks for a
42
- * finer average than the 2x2 one, so it point-samples level 0 again. UE filters with 32 below
43
- * roughness 0.1 and 64 above.
44
- * @type {number}
45
- */
46
- export const CONVOLVE_FROM_AVERAGES_SAMPLE_COUNT = 64;
47
-
48
- /**
49
- * Level 1 of the prefilter, by filtered importance sampling: each sample reads the plain average of
50
- * level 0 whose texel is the solid angle the sample stands for, so a texel brighter than its
51
- * neighbours is averaged into the coarser texel the sample reads instead of being hit or missed by
52
- * the sample pattern. Point taps into level 0 — 196 of them over a cone of 639 level-0 texels — put
53
- * one bright texel's share of level 1 anywhere from 0.79 to 1.21 of its energy, and an HDR sun
54
- * came out 0.66% brighter than it went in.
41
+ * Level 1 of the prefilter, from a copy of level 0 blurred by a Gaussian.
42
+ *
43
+ * Point taps into level 0 — 196 of them over a cone of 639 level-0 texels on a 1024 map — put one
44
+ * bright texel's share of level 1 anywhere from 0.79 to 1.21 of its energy, and an HDR sun came out
45
+ * 0.66% brighter than it went in. Read from a copy blurred wider than the samples are apart, every
46
+ * texel lands in level 1 once, whatever the sample pattern. The blur and the lobe are both Gaussians,
47
+ * so the lobe narrows by the blur's variance and level 1 comes out the lobe it is asked for.
48
+ *
49
+ * Samples are uniform in the cone, so each stands for the same solid angle. UE importance-samples
50
+ * and reads a coarser average in the lobe's tail than in its core; here the sun came out in blocks.
55
51
  *
56
52
  * Level 1 only. The levels after it read the level above, already smooth at their sample spacing
57
- * (see shader_convolve_reflection_map). Read from level 0 instead, their samples land on averages
58
- * 8 to 16 texels a side, too coarse an octahedral grid to keep a bright texel's energy: ±11% at
59
- * level 4, and a sky 11% brighter.
53
+ * (see shader_convolve_reflection_map).
60
54
  *
61
55
  * @see https://developer.nvidia.com/gpugems/gpugems3/part-iii-rendering/chapter-20-gpu-based-importance-sampling
62
- * @see https://github.com/EpicGames/UnrealEngine/blob/5.4/Engine/Shaders/Private/ReflectionEnvironmentShaders.usf FilterPS
63
56
  * @see https://projects.blender.org/blender/blender/src/commit/866ef5b468589587395b1ee7480ea75b4c0fbc26/source/blender/draw/engines/eevee_next/shaders/eevee_lightprobe_sphere_convolve_comp.glsl for the lobe
64
57
  * @type {CodeChunk}
65
58
  */
66
59
  const body = CodeChunk.from(
67
60
  //language=WGSL
68
61
  `
69
- /// level 0 is the map's own, the levels below it are the averages
70
- fn sample_source_level(direction: vec3<f32>, level: u32) -> vec4<f32> {
71
- let uv = uv_octahedral_unit_encode(direction);
72
-
73
- if (level == 0u) {
74
- let size = f32(textureDimensions(level_0).x);
75
-
76
- return textureSampleLevel(level_0, sEnvironment, texture_octahedral_skirt_uv(uv, size), 0.0);
77
- }
78
-
79
- let average_level = level - 1u;
80
- let size = f32(textureDimensions(averages, average_level).x);
81
-
82
- return textureSampleLevel(averages, sEnvironment, texture_octahedral_skirt_uv(uv, size), f32(average_level));
83
- }
84
-
85
62
  @compute @workgroup_size(16,16,1)
86
63
  fn main(
87
64
  @builtin(global_invocation_id) global_invocation_id : vec3<u32>,
@@ -94,7 +71,7 @@ fn main(
94
71
  return;
95
72
  }
96
73
 
97
- /* From mip to linear roughness (same as UI). */
74
+ // the cone is the lobe's as asked for; only its weights narrow
98
75
  let roughness = max(sphere_probe_lod_to_roughness(1.0), ${BSDF_ROUGHNESS_MINIMUM});
99
76
  let cone_cos = cone_cosine_from_roughness(roughness);
100
77
 
@@ -107,37 +84,19 @@ fn main(
107
84
  var weight_accum = 0.0;
108
85
  var radiance_accum = vec4(0.0);
109
86
 
110
- const sample_count = ${CONVOLVE_FROM_AVERAGES_SAMPLE_COUNT};
87
+ const sample_count = ${LEVEL_1_SAMPLE_COUNT};
111
88
 
112
- // uniform in the cone, so every sample stands for the same solid angle
113
- let sample_solid_angle = 2.0 * PI * (1.0 - cone_cos) / f32(sample_count);
114
-
115
- // level 0's octahedral square, n texels a side, spans 2 in octahedron coordinates; a texel there
116
- // covers (2/n)^2 of it, and the octahedron's solid angle per unit area is |d|_1^3 along unit d
117
- let level_0_interior = f32(textureDimensions(level_0).x) - 2.0;
118
- let level_0_texel_area = 4.0 / (level_0_interior * level_0_interior);
119
-
120
- let last_level = f32(textureNumLevels(averages));
89
+ let blurred_size = f32(textureDimensions(blurred).x);
121
90
 
122
91
  for (var i = 0u; i < sample_count; i++) {
123
92
  let rand = hammersley_2d(i, sample_count);
124
93
 
125
94
  let in_direction = normalize(basis * uniform_sample_cone(rand, cone_cos));
126
95
 
127
- let l1 = dot(abs(in_direction), vec3(1.0));
128
- let texel_solid_angle = level_0_texel_area * l1 * l1 * l1;
129
-
130
- let lod = clamp(0.5 * log2(sample_solid_angle / texel_solid_angle), 0.0, last_level);
131
- let lod_floor = floor(lod);
132
- let level = u32(lod_floor);
133
-
134
- let radiance = mix(
135
- sample_source_level(in_direction, level),
136
- sample_source_level(in_direction, min(level + 1u, u32(last_level))),
137
- lod - lod_floor
138
- );
96
+ let in_uv = texture_octahedral_skirt_uv(uv_octahedral_unit_encode(in_direction), blurred_size);
97
+ let radiance = textureSampleLevel(blurred, sEnvironment, in_uv, 0.0);
139
98
 
140
- let weight = reflection_sample_weight(out_direction, in_direction, roughness);
99
+ let weight = reflection_sample_weight(out_direction, in_direction, lobe_roughness);
141
100
 
142
101
  radiance_accum += radiance * weight;
143
102
  weight_accum += weight;
@@ -162,8 +121,8 @@ fn main(
162
121
  ]
163
122
  );
164
123
 
165
- export const shader_convolve_reflection_map_from_averages = new ComputeShader(ShaderDescriptor.from({
166
- label: 'Convolve reflection map from averages',
124
+ export const shader_convolve_reflection_map_from_blurred = new ComputeShader(ShaderDescriptor.from({
125
+ label: 'Convolve reflection map from blurred',
167
126
  body,
168
127
  resources
169
128
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"shader_downsample_environment_map.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/light/environment/shader_downsample_environment_map.js"],"names":[],"mappings":"AAoGA,8DAII;8BAjG0B,+BAA+B"}
1
+ {"version":3,"file":"shader_downsample_environment_map.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/light/environment/shader_downsample_environment_map.js"],"names":[],"mappings":"AAmGA,8DAII;8BAhG0B,+BAA+B"}
@@ -29,7 +29,6 @@ resources.createGroup()
29
29
  * (chunk_octahedral_solid_angle): a texel the octahedral fold crosses is no pair of spherical
30
30
  * triangles, and a bright one came out 4.7% dim.
31
31
  *
32
- * @see https://github.com/EpicGames/UnrealEngine/blob/5.4/Engine/Shaders/Private/ReflectionEnvironmentShaders.usf DownsamplePS
33
32
  * @type {CodeChunk}
34
33
  */
35
34
  const body = CodeChunk.from(
@@ -274,10 +274,7 @@ machine. Every VM pass and the bind pass compile and build pipelines under Tint
274
274
 
275
275
  ## Sources
276
276
 
277
- - UE 5.4 source on disk: `Plugins/FX/Niagara/Source/Niagara/Public/NiagaraTypes.h`
278
- (`FNiagaraEmitterParameters` and `FNiagaraSystemParameters` are the engine's members of each scope,
279
- with User values beside them), `Classes/NiagaraGPUSystemTick.h`,
280
- `Classes/NiagaraParameterCollection.h` (globals bound by name).
277
+ - Niagara Emitter and System parameter namespaces (with User values beside them) and Parameter Collections (globals bound by name).
281
278
  - [Niagara key concepts (namespace read/write table)](https://dev.epicgames.com/documentation/unreal-engine/key-concepts-in-niagara-effects-for-unreal-engine)
282
279
  - [VFX Graph instancing](https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@17.2/manual/Instancing.html)
283
280
  — instances share code and load their properties per instance.
@@ -359,8 +359,8 @@ Register peaks are pinned in `particle_group_library.spec.js`, all far under 48.
359
359
  - **An emitter-local frame** (Shuriken "Local"). It needs the scene database in the draw.
360
360
  `emitterRotation` does the same in INIT.
361
361
 
362
- Precedent, read from source: Niagara meshes, Niagara sprites, Unity VFX Graph and PopcornFX all
363
- compose the particle's rotation inside the facing frame. The mesh paths (Niagara `MeshOrientation`,
362
+ Precedent: Niagara meshes, Niagara sprites, Unity VFX Graph and PopcornFX all
363
+ compose the particle's rotation inside the facing frame. The mesh paths (Niagara mesh orientation,
364
364
  PopcornFX `Orientation`, Houdini `orient`) store a quaternion.
365
365
 
366
366
  ## Touch list
@@ -1,6 +1,6 @@
1
1
  # Neural Super Sampling (NSS)
2
2
 
3
- Port of [ARM's Neural Super Sampling](https://github.com/arm/neural-graphics-for-unreal/tree/main)
3
+ Port of ARM's Neural Super Sampling
4
4
  reference design onto the engine's FrameGraph. Same role as TAA — temporal
5
5
  anti-aliasing + upscale — but the spatial reconstruction kernel is predicted
6
6
  per-pixel by a small CNN (Kernel-Prediction Network) instead of a fixed
@@ -116,8 +116,7 @@ automatically; the renderer only needs to flip
116
116
 
117
117
  ### Source
118
118
 
119
- Extracted from `nss_v0_1_1_int8.vgf` in the ARM Neural Graphics for
120
- Unreal SDK in two passes:
119
+ Extracted from `nss_v0_1_1_int8.vgf` in the ARM Neural Graphics SDK in two passes:
121
120
 
122
121
  1. **VGF constants table** via ARM's own `Model_Parser.exe` — gives
123
122
  us the conv weights for every layer and biases for the 7 encoder
@@ -217,18 +216,14 @@ fp32 throughout our pipeline so the offset is implicit.
217
216
  #### Head ordering — ARM's quantized model
218
217
 
219
218
  The 6 heads come out of the SPIR-V in CONCAT order, which is NOT
220
- KPN col 0..3 + ThetaAlpha + FB. ARM's UE5.5 plugin
221
- (`UE5.5/Source/NSS/Private/NSS.cpp:241-246`) hard-codes the
222
- quantized-model `OutputIndices`:
223
-
224
- ```cpp
225
- Result->OutputIndices.Feedback = 0;
226
- Result->OutputIndices.ThetaAlpha = 1;
227
- Result->OutputIndices.KPNFilterCol3 = 2;
228
- Result->OutputIndices.KPNFilterCol2 = 3;
229
- Result->OutputIndices.KPNFilterCol1 = 4;
230
- Result->OutputIndices.KPNFilterCol0 = 5;
231
- ```
219
+ KPN col 0..3 + ThetaAlpha + FB. ARM's quantized model assigns the output head slots as:
220
+
221
+ - Slot 0: Feedback
222
+ - Slot 1: ThetaAlpha
223
+ - Slot 2: KPN column 3
224
+ - Slot 3: KPN column 2
225
+ - Slot 4: KPN column 1
226
+ - Slot 5: KPN column 0
232
227
 
233
228
  Our postprocess shader reads the columns from `[5, 4, 3, 2]` in
234
229
  that order to recover (col 0, col 1, col 2, col 3), and reads
@@ -236,7 +231,7 @@ ThetaAlpha from slot 1.
236
231
 
237
232
  #### Postprocess two-stage blend
238
233
 
239
- Mirrors ARM's `NSSPostprocess.usf` (UE5.5):
234
+ Mirrors ARM's reference postprocess:
240
235
  1. Apply the 4×4 KPN to the jittered colour, normalising by
241
236
  the (positive) weight sum. The centre tap (col=1, row=1) is also
242
237
  captured separately.
@@ -275,8 +270,7 @@ Audited against `ffx_nss_callbacks_glsl.h`, `ffx_nss_preprocess.h`,
275
270
  zeros tiny motion (`MotionWarpThresh=0.01`) and scales
276
271
  disocclusion by `~0.725` on near-static frames
277
272
  (`MotionDisThresh=0.25`). We do neither.
278
- - **History warp filter:** ARM uses Catmull-Rom with deringing
279
- (`CatmullRomWithDering`, NSSPostprocess.usf:55). We use plain
273
+ - **History warp filter:** ARM uses Catmull-Rom with deringing. We use plain
280
274
  bilinear via `SAMPLER_LINEAR_UPSCALE`. Slight softness on
281
275
  high-frequency history detail.
282
276
  - **Per-tensor input scales (forward pass):** ARM's INT8
@@ -292,7 +286,7 @@ Audited against `ffx_nss_callbacks_glsl.h`, `ffx_nss_preprocess.h`,
292
286
  - **Exposure factor:** ARM multiplies network colour reads by
293
287
  `Exposure()` and the final write by `1/Exposure()`
294
288
  (`ffx_nss_postprocess.h:48`). We hard-code `EXPOSURE = e^2` to
295
- match ARM's `NSSCommon.ush` constant — adequate for SDR output,
289
+ match ARM's reference constant — adequate for SDR output,
296
290
  but doesn't track engine exposure changes.
297
291
  - **2x preset KPN footprint:** ARM's 2x path uses a precomputed
298
292
  `kernelLUT` indexed by `(out_pixel + jitter_tile_offset) % 2`,
@@ -326,12 +320,11 @@ via `NSS.recommended_jitter_sequence_size(upscale_ratio)`), forwards
326
320
  | INT8 quantization with TOSA RESCALE + TABLE | Per-channel `127 * mult / 2^shift` rescale + per-head `output_zp` shift before LUT lookup; LUT dequant matches ARM's `(int8 + 127) / 255` |
327
321
  | 2× preset uses a 4-tap LUT pattern | Generic 4×4 KPN footprint for any upscale ratio |
328
322
  | Mirror-pad to round to 8 | Compute shader early-outs out-of-range threads; same effect, no extra pass |
329
- | UE's sparse motion vectors | Engine velocity is already dense and pixel-space; no convert pass |
323
+ | Sparse motion vectors | Engine velocity is already dense and pixel-space; no convert pass |
330
324
  | Feedback aliased as R8G8B8A8_SNORM image | Plain rgba16f texture |
331
325
 
332
326
  ## References
333
327
 
334
- - ARM / Unreal plugin: <https://github.com/arm/neural-graphics-for-unreal/tree/main>
335
328
  - ARM SDK (kernel sources): `Source/NG-SDK/sdk/include/FidelityFX/gpu/nss/`
336
329
  - ARM SDK Model Parser: `Source/NG-SDK/sdk/tools/binary_store/Model_Parser.exe`
337
330
  - FSR2 depth-clip (used unchanged for the disocclusion mask):
@@ -3,9 +3,7 @@
3
3
  * @typedef {import("../../GraphicsContext.js").GraphicsContext} GraphicsContext
4
4
  */
5
5
  /**
6
- * Neural Super Sampling — port of ARM's NSS reference design
7
- * (`https://github.com/arm/neural-graphics-for-unreal`) onto the
8
- * engine's FrameGraph.
6
+ * Neural Super Sampling — port of ARM's NSS reference design onto the engine's FrameGraph.
9
7
  *
10
8
  * Pipeline (per frame):
11
9
  * 1. Preprocess — assemble a 12-channel tensor from
@@ -1 +1 @@
1
- {"version":3,"file":"NSS.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/postprocess/nss/NSS.js"],"names":[],"mappings":"AAgCA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH;IAsaI;;;;;;OAMG;IACH,uDAHW,MAAM,GACJ,MAAM,CAKlB;IAsCD,uGAQC;IAxRD;;OAEG;IACH,sBAFW,eAAe,EAwCzB;IAhOD;;;OAGG;IACH,uBAEC;IAED;;;OAGG;IACH,4BAEC;IAED;;;;;OAKG;IACH,eAFU,OAAO,CAEI;IAErB;;;;;;;;OAQG;IACH,mBAFU,MAAM,CAEQ;IAExB;;;;;;;OAOG;IACH,gBAFU,MAAM,CAEM;IAEtB;;;;;OAKG;IACH,YAFU,MAAM,CAED;IAEf;;;;;;;;;;;OAWG;IACH,mBAFU,MAAM,CAEQ;IAExB;;;;;;OAMG;IACH,gBAFU,MAAM,CAEK;IAErB;;;;;;OAMG;IACH,iBAFU,MAAM,CAEM;IAEtB;;;;;;;;;OASG;IACH,eAFU,MAAM,CAEI;IACpB,wCAAwC;IACxC,eAD8B,MAAM,CAChB;IAkKpB;;;;;OAKG;IACH,+BAyHC;IAED,wCAAwC;IACxC,0BAEC;IArKD;;OAEG;IACH,gBA4BC;IAwID;;OAEG;IACH,uCAEC;IAED;;OAEG;IACH,mCAEC;IAcD;;OAEG;IACH,2BAEC;IA2CD,2BAAkF;IAClF,0BAA+C;IAE/C;;;;;;;;;;;;;;;;;;OAkBG;IACH;QAf4B,KAAK,EAAtB,UAAU;QACG,qBAAqB,EAAlC,MAAM;QACO,qBAAqB,EAAlC,MAAM;QACO,gBAAgB,EAA7B,MAAM;QACO,+BAA+B,EAA5C,MAAM;QAKO,qBAAqB,EAAlC,MAAM;QACO,cAAc,EAA3B,MAAM;QACS,iBAAiB,EAAhC,MAAM,EAAE;QACO,iBAAiB,EAAhC,MAAM,EAAE;QACN,MAAM,CA4NlB;;CACJ;yBAjwBY,OAAO,8DAA8D,EAAE,UAAU;8BACjF,OAAO,0BAA0B,EAAE,eAAe;2BATpC,iBAAiB;0CAvBF,oDAAoD"}
1
+ {"version":3,"file":"NSS.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/postprocess/nss/NSS.js"],"names":[],"mappings":"AAgCA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH;IAsaI;;;;;;OAMG;IACH,uDAHW,MAAM,GACJ,MAAM,CAKlB;IAsCD,uGAQC;IAxRD;;OAEG;IACH,sBAFW,eAAe,EAwCzB;IAhOD;;;OAGG;IACH,uBAEC;IAED;;;OAGG;IACH,4BAEC;IAED;;;;;OAKG;IACH,eAFU,OAAO,CAEI;IAErB;;;;;;;;OAQG;IACH,mBAFU,MAAM,CAEQ;IAExB;;;;;;;OAOG;IACH,gBAFU,MAAM,CAEM;IAEtB;;;;;OAKG;IACH,YAFU,MAAM,CAED;IAEf;;;;;;;;;;;OAWG;IACH,mBAFU,MAAM,CAEQ;IAExB;;;;;;OAMG;IACH,gBAFU,MAAM,CAEK;IAErB;;;;;;OAMG;IACH,iBAFU,MAAM,CAEM;IAEtB;;;;;;;;;OASG;IACH,eAFU,MAAM,CAEI;IACpB,wCAAwC;IACxC,eAD8B,MAAM,CAChB;IAkKpB;;;;;OAKG;IACH,+BAyHC;IAED,wCAAwC;IACxC,0BAEC;IArKD;;OAEG;IACH,gBA4BC;IAwID;;OAEG;IACH,uCAEC;IAED;;OAEG;IACH,mCAEC;IAcD;;OAEG;IACH,2BAEC;IA2CD,2BAAkF;IAClF,0BAA+C;IAE/C;;;;;;;;;;;;;;;;;;OAkBG;IACH;QAf4B,KAAK,EAAtB,UAAU;QACG,qBAAqB,EAAlC,MAAM;QACO,qBAAqB,EAAlC,MAAM;QACO,gBAAgB,EAA7B,MAAM;QACO,+BAA+B,EAA5C,MAAM;QAKO,qBAAqB,EAAlC,MAAM;QACO,cAAc,EAA3B,MAAM;QACS,iBAAiB,EAAhC,MAAM,EAAE;QACO,iBAAiB,EAAhC,MAAM,EAAE;QACN,MAAM,CA4NlB;;CACJ;yBA/vBY,OAAO,8DAA8D,EAAE,UAAU;8BACjF,OAAO,0BAA0B,EAAE,eAAe;2BATpC,iBAAiB;0CAvBF,oDAAoD"}
@@ -36,9 +36,7 @@ import { shader_nss_preprocess } from "./shader_nss_preprocess.js";
36
36
  */
37
37
 
38
38
  /**
39
- * Neural Super Sampling — port of ARM's NSS reference design
40
- * (`https://github.com/arm/neural-graphics-for-unreal`) onto the
41
- * engine's FrameGraph.
39
+ * Neural Super Sampling — port of ARM's NSS reference design onto the engine's FrameGraph.
42
40
  *
43
41
  * Pipeline (per frame):
44
42
  * 1. Preprocess — assemble a 12-channel tensor from
@@ -9,14 +9,13 @@
9
9
  * ReLU; decoder is conv8..conv12 without bias; 6 parallel output
10
10
  * heads each carry their own RESCALE + TABLE LUT.
11
11
  *
12
- * Head ordering matches ARM's `OutputIndices` mapping for the
13
- * QUANTIZED model (NSS.cpp:241-246):
12
+ * Head ordering for the quantized model:
14
13
  * slot 0 = Feedback (FB) — passed back to next frame's preprocess
15
14
  * slot 1 = ThetaAlpha — sigmoid temporal-blend params
16
- * slot 2 = KPNFilterCol3 — kernel column 3 (rightmost)
17
- * slot 3 = KPNFilterCol2
18
- * slot 4 = KPNFilterCol1
19
- * slot 5 = KPNFilterCol0 — kernel column 0 (leftmost)
15
+ * slot 2 = KPN column 3 — kernel column 3 (rightmost)
16
+ * slot 3 = KPN column 2
17
+ * slot 4 = KPN column 1
18
+ * slot 5 = KPN column 0 — kernel column 0 (leftmost)
20
19
  *
21
20
  * The KPN slot order is reversed because ARM packs the network outputs
22
21
  * in CONCAT order while our postprocess reads them as columns 0..3.
@@ -1 +1 @@
1
- {"version":3,"file":"NSS_NETWORK_SCHEMA.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/postprocess/nss/NSS_NETWORK_SCHEMA.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,oEAAoE;AACpE,6CACqE;AAErE;;;;GAIG;AACH,yCAA0C;AAE1C,kEAAkE;AAClE,mCAAoC;AAEpC,6DAA6D;AAC7D,qCAAsC;AAEtC,yCAAyC;AACzC,yCAA0C"}
1
+ {"version":3,"file":"NSS_NETWORK_SCHEMA.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/postprocess/nss/NSS_NETWORK_SCHEMA.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,oEAAoE;AACpE,6CACqE;AAErE;;;;GAIG;AACH,yCAA0C;AAE1C,kEAAkE;AAClE,mCAAoC;AAEpC,6DAA6D;AAC7D,qCAAsC;AAEtC,yCAAyC;AACzC,yCAA0C"}
@@ -9,14 +9,13 @@
9
9
  * ReLU; decoder is conv8..conv12 without bias; 6 parallel output
10
10
  * heads each carry their own RESCALE + TABLE LUT.
11
11
  *
12
- * Head ordering matches ARM's `OutputIndices` mapping for the
13
- * QUANTIZED model (NSS.cpp:241-246):
12
+ * Head ordering for the quantized model:
14
13
  * slot 0 = Feedback (FB) — passed back to next frame's preprocess
15
14
  * slot 1 = ThetaAlpha — sigmoid temporal-blend params
16
- * slot 2 = KPNFilterCol3 — kernel column 3 (rightmost)
17
- * slot 3 = KPNFilterCol2
18
- * slot 4 = KPNFilterCol1
19
- * slot 5 = KPNFilterCol0 — kernel column 0 (leftmost)
15
+ * slot 2 = KPN column 3 — kernel column 3 (rightmost)
16
+ * slot 3 = KPN column 2
17
+ * slot 4 = KPN column 1
18
+ * slot 5 = KPN column 0 — kernel column 0 (leftmost)
20
19
  *
21
20
  * The KPN slot order is reversed because ARM packs the network outputs
22
21
  * in CONCAT order while our postprocess reads them as columns 0..3.
@@ -52,10 +51,10 @@ export const NSS_NETWORK_SCHEMA = Object.freeze({
52
51
  // the slot index is what the postprocess reads back.
53
52
  { in: 16, out: 4, output_layer_offset: 0, kind: 'feedback' }, // 12 FB
54
53
  { in: 16, out: 4, output_layer_offset: 1, kind: 'theta_alpha' }, // 13 ThetaAlpha (sigmoid)
55
- { in: 16, out: 4, output_layer_offset: 2, kind: 'kpn_col_3' }, // 14 KPNFilterCol3
56
- { in: 16, out: 4, output_layer_offset: 3, kind: 'kpn_col_2' }, // 15 KPNFilterCol2
57
- { in: 16, out: 4, output_layer_offset: 4, kind: 'kpn_col_1' }, // 16 KPNFilterCol1
58
- { in: 16, out: 4, output_layer_offset: 5, kind: 'kpn_col_0' }, // 17 KPNFilterCol0
54
+ { in: 16, out: 4, output_layer_offset: 2, kind: 'kpn_col_3' }, // 14 KPN column 3
55
+ { in: 16, out: 4, output_layer_offset: 3, kind: 'kpn_col_2' }, // 15 KPN column 2
56
+ { in: 16, out: 4, output_layer_offset: 4, kind: 'kpn_col_1' }, // 16 KPN column 1
57
+ { in: 16, out: 4, output_layer_offset: 5, kind: 'kpn_col_0' }, // 17 KPN column 0
59
58
  ],
60
59
  });
61
60
 
@@ -1 +1 @@
1
- {"version":3,"file":"shader_nss_extract_feedback.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/postprocess/nss/shader_nss_extract_feedback.js"],"names":[],"mappings":"AA4CA,wDAIG;8BA/C2B,+BAA+B"}
1
+ {"version":3,"file":"shader_nss_extract_feedback.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/postprocess/nss/shader_nss_extract_feedback.js"],"names":[],"mappings":"AA2CA,wDAIG;8BA9C2B,+BAA+B"}
@@ -1,49 +1,48 @@
1
- import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
- import { ComputeShader } from "../../shader/ComputeShader.js";
3
- import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
4
- import { NSS_WORKGROUP_SIZE } from "./NSS_CONSTANTS.js";
5
-
6
- /**
7
- * Copies the feedback channel-group (z = 0 — head slot 0 in ARM's
8
- * quantized model output ordering, see NSS_NETWORK_SCHEMA) of the
9
- * network's 3D output tensor into a standalone 2D rgba16f texture, so
10
- * the next frame's preprocess pass can sample it as a regular 2D
11
- * texture (with bilinear filtering for the warp).
12
- *
13
- * Trivial pass — included as a separate shader rather than folded into
14
- * postprocess because postprocess runs at output-res while feedback is
15
- * needed at render-res.
16
- */
17
- const resources = new ShaderResourceSetDescriptor();
18
- resources.createGroup()
19
- .addTexture("tNetworkOut", "float", "3d")
20
- .addStorageTexture("tFeedback", "rgba16float", "2d", "write-only")
21
- ;
22
-
23
- const body = CodeChunk.from(
24
- //language=WGSL
25
- `
26
- @compute @workgroup_size(${NSS_WORKGROUP_SIZE}, ${NSS_WORKGROUP_SIZE}, 1)
27
- fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
28
- let dim = textureDimensions(tFeedback);
29
-
30
- if (any(gid.xy >= dim)) {
31
- return;
32
- }
33
-
34
- let st = vec2<i32>(gid.xy);
35
-
36
- // Slot 0 of the network output is the feedback tensor (ARM's
37
- // quantized-model OutputIndices.Feedback = 0).
38
- let fb = textureLoad(tNetworkOut, vec3<i32>(st, 0), 0);
39
-
40
- textureStore(tFeedback, st, fb);
41
- }
42
- `
43
- );
44
-
45
- export const shader_nss_extract_feedback = ComputeShader.from({
46
- label: "NSS / extract feedback",
47
- body,
48
- resources,
49
- });
1
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
+ import { ComputeShader } from "../../shader/ComputeShader.js";
3
+ import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
4
+ import { NSS_WORKGROUP_SIZE } from "./NSS_CONSTANTS.js";
5
+
6
+ /**
7
+ * Copies the feedback channel-group (z = 0 — head slot 0 in ARM's
8
+ * quantized model output ordering, see NSS_NETWORK_SCHEMA) of the
9
+ * network's 3D output tensor into a standalone 2D rgba16f texture, so
10
+ * the next frame's preprocess pass can sample it as a regular 2D
11
+ * texture (with bilinear filtering for the warp).
12
+ *
13
+ * Trivial pass — included as a separate shader rather than folded into
14
+ * postprocess because postprocess runs at output-res while feedback is
15
+ * needed at render-res.
16
+ */
17
+ const resources = new ShaderResourceSetDescriptor();
18
+ resources.createGroup()
19
+ .addTexture("tNetworkOut", "float", "3d")
20
+ .addStorageTexture("tFeedback", "rgba16float", "2d", "write-only")
21
+ ;
22
+
23
+ const body = CodeChunk.from(
24
+ //language=WGSL
25
+ `
26
+ @compute @workgroup_size(${NSS_WORKGROUP_SIZE}, ${NSS_WORKGROUP_SIZE}, 1)
27
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
28
+ let dim = textureDimensions(tFeedback);
29
+
30
+ if (any(gid.xy >= dim)) {
31
+ return;
32
+ }
33
+
34
+ let st = vec2<i32>(gid.xy);
35
+
36
+ // Slot 0 of the network output is the feedback tensor.
37
+ let fb = textureLoad(tNetworkOut, vec3<i32>(st, 0), 0);
38
+
39
+ textureStore(tFeedback, st, fb);
40
+ }
41
+ `
42
+ );
43
+
44
+ export const shader_nss_extract_feedback = ComputeShader.from({
45
+ label: "NSS / extract feedback",
46
+ body,
47
+ resources,
48
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"shader_nss_postprocess.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/postprocess/nss/shader_nss_postprocess.js"],"names":[],"mappings":"AAqSA,mDAIG;8BAvS2B,+BAA+B"}
1
+ {"version":3,"file":"shader_nss_postprocess.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/postprocess/nss/shader_nss_postprocess.js"],"names":[],"mappings":"AAiSA,mDAIG;8BAnS2B,+BAA+B"}
@@ -1,4 +1,4 @@
1
- import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
1
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
2
  import { F16_MAX_DEFINITION } from "../../shader/chunk/math/F16_MAX_DEFINITION.js";
3
3
  import { ComputeShader } from "../../shader/ComputeShader.js";
4
4
  import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
@@ -19,7 +19,7 @@ import { NSS_SETTINGS_STRUCT } from "./NSS_SETTINGS_STRUCT.js";
19
19
  * - the warped history at output-res
20
20
  * - the nearest-depth offset from preprocess (used to dilate velocity)
21
21
  *
22
- * Per-output-pixel logic mirrors ARM's reference (UE5.5 NSSPostprocess.usf):
22
+ * Per-output-pixel logic mirrors ARM's reference:
23
23
  * 1. Solve which render-res pixel feeds each of the 4x4 KPN taps.
24
24
  * 2. Apply the KPN to those taps, normalising by the weight sum.
25
25
  * 3. Warp the history (bilinear) using velocity dilated by the nearest
@@ -27,9 +27,6 @@ import { NSS_SETTINGS_STRUCT } from "./NSS_SETTINGS_STRUCT.js";
27
27
  * 4. Blend the KPN colour with warped history using theta.
28
28
  * 5. In tonemapped (Karis) space, accumulate the center tap with alpha.
29
29
  * 6. Inverse tonemap, divide by EXPOSURE, write.
30
- *
31
- * @see ARM reference: UE5.5/Shaders/Private/NSSPostprocess.usf and
32
- * NSSCommon.ush in github.com/arm/neural-graphics-for-unreal
33
30
  */
34
31
 
35
32
  const resources = new ShaderResourceSetDescriptor();
@@ -53,9 +50,9 @@ resources.createGroup()
53
50
  const body = CodeChunk.from(
54
51
  //language=WGSL
55
52
  `
56
- const NSS_EXPOSURE: f32 = 7.38905609893; // e^2, matches ARM's NSSCommon.ush
53
+ const NSS_EXPOSURE: f32 = 7.38905609893; // e^2
57
54
 
58
- // Karis tonemap (max-of-channels) — matches ARM's NSSCommon.ush.
55
+ // Karis tonemap (max-of-channels).
59
56
  // The guard is a FINITE clamp, not just a non-negative one: this target is rgba16float, so shading
60
57
  // above its range stores as +Inf and rgb / (1.0 + m) is Inf/Inf = NaN, which goes straight into the
61
58
  // next frame's history and stays there. NaN fails every comparison including with itself, which is
@@ -106,7 +103,7 @@ fn nss_sample_layer_bilinear(render_pos: vec2<f32>, render_res_max: vec2<i32>, l
106
103
 
107
104
  // SolveInputLocation: figure out which render-res pixel maps to a given
108
105
  // output-res pixel position, given upscale ratio and jitter. Direct port
109
- // of ARM's helper (NSSPostprocess.usf:80). Returns -1 when no render-res
106
+ // of ARM's reference helper. Returns -1 when no render-res
110
107
  // sample lands at this output position.
111
108
  fn nss_solve_input_location(out_idx: i32, upscale: f32, jitter: f32) -> i32 {
112
109
  let lower = f32(out_idx) / upscale - (-jitter + 0.5);
@@ -144,8 +141,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
144
141
  let coef_st_clamped = clamp(coef_st, vec2<i32>(0, 0), render_res_max);
145
142
 
146
143
  // ── KPN columns ──
147
- // ARM's quantized model maps OutputIndices.KPNFilterCol0 = 5,
148
- // KPNFilterCol1 = 4, KPNFilterCol2 = 3, KPNFilterCol3 = 2 (NSS.cpp:243).
144
+ // ARM's quantized model maps KPN columns 0..3 to head slots 5, 4, 3, 2.
149
145
  // Each column has 4 channels = the 4 row weights for that column.
150
146
  // Bilinear at render_centre (matches ARM's ManualBilinear4) — without
151
147
  // this, every 2x2 output block in 2x mode shares one set of weights and
@@ -155,7 +151,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
155
151
  let col2 = nss_sample_layer_bilinear(render_centre, render_res_max, 3);
156
152
  let col3 = nss_sample_layer_bilinear(render_centre, render_res_max, 2);
157
153
  // Force tiny positive — ARM does this to dodge 0/0 in the
158
- // weight-normalisation divide (NSSPostprocess.usf:118).
154
+ // weight-normalisation divide.
159
155
  let kpn_cols = array<vec4<f32>, 4>(
160
156
  max(col0, vec4<f32>(1e-7)),
161
157
  max(col1, vec4<f32>(1e-7)),
@@ -208,7 +204,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
208
204
  let nearest_offset = vec2<i32>(round(nearest_packed * 2.0 - 1.0));
209
205
 
210
206
  var velocity = textureLoad(tVelocity, coef_st_clamped + nearest_offset, 0).rg;
211
- // Motion zero-clamp (ARM NSSPostprocess.usf:215). Sub-pixel velocity on
207
+ // Motion zero-clamp. Sub-pixel velocity on
212
208
  // near-static frames drifts prev_uv by fractions of a pixel each frame
213
209
  // and bilinear-resamples the history at slightly different sub-pixel
214
210
  // positions — visible as flicker even when nothing in the scene is
@@ -225,10 +221,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
225
221
  let on_screen_f = select(0.0, 1.0, all(prev_uv >= vec2<f32>(0.0)) && all(prev_uv <= vec2<f32>(1.0)));
226
222
 
227
223
  // ── ThetaAlpha (head slot 1) ──
228
- // ARM's quantized model maps OutputIndices.ThetaAlpha = 1
229
- // (NSS.cpp:242). Channel x = theta (history blend weight, [0, 1] from
224
+ // ARM's quantized model maps ThetaAlpha to head slot 1.
225
+ // Channel x = theta (history blend weight, [0, 1] from
230
226
  // sigmoid LUT), channel y = alpha (raw [0, 1], remapped to
231
- // [0.05, 0.4] per NSSPostprocess.usf:248).
227
+ // [0.05, 0.4]).
232
228
  // Bilinear at render_centre — same reasoning as the KPN cols above.
233
229
  let ta = nss_sample_layer_bilinear(render_centre, render_res_max, 1);
234
230
  let theta_network = saturate(ta.x);
@@ -286,7 +282,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
286
282
  textureStore(tOutput, out_st, vec4<f32>(final_rgb, theta));
287
283
  }
288
284
  `, [
289
- F16_MAX_DEFINITION,
285
+ F16_MAX_DEFINITION,
290
286
  NSS_SETTINGS_STRUCT.declaration_chunk,
291
287
  ]
292
288
  );