@woosh/meep-engine 3.60.3 → 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 (163) 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_blurred.js +128 -0
  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/view/elements/progress/segmented/SegmentedResourceBarView.d.ts +0 -19
  156. package/src/view/elements/progress/segmented/SegmentedResourceBarView.d.ts.map +1 -1
  157. package/src/view/elements/progress/segmented/SegmentedResourceBarView.js +2 -52
  158. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_averages.d.ts +0 -13
  159. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_averages.d.ts.map +0 -1
  160. package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_averages.js +0 -198
  161. package/src/view/elements/progress/segmented/segment_frame_transform.d.ts +0 -15
  162. package/src/view/elements/progress/segmented/segment_frame_transform.d.ts.map +0 -1
  163. package/src/view/elements/progress/segmented/segment_frame_transform.js +0 -69
@@ -1,246 +1,246 @@
1
- import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
- import { F16_MAX_DEFINITION } from "../../shader/chunk/math/F16_MAX_DEFINITION.js";
3
- import { ComputeShader } from "../../shader/ComputeShader.js";
4
- import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
5
- import { SAMPLER_LINEAR_UPSCALE } from "../../texture/SAMPLER_LINEAR_UPSCALE.js";
6
- import { chunk_nss_find_nearest_depth } from "./chunk_nss_find_nearest_depth.js";
7
- import { chunk_nss_luma_derivative } from "./chunk_nss_luma_derivative.js";
8
- import { NSS_WORKGROUP_SIZE } from "./NSS_CONSTANTS.js";
9
- import { NSS_SETTINGS_STRUCT } from "./NSS_SETTINGS_STRUCT.js";
10
-
11
- /**
12
- * NSS preprocess pass. Runs at render-resolution (one thread per render-res
13
- * pixel) and produces:
14
- * 1. The 12-channel network input tensor, packed into a single rgba16f
15
- * 3D storage texture with depth=3 (channels 0..3, 4..7, 8..11).
16
- * 2. The encoded "nearest depth offset" used by postprocess to dilate
17
- * velocity at output-res (`tNearestOffset` — components in [0, 1]
18
- * decode to {-1, 0, 1}² via `(x*2 - 1)`).
19
- *
20
- * Per-pixel logic (matches the algorithm in ARM's `Preprocess()`):
21
- * 1. Dilate depth over a 3×3 neighbourhood, remember the offset of the
22
- * nearest sample.
23
- * 2. Sample velocity at the dilated coord.
24
- * 3. Project to the previous frame, sample warped history (bilinear).
25
- * 4. Read the FSR2 depth-clip confidence from the upstream pass and
26
- * invert it into the network's "high = disocclusion" convention.
27
- * 5. Sample the warped feedback tensor (bilinear).
28
- * 6. Compute the luma derivative between current and warped history.
29
- * 7. Pack everything into the output tensor — colours
30
- * tonemapped via `Tonemap(EXPOSURE * raw)` to match ARM's training
31
- * distribution.
32
- *
33
- * @see ARM NSS reference: `Preprocess` in
34
- * `Source/NG-SDK/sdk/include/FidelityFX/gpu/nss/ffx_nss_preprocess.h`
35
- */
36
- const resources = new ShaderResourceSetDescriptor();
37
- resources.createGroup()
38
- .addSampler("sLinear", "filtering", SAMPLER_LINEAR_UPSCALE)
39
- // ── inputs at render-res ──
40
- .addTexture("tColour", "float") // jittered scene colour, render-res
41
- // depth32float can't be bound as 'float' (filterable) — WebGPU only
42
- // accepts depth textures via 'unfilterable-float' in this context.
43
- // We only ever read this via textureLoad inside the depth dilation.
44
- .addTexture("tDepthCurrent", "unfilterable-float")
45
- .addTexture("tVelocity", "float") // pixel-space motion vectors, render-res
46
- // FSR2 depth-clip confidence (1 = trust history, 0 = disocclusion)
47
- // produced by the engine's shared shader_depth_occlusion_clip pass.
48
- // We invert it into ARM's "high = disocclusion" network input.
49
- .addTexture("tDisocclusionConfidence", "float")
50
- // ── inputs at output-res / feedback at render-res ──
51
- .addTexture("tHistory", "float") // previous frame upscaled colour, output-res
52
- .addTexture("tFeedbackIn", "float") // 4-ch feedback tensor from previous frame, render-res
53
- // ── settings ──
54
- .addUniform("settings", NSS_SETTINGS_STRUCT)
55
- // ── outputs ──
56
- // Single rgba16f 3D storage texture holds the 12-channel input tensor
57
- // packed across depth=3 layers (4 channels each). rgba16f gives the
58
- // network ~10 bits of mantissa per channel, which is plenty for
59
- // normalized [0, 1] inputs after the network's first BN/scale.
60
- .addStorageTexture("tTensor", "rgba16float", "3d", "write-only")
61
- // Nearest-depth offset packed as (dx+1, dy+1) / 2 -> [0, 1]. Postprocess
62
- // uses this to fetch the velocity at the dilated coordinate when warping
63
- // the history at output-resolution.
64
- .addStorageTexture("tNearestOffset", "rg8unorm", "2d", "write-only")
65
- ;
66
-
67
-
68
- const body = CodeChunk.from(
69
- //language=WGSL
70
- `
71
- const NSS_EXPOSURE: f32 = 7.38905609893; // e^2 — matches ARM's NSSCommon.ush
72
-
73
- // Karis tonemap (max-of-channels), applied to EXPOSURE-scaled colour.
74
- // ARM's training distribution: Tonemap(EXPOSURE * raw) -> network input.
75
- fn nss_tonemap_exposure(rgb: vec3<f32>) -> vec3<f32> {
76
- let finite = select(vec3<f32>(0.0), clamp(rgb, vec3<f32>(0.0), vec3<f32>(F16_MAX)), rgb == rgb);
77
- let scaled = finite * NSS_EXPOSURE;
78
- let m = max(max(scaled.r, scaled.g), scaled.b);
79
- return scaled / (1.0 + m);
80
- }
81
-
82
- // ARM's network was trained against inputs that go through their Quantize
83
- // formula: int8 = round(fp * 255 - 128). The conv then sees (uint8 - 128)
84
- // = signed int8 in [-128, 127] - i.e. fp 0 -> -128, fp 0.5 -> 0, fp 1 -> 127.
85
- // Our pipeline naively feeds fp [0, 1] which has DC offset +0.5 vs ARM's
86
- // expected DC of 0. The trained head biases were calibrated against that
87
- // near-zero DC, so feeding +0.5 puts every conv accumulator off by
88
- // (sum_of_weights * 0.5 * 255) - way outside the trained operating range.
89
- //
90
- // We use the SMOOTH (no-round) version of ARM's transform: a linear
91
- // remap [0, 1] -> approx [-1.008, 1.008] clamped to [-1, 1]. Matches
92
- // ARM's DC shift but without the round() discontinuities that caused
93
- // feature-dependent flickering when small jitter-driven input changes
94
- // pushed pixels across quantization boundaries. Network sensitivity to
95
- // near-boundary inputs would otherwise flip int8 outputs by 1/127 per
96
- // frame and propagate through every layer.
97
- //
98
- // Per-multiply lands at ~(ARM signed * int8_w) / 127^2, so our acc is
99
- // approx (ARM int32_acc / 127^2). Our rescale_factor (= 127 * mult /
100
- // 2^shift) then produces value_fp ~ int8_in / 127 going into the LUT -
101
- // the shape ARM's network was trained to produce.
102
- fn nss_arm_quantize(fp: f32) -> f32 {
103
- return clamp(fp * (255.0 / 127.0) - (128.0 / 127.0), -1.0, 1.0);
104
- }
105
-
106
- fn nss_arm_quantize_v3(rgb: vec3<f32>) -> vec3<f32> {
107
- return vec3<f32>(nss_arm_quantize(rgb.r), nss_arm_quantize(rgb.g), nss_arm_quantize(rgb.b));
108
- }
109
-
110
- fn nss_arm_quantize_v4(v: vec4<f32>) -> vec4<f32> {
111
- return vec4<f32>(nss_arm_quantize(v.x), nss_arm_quantize(v.y), nss_arm_quantize(v.z), nss_arm_quantize(v.w));
112
- }
113
-
114
- fn nss_warp_history_sample(prev_uv: vec2<f32>) -> vec3<f32> {
115
- let on_screen = all(prev_uv >= vec2<f32>(0.0)) && all(prev_uv <= vec2<f32>(1.0));
116
- if (!on_screen) {
117
- return vec3<f32>(0.0);
118
- }
119
- // ARM uses bilinear (LoadHistory in ffx_nss_callbacks_glsl.h:471);
120
- // Catmull-Rom is opt-in via HISTORY_CATMULL define.
121
- return max(vec3<f32>(0.0), textureSampleLevel(tHistory, sLinear, prev_uv, 0.0).rgb);
122
- }
123
-
124
- fn nss_warp_feedback_sample(prev_uv_render: vec2<f32>) -> vec4<f32> {
125
- let on_screen = all(prev_uv_render >= vec2<f32>(0.0)) && all(prev_uv_render <= vec2<f32>(1.0));
126
- if (!on_screen) {
127
- return vec4<f32>(0.0);
128
- }
129
- return textureSampleLevel(tFeedbackIn, sLinear, prev_uv_render, 0.0);
130
- }
131
-
132
- @compute @workgroup_size(${NSS_WORKGROUP_SIZE}, ${NSS_WORKGROUP_SIZE}, 1)
133
- fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
134
- let render_res_u = settings.render_resolution;
135
- let render_res = vec2<i32>(render_res_u);
136
-
137
- if (any(gid.xy >= render_res_u)) {
138
- return;
139
- }
140
-
141
- let st = vec2<i32>(gid.xy);
142
-
143
- // 1. Depth dilation
144
- var nearest_off = vec2<i32>(0, 0);
145
- let _dilated_depth = nss_find_nearest_depth(tDepthCurrent, st, render_res, &nearest_off);
146
-
147
- // 2. Velocity at the depth-nearest tap (FSR2 strategy — sharpens
148
- // silhouettes at disocclusion vs picking velocity at the centre).
149
- let velocity = textureLoad(tVelocity, st + nearest_off, 0).rg;
150
-
151
- // 3. Reproject to previous frame
152
- let st_centre = vec2<f32>(st) + 0.5;
153
- let prev_st_render = st_centre - velocity;
154
- let prev_uv_render = prev_st_render / vec2<f32>(render_res);
155
-
156
- // History lives at output resolution but the UV is the same in [0, 1].
157
- let history_rgb = nss_warp_history_sample(prev_uv_render);
158
-
159
- // 4. Disocclusion mask. The shared depth-clip pass returns FSR2
160
- // confidence (1 = trust history, 0 = disocclusion); ARM's network
161
- // input expects the inverse (high = disocclusion). Multiply by
162
- // history_validity so a hard reset zeros the mask too.
163
- let confidence = textureLoad(tDisocclusionConfidence, st, 0).r;
164
- let disocclusion_mask = (1.0 - saturate(confidence)) * saturate(settings.history_validity);
165
-
166
- // 5. Warped feedback. Multiplied by history_validity so the very first
167
- // frame (or any reset) feeds neutral (0.5 raw -> 0 post-quant)
168
- // feedback to the network instead of garbage from an uninitialised
169
- // texture.
170
- //
171
- // feedback_scale (debug knob, default 1.0) blends between actual FB
172
- // and the neutral value 0.5. At 0 the network sees raw 0.5 across
173
- // all FB channels, which post-quantize is ≈0 — the trained
174
- // "no signal" point, NOT a strong negative signal.
175
- let feedback_actual = nss_warp_feedback_sample(prev_uv_render);
176
- let feedback_neutral = vec4<f32>(0.5);
177
- let feedback = mix(
178
- feedback_neutral,
179
- feedback_actual,
180
- saturate(settings.history_validity) * saturate(settings.feedback_scale),
181
- );
182
-
183
- // 6. Current colour (load, no filtering — already at render-res)
184
- let current_rgb = max(vec3<f32>(0.0), textureLoad(tColour, st, 0).rgb);
185
-
186
- // 7. Luma derivative — uses raw colours; the chunk handles its own scaling.
187
- let luma_deriv = nss_luma_derivative(current_rgb, history_rgb);
188
-
189
- // Tonemap with EXPOSURE applied first — matches ARM's
190
- // Tonemap(EXPOSURE * raw) training distribution. Raw [0, 1] tonemap
191
- // (without exposure) lands values 2-5x below the network's trained
192
- // operating point.
193
- let history_t = nss_tonemap_exposure(history_rgb);
194
- let current_t = nss_tonemap_exposure(current_rgb);
195
-
196
- // Apply ARM's Quantize transformation in fp — converts our [0, 1] inputs
197
- // into the [-1, 1] signed-int8 / 127 distribution the trained network
198
- // expects (DC at 0, not +0.5). See nss_arm_quantize header for derivation.
199
- // settings.quantize_inputs (default 1.0) blends between this transform
200
- // and the raw [0, 1] tonemap (0.0). Useful as an A/B test knob.
201
- let q = saturate(settings.quantize_inputs);
202
- let history_q = mix(history_t, nss_arm_quantize_v3(history_t), q);
203
- let current_q = mix(current_t, nss_arm_quantize_v3(current_t), q);
204
- let disocclusion_q = mix(disocclusion_mask, nss_arm_quantize(disocclusion_mask), q);
205
- let feedback_q = mix(feedback, nss_arm_quantize_v4(feedback), q);
206
- let luma_deriv_q = mix(luma_deriv, nss_arm_quantize(luma_deriv), q);
207
-
208
- // ── Pack into 12-channel tensor ──
209
- // Layout (4ch × depth=3):
210
- // z=0 : history.rgb, current.r
211
- // z=1 : current.gb, disocclusion_mask, feedback.r
212
- // z=2 : feedback.gba, luma_derivative
213
- textureStore(tTensor, vec3<i32>(st, 0), vec4<f32>(history_q, current_q.r));
214
- textureStore(tTensor, vec3<i32>(st, 1), vec4<f32>(current_q.g, current_q.b, disocclusion_q, feedback_q.r));
215
- textureStore(tTensor, vec3<i32>(st, 2), vec4<f32>(feedback_q.gba, luma_deriv_q));
216
-
217
- // Pack nearest offset for postprocess: (-1, 0, 1) in each axis -> [0, 1]
218
- //
219
- // NOTE there are two offset codecs in flight per frame under NSS. This packs (offset + 1) * 0.5
220
- // into the rg of its own rg8unorm texture and shader_nss_postprocess decodes it inline; the TAA
221
- // depth-clip pass, which runs unconditionally and whose confidence output NSS consumes, packs
222
- // index/8 into one channel of its own output through chunk_depth_clip_offset_codec, which has a
223
- // round-trip spec. The 9-tap search itself is now shared (chunk_find_nearest_depth), so the two
224
- // agree on what they are encoding — but the search still runs twice over the same depth buffer and
225
- // a reader has to check which convention a given rg8unorm offset texture uses.
226
- //
227
- // Collapsing them means this pass reading the depth-clip g channel instead of writing
228
- // tNearestOffset, which changes what NSS is bound to and what its postprocess pair decodes. That is
229
- // a pipeline change with a visual outcome rather than a de-duplication, so it wants a measured
230
- // before/after on hardware; left as is deliberately. See DUP-039.
231
- let nearest_packed = (vec2<f32>(nearest_off) + 1.0) * 0.5;
232
- textureStore(tNearestOffset, st, vec4<f32>(nearest_packed, 0.0, 0.0));
233
- }
234
- `, [
235
- F16_MAX_DEFINITION,
236
- chunk_nss_find_nearest_depth,
237
- chunk_nss_luma_derivative,
238
- NSS_SETTINGS_STRUCT.declaration_chunk,
239
- ]
240
- );
241
-
242
- export const shader_nss_preprocess = ComputeShader.from({
243
- label: "NSS / preprocess",
244
- body,
245
- resources,
246
- });
1
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
+ import { F16_MAX_DEFINITION } from "../../shader/chunk/math/F16_MAX_DEFINITION.js";
3
+ import { ComputeShader } from "../../shader/ComputeShader.js";
4
+ import { ShaderResourceSetDescriptor } from "../../shader/resource/ShaderResourceSetDescriptor.js";
5
+ import { SAMPLER_LINEAR_UPSCALE } from "../../texture/SAMPLER_LINEAR_UPSCALE.js";
6
+ import { chunk_nss_find_nearest_depth } from "./chunk_nss_find_nearest_depth.js";
7
+ import { chunk_nss_luma_derivative } from "./chunk_nss_luma_derivative.js";
8
+ import { NSS_WORKGROUP_SIZE } from "./NSS_CONSTANTS.js";
9
+ import { NSS_SETTINGS_STRUCT } from "./NSS_SETTINGS_STRUCT.js";
10
+
11
+ /**
12
+ * NSS preprocess pass. Runs at render-resolution (one thread per render-res
13
+ * pixel) and produces:
14
+ * 1. The 12-channel network input tensor, packed into a single rgba16f
15
+ * 3D storage texture with depth=3 (channels 0..3, 4..7, 8..11).
16
+ * 2. The encoded "nearest depth offset" used by postprocess to dilate
17
+ * velocity at output-res (`tNearestOffset` — components in [0, 1]
18
+ * decode to {-1, 0, 1}² via `(x*2 - 1)`).
19
+ *
20
+ * Per-pixel logic (matches the algorithm in ARM's `Preprocess()`):
21
+ * 1. Dilate depth over a 3×3 neighbourhood, remember the offset of the
22
+ * nearest sample.
23
+ * 2. Sample velocity at the dilated coord.
24
+ * 3. Project to the previous frame, sample warped history (bilinear).
25
+ * 4. Read the FSR2 depth-clip confidence from the upstream pass and
26
+ * invert it into the network's "high = disocclusion" convention.
27
+ * 5. Sample the warped feedback tensor (bilinear).
28
+ * 6. Compute the luma derivative between current and warped history.
29
+ * 7. Pack everything into the output tensor — colours
30
+ * tonemapped via `Tonemap(EXPOSURE * raw)` to match ARM's training
31
+ * distribution.
32
+ *
33
+ * @see ARM NSS reference: `Preprocess` in
34
+ * `Source/NG-SDK/sdk/include/FidelityFX/gpu/nss/ffx_nss_preprocess.h`
35
+ */
36
+ const resources = new ShaderResourceSetDescriptor();
37
+ resources.createGroup()
38
+ .addSampler("sLinear", "filtering", SAMPLER_LINEAR_UPSCALE)
39
+ // ── inputs at render-res ──
40
+ .addTexture("tColour", "float") // jittered scene colour, render-res
41
+ // depth32float can't be bound as 'float' (filterable) — WebGPU only
42
+ // accepts depth textures via 'unfilterable-float' in this context.
43
+ // We only ever read this via textureLoad inside the depth dilation.
44
+ .addTexture("tDepthCurrent", "unfilterable-float")
45
+ .addTexture("tVelocity", "float") // pixel-space motion vectors, render-res
46
+ // FSR2 depth-clip confidence (1 = trust history, 0 = disocclusion)
47
+ // produced by the engine's shared shader_depth_occlusion_clip pass.
48
+ // We invert it into ARM's "high = disocclusion" network input.
49
+ .addTexture("tDisocclusionConfidence", "float")
50
+ // ── inputs at output-res / feedback at render-res ──
51
+ .addTexture("tHistory", "float") // previous frame upscaled colour, output-res
52
+ .addTexture("tFeedbackIn", "float") // 4-ch feedback tensor from previous frame, render-res
53
+ // ── settings ──
54
+ .addUniform("settings", NSS_SETTINGS_STRUCT)
55
+ // ── outputs ──
56
+ // Single rgba16f 3D storage texture holds the 12-channel input tensor
57
+ // packed across depth=3 layers (4 channels each). rgba16f gives the
58
+ // network ~10 bits of mantissa per channel, which is plenty for
59
+ // normalized [0, 1] inputs after the network's first BN/scale.
60
+ .addStorageTexture("tTensor", "rgba16float", "3d", "write-only")
61
+ // Nearest-depth offset packed as (dx+1, dy+1) / 2 -> [0, 1]. Postprocess
62
+ // uses this to fetch the velocity at the dilated coordinate when warping
63
+ // the history at output-resolution.
64
+ .addStorageTexture("tNearestOffset", "rg8unorm", "2d", "write-only")
65
+ ;
66
+
67
+
68
+ const body = CodeChunk.from(
69
+ //language=WGSL
70
+ `
71
+ const NSS_EXPOSURE: f32 = 7.38905609893; // e^2
72
+
73
+ // Karis tonemap (max-of-channels), applied to EXPOSURE-scaled colour.
74
+ // ARM's training distribution: Tonemap(EXPOSURE * raw) -> network input.
75
+ fn nss_tonemap_exposure(rgb: vec3<f32>) -> vec3<f32> {
76
+ let finite = select(vec3<f32>(0.0), clamp(rgb, vec3<f32>(0.0), vec3<f32>(F16_MAX)), rgb == rgb);
77
+ let scaled = finite * NSS_EXPOSURE;
78
+ let m = max(max(scaled.r, scaled.g), scaled.b);
79
+ return scaled / (1.0 + m);
80
+ }
81
+
82
+ // ARM's network was trained against inputs that go through their Quantize
83
+ // formula: int8 = round(fp * 255 - 128). The conv then sees (uint8 - 128)
84
+ // = signed int8 in [-128, 127] - i.e. fp 0 -> -128, fp 0.5 -> 0, fp 1 -> 127.
85
+ // Our pipeline naively feeds fp [0, 1] which has DC offset +0.5 vs ARM's
86
+ // expected DC of 0. The trained head biases were calibrated against that
87
+ // near-zero DC, so feeding +0.5 puts every conv accumulator off by
88
+ // (sum_of_weights * 0.5 * 255) - way outside the trained operating range.
89
+ //
90
+ // We use the SMOOTH (no-round) version of ARM's transform: a linear
91
+ // remap [0, 1] -> approx [-1.008, 1.008] clamped to [-1, 1]. Matches
92
+ // ARM's DC shift but without the round() discontinuities that caused
93
+ // feature-dependent flickering when small jitter-driven input changes
94
+ // pushed pixels across quantization boundaries. Network sensitivity to
95
+ // near-boundary inputs would otherwise flip int8 outputs by 1/127 per
96
+ // frame and propagate through every layer.
97
+ //
98
+ // Per-multiply lands at ~(ARM signed * int8_w) / 127^2, so our acc is
99
+ // approx (ARM int32_acc / 127^2). Our rescale_factor (= 127 * mult /
100
+ // 2^shift) then produces value_fp ~ int8_in / 127 going into the LUT -
101
+ // the shape ARM's network was trained to produce.
102
+ fn nss_arm_quantize(fp: f32) -> f32 {
103
+ return clamp(fp * (255.0 / 127.0) - (128.0 / 127.0), -1.0, 1.0);
104
+ }
105
+
106
+ fn nss_arm_quantize_v3(rgb: vec3<f32>) -> vec3<f32> {
107
+ return vec3<f32>(nss_arm_quantize(rgb.r), nss_arm_quantize(rgb.g), nss_arm_quantize(rgb.b));
108
+ }
109
+
110
+ fn nss_arm_quantize_v4(v: vec4<f32>) -> vec4<f32> {
111
+ return vec4<f32>(nss_arm_quantize(v.x), nss_arm_quantize(v.y), nss_arm_quantize(v.z), nss_arm_quantize(v.w));
112
+ }
113
+
114
+ fn nss_warp_history_sample(prev_uv: vec2<f32>) -> vec3<f32> {
115
+ let on_screen = all(prev_uv >= vec2<f32>(0.0)) && all(prev_uv <= vec2<f32>(1.0));
116
+ if (!on_screen) {
117
+ return vec3<f32>(0.0);
118
+ }
119
+ // ARM uses bilinear (LoadHistory in ffx_nss_callbacks_glsl.h:471);
120
+ // Catmull-Rom is opt-in via HISTORY_CATMULL define.
121
+ return max(vec3<f32>(0.0), textureSampleLevel(tHistory, sLinear, prev_uv, 0.0).rgb);
122
+ }
123
+
124
+ fn nss_warp_feedback_sample(prev_uv_render: vec2<f32>) -> vec4<f32> {
125
+ let on_screen = all(prev_uv_render >= vec2<f32>(0.0)) && all(prev_uv_render <= vec2<f32>(1.0));
126
+ if (!on_screen) {
127
+ return vec4<f32>(0.0);
128
+ }
129
+ return textureSampleLevel(tFeedbackIn, sLinear, prev_uv_render, 0.0);
130
+ }
131
+
132
+ @compute @workgroup_size(${NSS_WORKGROUP_SIZE}, ${NSS_WORKGROUP_SIZE}, 1)
133
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
134
+ let render_res_u = settings.render_resolution;
135
+ let render_res = vec2<i32>(render_res_u);
136
+
137
+ if (any(gid.xy >= render_res_u)) {
138
+ return;
139
+ }
140
+
141
+ let st = vec2<i32>(gid.xy);
142
+
143
+ // 1. Depth dilation
144
+ var nearest_off = vec2<i32>(0, 0);
145
+ let _dilated_depth = nss_find_nearest_depth(tDepthCurrent, st, render_res, &nearest_off);
146
+
147
+ // 2. Velocity at the depth-nearest tap (FSR2 strategy — sharpens
148
+ // silhouettes at disocclusion vs picking velocity at the centre).
149
+ let velocity = textureLoad(tVelocity, st + nearest_off, 0).rg;
150
+
151
+ // 3. Reproject to previous frame
152
+ let st_centre = vec2<f32>(st) + 0.5;
153
+ let prev_st_render = st_centre - velocity;
154
+ let prev_uv_render = prev_st_render / vec2<f32>(render_res);
155
+
156
+ // History lives at output resolution but the UV is the same in [0, 1].
157
+ let history_rgb = nss_warp_history_sample(prev_uv_render);
158
+
159
+ // 4. Disocclusion mask. The shared depth-clip pass returns FSR2
160
+ // confidence (1 = trust history, 0 = disocclusion); ARM's network
161
+ // input expects the inverse (high = disocclusion). Multiply by
162
+ // history_validity so a hard reset zeros the mask too.
163
+ let confidence = textureLoad(tDisocclusionConfidence, st, 0).r;
164
+ let disocclusion_mask = (1.0 - saturate(confidence)) * saturate(settings.history_validity);
165
+
166
+ // 5. Warped feedback. Multiplied by history_validity so the very first
167
+ // frame (or any reset) feeds neutral (0.5 raw -> 0 post-quant)
168
+ // feedback to the network instead of garbage from an uninitialised
169
+ // texture.
170
+ //
171
+ // feedback_scale (debug knob, default 1.0) blends between actual FB
172
+ // and the neutral value 0.5. At 0 the network sees raw 0.5 across
173
+ // all FB channels, which post-quantize is ≈0 — the trained
174
+ // "no signal" point, NOT a strong negative signal.
175
+ let feedback_actual = nss_warp_feedback_sample(prev_uv_render);
176
+ let feedback_neutral = vec4<f32>(0.5);
177
+ let feedback = mix(
178
+ feedback_neutral,
179
+ feedback_actual,
180
+ saturate(settings.history_validity) * saturate(settings.feedback_scale),
181
+ );
182
+
183
+ // 6. Current colour (load, no filtering — already at render-res)
184
+ let current_rgb = max(vec3<f32>(0.0), textureLoad(tColour, st, 0).rgb);
185
+
186
+ // 7. Luma derivative — uses raw colours; the chunk handles its own scaling.
187
+ let luma_deriv = nss_luma_derivative(current_rgb, history_rgb);
188
+
189
+ // Tonemap with EXPOSURE applied first — matches ARM's
190
+ // Tonemap(EXPOSURE * raw) training distribution. Raw [0, 1] tonemap
191
+ // (without exposure) lands values 2-5x below the network's trained
192
+ // operating point.
193
+ let history_t = nss_tonemap_exposure(history_rgb);
194
+ let current_t = nss_tonemap_exposure(current_rgb);
195
+
196
+ // Apply ARM's Quantize transformation in fp — converts our [0, 1] inputs
197
+ // into the [-1, 1] signed-int8 / 127 distribution the trained network
198
+ // expects (DC at 0, not +0.5). See nss_arm_quantize header for derivation.
199
+ // settings.quantize_inputs (default 1.0) blends between this transform
200
+ // and the raw [0, 1] tonemap (0.0). Useful as an A/B test knob.
201
+ let q = saturate(settings.quantize_inputs);
202
+ let history_q = mix(history_t, nss_arm_quantize_v3(history_t), q);
203
+ let current_q = mix(current_t, nss_arm_quantize_v3(current_t), q);
204
+ let disocclusion_q = mix(disocclusion_mask, nss_arm_quantize(disocclusion_mask), q);
205
+ let feedback_q = mix(feedback, nss_arm_quantize_v4(feedback), q);
206
+ let luma_deriv_q = mix(luma_deriv, nss_arm_quantize(luma_deriv), q);
207
+
208
+ // ── Pack into 12-channel tensor ──
209
+ // Layout (4ch × depth=3):
210
+ // z=0 : history.rgb, current.r
211
+ // z=1 : current.gb, disocclusion_mask, feedback.r
212
+ // z=2 : feedback.gba, luma_derivative
213
+ textureStore(tTensor, vec3<i32>(st, 0), vec4<f32>(history_q, current_q.r));
214
+ textureStore(tTensor, vec3<i32>(st, 1), vec4<f32>(current_q.g, current_q.b, disocclusion_q, feedback_q.r));
215
+ textureStore(tTensor, vec3<i32>(st, 2), vec4<f32>(feedback_q.gba, luma_deriv_q));
216
+
217
+ // Pack nearest offset for postprocess: (-1, 0, 1) in each axis -> [0, 1]
218
+ //
219
+ // NOTE there are two offset codecs in flight per frame under NSS. This packs (offset + 1) * 0.5
220
+ // into the rg of its own rg8unorm texture and shader_nss_postprocess decodes it inline; the TAA
221
+ // depth-clip pass, which runs unconditionally and whose confidence output NSS consumes, packs
222
+ // index/8 into one channel of its own output through chunk_depth_clip_offset_codec, which has a
223
+ // round-trip spec. The 9-tap search itself is now shared (chunk_find_nearest_depth), so the two
224
+ // agree on what they are encoding — but the search still runs twice over the same depth buffer and
225
+ // a reader has to check which convention a given rg8unorm offset texture uses.
226
+ //
227
+ // Collapsing them means this pass reading the depth-clip g channel instead of writing
228
+ // tNearestOffset, which changes what NSS is bound to and what its postprocess pair decodes. That is
229
+ // a pipeline change with a visual outcome rather than a de-duplication, so it wants a measured
230
+ // before/after on hardware; left as is deliberately. See DUP-039.
231
+ let nearest_packed = (vec2<f32>(nearest_off) + 1.0) * 0.5;
232
+ textureStore(tNearestOffset, st, vec4<f32>(nearest_packed, 0.0, 0.0));
233
+ }
234
+ `, [
235
+ F16_MAX_DEFINITION,
236
+ chunk_nss_find_nearest_depth,
237
+ chunk_nss_luma_derivative,
238
+ NSS_SETTINGS_STRUCT.declaration_chunk,
239
+ ]
240
+ );
241
+
242
+ export const shader_nss_preprocess = ComputeShader.from({
243
+ label: "NSS / preprocess",
244
+ body,
245
+ resources,
246
+ });
@@ -3,8 +3,7 @@
3
3
  * place — because there is more than one reason to reverse and they are not independent of each
