@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.
- package/editor/ecs/component/editors/ecs/Trail3DEditor.d.ts +3 -0
- package/editor/ecs/component/editors/ecs/Trail3DEditor.d.ts.map +1 -1
- package/editor/ecs/component/editors/ecs/Trail3DEditor.js +6 -0
- package/package.json +1 -1
- package/src/engine/ecs/ik/PLAN.md +1 -1
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +1 -2
- package/src/engine/graphics/ecs/trail3d/TRAIL3D_FADE_LINEAR.d.ts +14 -0
- package/src/engine/graphics/ecs/trail3d/TRAIL3D_FADE_LINEAR.d.ts.map +1 -0
- package/src/engine/graphics/ecs/trail3d/TRAIL3D_FADE_LINEAR.js +22 -0
- package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts +19 -3
- package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts.map +1 -1
- package/src/engine/graphics/ecs/trail3d/Trail3D.js +31 -4
- package/src/engine/graphics/ecs/trail3d/advance_trail.js +1 -1
- package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.d.ts +5 -5
- package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.d.ts.map +1 -1
- package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.js +6 -6
- package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts +10 -0
- package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts.map +1 -1
- package/src/engine/graphics3/trail/trail_tube_write_geometry.js +13 -1
- package/src/engine/physics/cloth/ecs/cloth_geodesic.d.ts +2 -2
- package/src/engine/physics/cloth/ecs/cloth_geodesic.js +2 -2
- package/src/shade/playground/probe_clipmap/README.md +1 -0
- package/src/shade/playground/probe_clipmap/index.html +5 -0
- package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
- package/src/shade/playground/probe_clipmap/main.js +16 -2
- package/src/shade/playground/vgeo_scene/README.md +1 -1
- package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.d.ts +4 -6
- package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/MULTISCATTER_LUT_CONFIG.js +34 -36
- package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts +1 -1
- package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts.map +1 -1
- package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.js +162 -163
- package/src/shade/renderer/atmosphere/compute_mie_absorption.d.ts +1 -1
- package/src/shade/renderer/atmosphere/compute_mie_absorption.js +1 -1
- package/src/shade/renderer/atmosphere/hillaire/ATMOSPHERE_EARTH.js +1 -1
- package/src/shade/renderer/atmosphere/hillaire/ATMOSPHERE_PARAMETERS_STRUCT.js +1 -1
- package/src/shade/renderer/atmosphere/shader_multiscatter_lut.js +164 -164
- package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.js +1 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +2 -2
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +2 -2
- package/src/shade/renderer/geometry/sdf/cards/mesh_cards_raster_pass_descriptor.js +2 -2
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.d.ts +1 -1
- package/src/shade/renderer/geometry/sdf/cards/shader_mesh_cards_histogram.js +1 -1
- package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.d.ts +4 -5
- package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.js +6 -7
- package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +1 -1
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +2 -4
- package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +3 -10
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +119 -38
- package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +2 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +12 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +22 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +4 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +50 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +6 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +7 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_RESAMPLING.d.ts +13 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_RESAMPLING.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP_RESAMPLING.js +13 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +17 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +20 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_resampled.d.ts +18 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_resampled.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_resampled.js +42 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +5 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +4 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js +13 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_resample.d.ts +52 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_resample.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_resample.js +250 -0
- package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +7 -7
- package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +2 -2
- package/src/shade/renderer/light/environment/environment_level_1_blur_plan.d.ts +39 -0
- package/src/shade/renderer/light/environment/environment_level_1_blur_plan.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/environment_level_1_blur_plan.js +119 -0
- package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts +15 -7
- package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/execute_filter_environment_map.js +66 -83
- package/src/shade/renderer/light/environment/graph_filter_environment_map.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/graph_filter_environment_map.js +15 -6
- package/src/shade/renderer/light/environment/shader_blur_environment_map.d.ts +3 -0
- package/src/shade/renderer/light/environment/shader_blur_environment_map.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/shader_blur_environment_map.js +111 -0
- package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_blurred.d.ts +3 -0
- package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_blurred.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_blurred.js +128 -0
- package/src/shade/renderer/light/environment/shader_downsample_environment_map.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/shader_downsample_environment_map.js +0 -1
- package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +1 -4
- package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +2 -2
- package/src/shade/renderer/postprocess/nss/NOTES.md +14 -21
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -3
- package/src/shade/renderer/postprocess/nss/NSS.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/NSS.js +1 -3
- package/src/shade/renderer/postprocess/nss/NSS_NETWORK_SCHEMA.d.ts +5 -6
- package/src/shade/renderer/postprocess/nss/NSS_NETWORK_SCHEMA.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/NSS_NETWORK_SCHEMA.js +9 -10
- package/src/shade/renderer/postprocess/nss/shader_nss_extract_feedback.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_extract_feedback.js +48 -49
- package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +12 -16
- package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +246 -246
- package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.d.ts +1 -2
- package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.js +34 -35
- package/src/shade/renderer/shader/chunk/atmosphere/C_MIE_SCATTERING_DECLARATION.d.ts +2 -2
- package/src/shade/renderer/shader/chunk/atmosphere/C_MIE_SCATTERING_DECLARATION.js +2 -2
- package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +1 -1
- package/src/shade/renderer/shader/chunk/atmosphere/chunk_compute_extinction.js +1 -1
- package/src/shade/renderer/shader/chunk/atmosphere/hillaire/DENSITY_PROFILE_LAYER_STRUCT.d.ts +1 -1
- package/src/shade/renderer/shader/chunk/atmosphere/hillaire/DENSITY_PROFILE_LAYER_STRUCT.js +1 -1
- package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +4 -7
- package/src/shade/renderer/shader/chunk/brdf/fresnel/chunk_F_Schlick.d.ts +3 -3
- package/src/shade/renderer/shader/chunk/brdf/fresnel/chunk_F_Schlick.js +3 -3
- package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +12 -19
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.d.ts +9 -10
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.js +9 -10
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.d.ts +4 -4
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.js +5 -5
- package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +1 -1
- package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.d.ts +1 -2
- package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.js +1 -2
- package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec2.d.ts +14 -1
- package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec2.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec2.js +19 -6
- package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec3.d.ts +10 -1
- package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec3.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/noise/chunk_stbn_sample_vec3.js +14 -6
- package/src/shade/renderer/shader/chunk/random/murmur/chunk_murmur3_vec3u.d.ts +1 -1
- package/src/shade/renderer/shader/chunk/random/murmur/chunk_murmur3_vec3u.js +1 -1
- package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +9 -14
- package/src/shade/renderer/shadow/contact/FINDINGS.md +5 -5
- package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_DYNAMIC_LOD_BIAS.d.ts +2 -3
- package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_DYNAMIC_LOD_BIAS.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_DYNAMIC_LOD_BIAS.js +7 -8
- package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_LOAD_FACTOR.d.ts +1 -1
- package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_MAX_LOAD_FACTOR.js +12 -12
- package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts +2 -2
- package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/VSMPageManager.js +3 -4
- package/src/shade/renderer/texture/mipmaps/NOTES.md +1 -2
- package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +1 -1
- package/src/view/elements/progress/segmented/SegmentedResourceBarView.d.ts +0 -19
- package/src/view/elements/progress/segmented/SegmentedResourceBarView.d.ts.map +1 -1
- package/src/view/elements/progress/segmented/SegmentedResourceBarView.js +2 -52
- package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_averages.d.ts +0 -13
- package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_averages.d.ts.map +0 -1
- package/src/shade/renderer/light/environment/shader_convolve_reflection_map_from_averages.js +0 -198
- package/src/view/elements/progress/segmented/segment_frame_transform.d.ts +0 -15
- package/src/view/elements/progress/segmented/segment_frame_transform.d.ts.map +0 -1
- 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
|
|
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
|
|
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
|
|
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
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* @
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|