4
4
  * other.
5
5
  *
6
- * Feed the answer to `triangle_list_reverse_winding`. Nanite's `ReverseWindingOrder` is the same
7
- * function for the same reason: a GPU-driven draw mixes instances that disagree about this, so it
6
+ * Feed the answer to `triangle_list_reverse_winding`: a GPU-driven draw mixes instances that disagree about this, so it
8
7
  * cannot be pipeline state, and every reason has to be combined before the corner is chosen.
9
8
  *
10
9
  * @see chunk_triangle_list_reverse_winding
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_triangle_winding_is_reversed.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;GAWG;AACH,iDAFU,SAAS,CAmBb;0BA/BoB,iCAAiC"}
1
+ {"version":3,"file":"chunk_triangle_winding_is_reversed.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.js"],"names":[],"mappings":"AAKA;;;;;;;;;;GAUG;AACH,iDAFU,SAAS,CAmBb;0BA9BoB,iCAAiC"}
@@ -1,35 +1,34 @@
1
- import { chunk_material_draw_side } from "../material/chunk_material_draw_side.js";
2
- import { chunk_node3d_flags } from "../scene/chunk_node3d_flags.js";
3
- import { NODE3D_STRUCT } from "../scene/NODE3D_STRUCT.js";
4
- import { CodeChunk } from "../shader/compiler/CodeChunk.js";
5
-
6
- /**
7
- * The whole of what a vertex shader needs to know to emit a triangle the right way round, in one
8
- * place — because there is more than one reason to reverse and they are not independent of each
9
- * other.
10
- *
11
- * Feed the answer to `triangle_list_reverse_winding`. Nanite's `ReverseWindingOrder` is the same
12
- * function for the same reason: a GPU-driven draw mixes instances that disagree about this, so it
13
- * cannot be pipeline state, and every reason has to be combined before the corner is chosen.
14
- *
15
- * @see chunk_triangle_list_reverse_winding
16
- * @type {CodeChunk}
17
- */
18
- export const chunk_triangle_winding_is_reversed = CodeChunk.from(
19
- //language=WGSL
20
- `
21
- /**
22
- * Whether this instance's triangles must be emitted back to front.
23
- *
24
- * Two reasons, and they cancel: the instance's transform reflects, or the material asks for the
25
- * back face. A back-sided material on a mirrored instance is wound like a front-sided one on an
26
- * ordinary instance, and draws with the same pipeline state as both.
27
- */
28
- fn triangle_winding_is_reversed( node: ${NODE3D_STRUCT.wgsl_ref}, draw_side: u32 ) -> bool{
29
- return node3d_global_is_mirrored(node) != material_draws_back_side(draw_side);
30
- }
31
- `, [
32
- NODE3D_STRUCT.declaration_chunk,
33
- chunk_node3d_flags,
34
- chunk_material_draw_side,
35
- ])
1
+ import { chunk_material_draw_side } from "../material/chunk_material_draw_side.js";
2
+ import { chunk_node3d_flags } from "../scene/chunk_node3d_flags.js";
3
+ import { NODE3D_STRUCT } from "../scene/NODE3D_STRUCT.js";
4
+ import { CodeChunk } from "../shader/compiler/CodeChunk.js";
5
+
6
+ /**
7
+ * The whole of what a vertex shader needs to know to emit a triangle the right way round, in one
8
+ * place — because there is more than one reason to reverse and they are not independent of each
9
+ * other.
10
+ *
11
+ * Feed the answer to `triangle_list_reverse_winding`: a GPU-driven draw mixes instances that disagree about this, so it
12
+ * cannot be pipeline state, and every reason has to be combined before the corner is chosen.
13
+ *
14
+ * @see chunk_triangle_list_reverse_winding
15
+ * @type {CodeChunk}
16
+ */
17
+ export const chunk_triangle_winding_is_reversed = CodeChunk.from(
18
+ //language=WGSL
19
+ `
20
+ /**
21
+ * Whether this instance's triangles must be emitted back to front.
22
+ *
23
+ * Two reasons, and they cancel: the instance's transform reflects, or the material asks for the
24
+ * back face. A back-sided material on a mirrored instance is wound like a front-sided one on an
25
+ * ordinary instance, and draws with the same pipeline state as both.
26
+ */
27
+ fn triangle_winding_is_reversed( node: ${NODE3D_STRUCT.wgsl_ref}, draw_side: u32 ) -> bool{
28
+ return node3d_global_is_mirrored(node) != material_draws_back_side(draw_side);
29
+ }
30
+ `, [
31
+ NODE3D_STRUCT.declaration_chunk,
32
+ chunk_node3d_flags,
33
+ chunk_material_draw_side,
34
+ ])
@@ -7,7 +7,7 @@ export const C_MIE_SCATTERING_DECLARATION: CodeChunk;
7
7
  * Mie extinction: scattering plus absorption. Hillaire's Earth authors this and the scattering,
8
8
  * not the absorption -- 0.004440 and 0.003996 per km.
9
9
  *
10
- * @see https://github.com/sebh/UnrealEngineSkyAtmosphere/blob/183ead5bdacc701b3b626347a680a2f3cd3d4fbd/Application/SkyAtmosphereCommon.cpp#L40
10
+ * @see "A Scalable and Production Ready Sky and Atmosphere Rendering Technique", Hillaire (2020)
11
11
  */
12
12
  export const C_MIE_EXTINCTION_DECLARATION: CodeChunk;
13
13
  /**
@@ -15,7 +15,7 @@ export const C_MIE_EXTINCTION_DECLARATION: CodeChunk;
15
15
  * a tenth of the extinction. The shadertoy port wrote the 4.4 extinction here as the absorption,
16
16
  * which put the extinction at 8.396e-6.
17
17
  *
18
- * @see https://github.com/sebh/UnrealEngineSkyAtmosphere/blob/183ead5bdacc701b3b626347a680a2f3cd3d4fbd/Application/Game.cpp#L707
18
+ * @see "A Scalable and Production Ready Sky and Atmosphere Rendering Technique", Hillaire (2020)
19
19
  */
20
20
  export const C_MIE_ABSORPTION_DECLARATION: CodeChunk;
21
21
  import { CodeChunk } from "../../compiler/CodeChunk.js";
@@ -13,7 +13,7 @@ export const C_MIE_SCATTERING_DECLARATION = CodeChunk.from(
13
13
  * Mie extinction: scattering plus absorption. Hillaire's Earth authors this and the scattering,
14
14
  * not the absorption -- 0.004440 and 0.003996 per km.
15
15
  *
16
- * @see https://github.com/sebh/UnrealEngineSkyAtmosphere/blob/183ead5bdacc701b3b626347a680a2f3cd3d4fbd/Application/SkyAtmosphereCommon.cpp#L40
16
+ * @see "A Scalable and Production Ready Sky and Atmosphere Rendering Technique", Hillaire (2020)
17
17
  */
18
18
  export const C_MIE_EXTINCTION_DECLARATION = CodeChunk.from(
19
19
  //language=WGSL
@@ -25,7 +25,7 @@ export const C_MIE_EXTINCTION_DECLARATION = CodeChunk.from(
25
25
  * a tenth of the extinction. The shadertoy port wrote the 4.4 extinction here as the absorption,
26
26
  * which put the extinction at 8.396e-6.
27
27
  *
28
- * @see https://github.com/sebh/UnrealEngineSkyAtmosphere/blob/183ead5bdacc701b3b626347a680a2f3cd3d4fbd/Application/Game.cpp#L707
28
+ * @see "A Scalable and Production Ready Sky and Atmosphere Rendering Technique", Hillaire (2020)
29
29
  */
30
30
  export const C_MIE_ABSORPTION_DECLARATION = CodeChunk.from(
31
31
  //language=WGSL
@@ -1,5 +1,5 @@
1
1
  # references:
2
- https://github.com/sebh/UnrealEngineSkyAtmosphere
2
+ https://sebh.github.io/publications/egsr2020.pdf
3
3
  https://www.shadertoy.com/view/slSXRW
4
4
  https://www.reddit.com/r/GraphicsProgramming/comments/osbbhg/shadertoy_implementation_of_a_scalable_and/
5
5
  https://github1s.com/Fewes/MinimalAtmosphere/blob/master/Assets/Atmosphere/Shaders/Atmosphere.cginc#L146