@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,164 +1,164 @@
|
|
|
1
|
-
import { WebGPUExtensionType } from "../../descriptor/WebGPUExtensionType.js";
|
|
2
|
-
import { ATMOSPHERE_HEIGHT_DECLARATION } from "../shader/chunk/atmosphere/ATMOSPHERE_HEIGHT_DECLARATION.js";
|
|
3
|
-
import { chunk_safe_acos } from "../shader/chunk/math/chunk_safe_acos.js";
|
|
4
|
-
import { CodeChunk } from "../shader/compiler/CodeChunk.js";
|
|
5
|
-
import { ComputeShader } from "../shader/ComputeShader.js";
|
|
6
|
-
import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
|
|
7
|
-
import { chunk_get_multiscatter_values } from "./chunk_get_multiscatter_values.js";
|
|
8
|
-
import { chunk_multiscatter_sample_direction } from "./chunk_multiscatter_sample_direction.js";
|
|
9
|
-
import { chunk_sky_lut_texel_to_unit } from "./chunk_sky_lut_texel_to_unit.js";
|
|
10
|
-
import {
|
|
11
|
-
MULTISCATTER_LUT_DIRECTION_COUNT,
|
|
12
|
-
MULTISCATTER_LUT_MAX_SUBGROUP_PARTIALS
|
|
13
|
-
} from "./MULTISCATTER_LUT_CONFIG.js";
|
|
14
|
-
import { SAMPLER_SKY_LUT } from "./SAMPLER_SKY_LUT.js";
|
|
15
|
-
|
|
16
|
-
const resources = new ShaderResourceSetDescriptor();
|
|
17
|
-
resources.createGroup()
|
|
18
|
-
// "float" rather than the default "unfilterable-float": rgba16float is filterable in
|
|
19
|
-
// core WebGPU, so the LUT goes through the texture unit instead of a 4-tap manual
|
|
20
|
-
// bilinear.
|
|
21
|
-
.addTexture("tSkyLutTransmittance", "float")
|
|
22
|
-
.addSampler("sSkyLut", "filtering", SAMPLER_SKY_LUT)
|
|
23
|
-
.addStorageTexture("tSkyLutMultiscatterOut", "rgba16float")
|
|
24
|
-
;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* the multiple-scattering LUT. Each pixel coordinate corresponds to a height and sun zenith angle, and
|
|
29
|
-
* the value is the multiple scattering approximation (Psi_ms from the paper, Eq. 10).
|
|
30
|
-
*
|
|
31
|
-
* One workgroup per LUT texel, one thread per direction
|
|
32
|
-
*
|
|
33
|
-
* inside a fragment shader, which left the whole pass with 32*32 = 1024 threads of
|
|
34
|
-
* parallelism -- a few dozen waves, one per scheduler at best, with nothing to hide the
|
|
35
|
-
* latency of the transmittance fetches. Per-thread it is now a single direction's 20-step
|
|
36
|
-
* march.
|
|
37
|
-
*
|
|
38
|
-
* The per-direction results are summed with `subgroupAdd` and then across subgroups through
|
|
39
|
-
* workgroup memory
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* @see "A Scalable and Production Ready Sky and Atmosphere Rendering Technique", Hillaire (2020)
|
|
43
|
-
* @see https://www.shadertoy.com/view/slSXRW
|
|
44
|
-
* @type {CodeChunk}
|
|
45
|
-
*/
|
|
46
|
-
const body = CodeChunk.from(
|
|
47
|
-
//language=WGSL
|
|
48
|
-
`
|
|
49
|
-
const MULTISCATTER_DIRECTION_COUNT = ${MULTISCATTER_LUT_DIRECTION_COUNT}u;
|
|
50
|
-
const MULTISCATTER_MAX_SUBGROUP_PARTIALS = ${MULTISCATTER_LUT_MAX_SUBGROUP_PARTIALS}u;
|
|
51
|
-
|
|
52
|
-
var<workgroup> wg_partial_count: atomic<u32>;
|
|
53
|
-
var<workgroup> wg_lum: array<vec3<f32>, MULTISCATTER_MAX_SUBGROUP_PARTIALS>;
|
|
54
|
-
var<workgroup> wg_fms: array<vec3<f32>, MULTISCATTER_MAX_SUBGROUP_PARTIALS>;
|
|
55
|
-
|
|
56
|
-
@compute @workgroup_size(${MULTISCATTER_LUT_DIRECTION_COUNT}, 1, 1)
|
|
57
|
-
fn main(
|
|
58
|
-
@builtin(workgroup_id) workgroup_id: vec3<u32>,
|
|
59
|
-
@builtin(local_invocation_index) thread_index: u32,
|
|
60
|
-
) {
|
|
61
|
-
|
|
62
|
-
if (thread_index == 0u) {
|
|
63
|
-
atomicStore(&wg_partial_count, 0u);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Every thread is here together anyway, so the counter's initialisation costs nothing
|
|
67
|
-
// beyond the barrier itself. WGSL does not promise workgroup variables start zeroed.
|
|
68
|
-
workgroupBarrier();
|
|
69
|
-
|
|
70
|
-
// one workgroup per texel; the dispatch is sized from the texture, so this is in range
|
|
71
|
-
let texel = workgroup_id.xy;
|
|
72
|
-
|
|
73
|
-
let lut_size = vec2<f32>(textureDimensions(tSkyLutMultiscatterOut));
|
|
74
|
-
|
|
75
|
-
// The point of each range this texel stands for: texel 0 carries the bottom and the last
|
|
76
|
-
// texel the top, which is what lets a lookup at either end read a value computed there
|
|
77
|
-
// rather than one from half a texel inside. sky_lut_uv is the other half of this.
|
|
78
|
-
let unit = sky_lut_texel_to_unit(vec2<f32>(texel), lut_size);
|
|
79
|
-
|
|
80
|
-
let sunCosTheta = 2.0*unit.x - 1.0;
|
|
81
|
-
let sunTheta = safe_acos(sunCosTheta);
|
|
82
|
-
|
|
83
|
-
let height = ATMOSPHERE_HEIGHT*unit.y;
|
|
84
|
-
|
|
85
|
-
let pos = vec3(0.0, height, 0.0);
|
|
86
|
-
let sunDir = normalize(vec3(0.0, sunCosTheta, -sin(sunTheta)));
|
|
87
|
-
|
|
88
|
-
// pos on the +y axis and sunDir with a zero x component are exactly the preconditions
|
|
89
|
-
// multiscatter_sample_direction's half-azimuth sample set needs
|
|
90
|
-
let rayDir = multiscatter_sample_direction(thread_index);
|
|
91
|
-
|
|
92
|
-
var lum:vec3<f32>;
|
|
93
|
-
var f_ms:vec3<f32>;
|
|
94
|
-
|
|
95
|
-
get_multiscatter_values(pos, sunDir, rayDir, &lum, &f_ms);
|
|
96
|
-
|
|
97
|
-
// Uniform control flow up to here, so every one of the workgroup's threads is an active
|
|
98
|
-
// lane and the subgroup sum covers all of them.
|
|
99
|
-
let lum_subgroup = subgroupAdd(lum);
|
|
100
|
-
let fms_subgroup = subgroupAdd(f_ms);
|
|
101
|
-
|
|
102
|
-
// subgroupElect picks exactly one active invocation per subgroup, and the slot it claims
|
|
103
|
-
// is whichever the counter hands out. Deriving the slot from local_invocation_index /
|
|
104
|
-
// subgroup_size instead would assume invocations are packed into subgroups in contiguous
|
|
105
|
-
// index order, which WGSL leaves unspecified: a mapping that is not contiguous blocks
|
|
106
|
-
// would collide two subgroups onto one slot and silently drop a partial sum. Which slot
|
|
107
|
-
// a subgroup lands in does not matter, only that it gets its own.
|
|
108
|
-
//
|
|
109
|
-
// Every lane holds the same subgroup sum, so letting them all store it would be a data
|
|
110
|
-
// race on one address even though the values agree.
|
|
111
|
-
if (subgroupElect()) {
|
|
112
|
-
let slot = atomicAdd(&wg_partial_count, 1u);
|
|
113
|
-
|
|
114
|
-
wg_lum[slot] = lum_subgroup;
|
|
115
|
-
wg_fms[slot] = fms_subgroup;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
workgroupBarrier();
|
|
119
|
-
|
|
120
|
-
if (thread_index != 0u) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// WGSL pins the subgroup size to a power of two in [4, 128], so the workgroup cannot hold
|
|
125
|
-
// more subgroups than the partials array has room for. The clamp keeps a driver that
|
|
126
|
-
// broke that promise reading initialised slots rather than garbage.
|
|
127
|
-
let partial_count = min(atomicLoad(&wg_partial_count), MULTISCATTER_MAX_SUBGROUP_PARTIALS);
|
|
128
|
-
|
|
129
|
-
var lum_total = vec3(0.0);
|
|
130
|
-
var fms_total = vec3(0.0);
|
|
131
|
-
|
|
132
|
-
for (var i = 0u; i < partial_count; i++) {
|
|
133
|
-
lum_total += wg_lum[i];
|
|
134
|
-
fms_total += wg_fms[i];
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// The directions carry equal solid angle, so the mean over them is the spherical average
|
|
138
|
-
// the paper's uniform phase reduces to.
|
|
139
|
-
let inv_samples = 1.0 / f32(MULTISCATTER_DIRECTION_COUNT);
|
|
140
|
-
|
|
141
|
-
lum_total *= inv_samples;
|
|
142
|
-
fms_total *= inv_samples;
|
|
143
|
-
|
|
144
|
-
// Equation 10 from the paper.
|
|
145
|
-
let psi = lum_total / (1.0 - fms_total);
|
|
146
|
-
|
|
147
|
-
textureStore(tSkyLutMultiscatterOut, texel, vec4(psi, 1.0));
|
|
148
|
-
}
|
|
149
|
-
`, [
|
|
150
|
-
chunk_safe_acos,
|
|
151
|
-
ATMOSPHERE_HEIGHT_DECLARATION,
|
|
152
|
-
chunk_multiscatter_sample_direction,
|
|
153
|
-
chunk_sky_lut_texel_to_unit,
|
|
154
|
-
chunk_get_multiscatter_values,
|
|
155
|
-
]
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
body.addExtension(WebGPUExtensionType.Subgroups);
|
|
159
|
-
|
|
160
|
-
export const shader_multiscatter_lut = ComputeShader.from({
|
|
161
|
-
label: "Sky / multi-scatter LUT",
|
|
162
|
-
body,
|
|
163
|
-
resources,
|
|
164
|
-
});
|
|
1
|
+
import { WebGPUExtensionType } from "../../descriptor/WebGPUExtensionType.js";
|
|
2
|
+
import { ATMOSPHERE_HEIGHT_DECLARATION } from "../shader/chunk/atmosphere/ATMOSPHERE_HEIGHT_DECLARATION.js";
|
|
3
|
+
import { chunk_safe_acos } from "../shader/chunk/math/chunk_safe_acos.js";
|
|
4
|
+
import { CodeChunk } from "../shader/compiler/CodeChunk.js";
|
|
5
|
+
import { ComputeShader } from "../shader/ComputeShader.js";
|
|
6
|
+
import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
|
|
7
|
+
import { chunk_get_multiscatter_values } from "./chunk_get_multiscatter_values.js";
|
|
8
|
+
import { chunk_multiscatter_sample_direction } from "./chunk_multiscatter_sample_direction.js";
|
|
9
|
+
import { chunk_sky_lut_texel_to_unit } from "./chunk_sky_lut_texel_to_unit.js";
|
|
10
|
+
import {
|
|
11
|
+
MULTISCATTER_LUT_DIRECTION_COUNT,
|
|
12
|
+
MULTISCATTER_LUT_MAX_SUBGROUP_PARTIALS
|
|
13
|
+
} from "./MULTISCATTER_LUT_CONFIG.js";
|
|
14
|
+
import { SAMPLER_SKY_LUT } from "./SAMPLER_SKY_LUT.js";
|
|
15
|
+
|
|
16
|
+
const resources = new ShaderResourceSetDescriptor();
|
|
17
|
+
resources.createGroup()
|
|
18
|
+
// "float" rather than the default "unfilterable-float": rgba16float is filterable in
|
|
19
|
+
// core WebGPU, so the LUT goes through the texture unit instead of a 4-tap manual
|
|
20
|
+
// bilinear.
|
|
21
|
+
.addTexture("tSkyLutTransmittance", "float")
|
|
22
|
+
.addSampler("sSkyLut", "filtering", SAMPLER_SKY_LUT)
|
|
23
|
+
.addStorageTexture("tSkyLutMultiscatterOut", "rgba16float")
|
|
24
|
+
;
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* the multiple-scattering LUT. Each pixel coordinate corresponds to a height and sun zenith angle, and
|
|
29
|
+
* the value is the multiple scattering approximation (Psi_ms from the paper, Eq. 10).
|
|
30
|
+
*
|
|
31
|
+
* One workgroup per LUT texel, one thread per direction (64 threads per workgroup).
|
|
32
|
+
* The 64 directions used to be a serial loop
|
|
33
|
+
* inside a fragment shader, which left the whole pass with 32*32 = 1024 threads of
|
|
34
|
+
* parallelism -- a few dozen waves, one per scheduler at best, with nothing to hide the
|
|
35
|
+
* latency of the transmittance fetches. Per-thread it is now a single direction's 20-step
|
|
36
|
+
* march.
|
|
37
|
+
*
|
|
38
|
+
* The per-direction results are summed with `subgroupAdd` and then across subgroups through
|
|
39
|
+
* workgroup memory, collapsing a six-step groupshared log-reduction into one subgroup
|
|
40
|
+
* instruction plus a handful of partials.
|
|
41
|
+
*
|
|
42
|
+
* @see "A Scalable and Production Ready Sky and Atmosphere Rendering Technique", Hillaire (2020)
|
|
43
|
+
* @see https://www.shadertoy.com/view/slSXRW
|
|
44
|
+
* @type {CodeChunk}
|
|
45
|
+
*/
|
|
46
|
+
const body = CodeChunk.from(
|
|
47
|
+
//language=WGSL
|
|
48
|
+
`
|
|
49
|
+
const MULTISCATTER_DIRECTION_COUNT = ${MULTISCATTER_LUT_DIRECTION_COUNT}u;
|
|
50
|
+
const MULTISCATTER_MAX_SUBGROUP_PARTIALS = ${MULTISCATTER_LUT_MAX_SUBGROUP_PARTIALS}u;
|
|
51
|
+
|
|
52
|
+
var<workgroup> wg_partial_count: atomic<u32>;
|
|
53
|
+
var<workgroup> wg_lum: array<vec3<f32>, MULTISCATTER_MAX_SUBGROUP_PARTIALS>;
|
|
54
|
+
var<workgroup> wg_fms: array<vec3<f32>, MULTISCATTER_MAX_SUBGROUP_PARTIALS>;
|
|
55
|
+
|
|
56
|
+
@compute @workgroup_size(${MULTISCATTER_LUT_DIRECTION_COUNT}, 1, 1)
|
|
57
|
+
fn main(
|
|
58
|
+
@builtin(workgroup_id) workgroup_id: vec3<u32>,
|
|
59
|
+
@builtin(local_invocation_index) thread_index: u32,
|
|
60
|
+
) {
|
|
61
|
+
|
|
62
|
+
if (thread_index == 0u) {
|
|
63
|
+
atomicStore(&wg_partial_count, 0u);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Every thread is here together anyway, so the counter's initialisation costs nothing
|
|
67
|
+
// beyond the barrier itself. WGSL does not promise workgroup variables start zeroed.
|
|
68
|
+
workgroupBarrier();
|
|
69
|
+
|
|
70
|
+
// one workgroup per texel; the dispatch is sized from the texture, so this is in range
|
|
71
|
+
let texel = workgroup_id.xy;
|
|
72
|
+
|
|
73
|
+
let lut_size = vec2<f32>(textureDimensions(tSkyLutMultiscatterOut));
|
|
74
|
+
|
|
75
|
+
// The point of each range this texel stands for: texel 0 carries the bottom and the last
|
|
76
|
+
// texel the top, which is what lets a lookup at either end read a value computed there
|
|
77
|
+
// rather than one from half a texel inside. sky_lut_uv is the other half of this.
|
|
78
|
+
let unit = sky_lut_texel_to_unit(vec2<f32>(texel), lut_size);
|
|
79
|
+
|
|
80
|
+
let sunCosTheta = 2.0*unit.x - 1.0;
|
|
81
|
+
let sunTheta = safe_acos(sunCosTheta);
|
|
82
|
+
|
|
83
|
+
let height = ATMOSPHERE_HEIGHT*unit.y;
|
|
84
|
+
|
|
85
|
+
let pos = vec3(0.0, height, 0.0);
|
|
86
|
+
let sunDir = normalize(vec3(0.0, sunCosTheta, -sin(sunTheta)));
|
|
87
|
+
|
|
88
|
+
// pos on the +y axis and sunDir with a zero x component are exactly the preconditions
|
|
89
|
+
// multiscatter_sample_direction's half-azimuth sample set needs
|
|
90
|
+
let rayDir = multiscatter_sample_direction(thread_index);
|
|
91
|
+
|
|
92
|
+
var lum:vec3<f32>;
|
|
93
|
+
var f_ms:vec3<f32>;
|
|
94
|
+
|
|
95
|
+
get_multiscatter_values(pos, sunDir, rayDir, &lum, &f_ms);
|
|
96
|
+
|
|
97
|
+
// Uniform control flow up to here, so every one of the workgroup's threads is an active
|
|
98
|
+
// lane and the subgroup sum covers all of them.
|
|
99
|
+
let lum_subgroup = subgroupAdd(lum);
|
|
100
|
+
let fms_subgroup = subgroupAdd(f_ms);
|
|
101
|
+
|
|
102
|
+
// subgroupElect picks exactly one active invocation per subgroup, and the slot it claims
|
|
103
|
+
// is whichever the counter hands out. Deriving the slot from local_invocation_index /
|
|
104
|
+
// subgroup_size instead would assume invocations are packed into subgroups in contiguous
|
|
105
|
+
// index order, which WGSL leaves unspecified: a mapping that is not contiguous blocks
|
|
106
|
+
// would collide two subgroups onto one slot and silently drop a partial sum. Which slot
|
|
107
|
+
// a subgroup lands in does not matter, only that it gets its own.
|
|
108
|
+
//
|
|
109
|
+
// Every lane holds the same subgroup sum, so letting them all store it would be a data
|
|
110
|
+
// race on one address even though the values agree.
|
|
111
|
+
if (subgroupElect()) {
|
|
112
|
+
let slot = atomicAdd(&wg_partial_count, 1u);
|
|
113
|
+
|
|
114
|
+
wg_lum[slot] = lum_subgroup;
|
|
115
|
+
wg_fms[slot] = fms_subgroup;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
workgroupBarrier();
|
|
119
|
+
|
|
120
|
+
if (thread_index != 0u) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// WGSL pins the subgroup size to a power of two in [4, 128], so the workgroup cannot hold
|
|
125
|
+
// more subgroups than the partials array has room for. The clamp keeps a driver that
|
|
126
|
+
// broke that promise reading initialised slots rather than garbage.
|
|
127
|
+
let partial_count = min(atomicLoad(&wg_partial_count), MULTISCATTER_MAX_SUBGROUP_PARTIALS);
|
|
128
|
+
|
|
129
|
+
var lum_total = vec3(0.0);
|
|
130
|
+
var fms_total = vec3(0.0);
|
|
131
|
+
|
|
132
|
+
for (var i = 0u; i < partial_count; i++) {
|
|
133
|
+
lum_total += wg_lum[i];
|
|
134
|
+
fms_total += wg_fms[i];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// The directions carry equal solid angle, so the mean over them is the spherical average
|
|
138
|
+
// the paper's uniform phase reduces to.
|
|
139
|
+
let inv_samples = 1.0 / f32(MULTISCATTER_DIRECTION_COUNT);
|
|
140
|
+
|
|
141
|
+
lum_total *= inv_samples;
|
|
142
|
+
fms_total *= inv_samples;
|
|
143
|
+
|
|
144
|
+
// Equation 10 from the paper.
|
|
145
|
+
let psi = lum_total / (1.0 - fms_total);
|
|
146
|
+
|
|
147
|
+
textureStore(tSkyLutMultiscatterOut, texel, vec4(psi, 1.0));
|
|
148
|
+
}
|
|
149
|
+
`, [
|
|
150
|
+
chunk_safe_acos,
|
|
151
|
+
ATMOSPHERE_HEIGHT_DECLARATION,
|
|
152
|
+
chunk_multiscatter_sample_direction,
|
|
153
|
+
chunk_sky_lut_texel_to_unit,
|
|
154
|
+
chunk_get_multiscatter_values,
|
|
155
|
+
]
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
body.addExtension(WebGPUExtensionType.Subgroups);
|
|
159
|
+
|
|
160
|
+
export const shader_multiscatter_lut = ComputeShader.from({
|
|
161
|
+
label: "Sky / multi-scatter LUT",
|
|
162
|
+
body,
|
|
163
|
+
resources,
|
|
164
|
+
});
|
|
@@ -116,7 +116,7 @@ fn raymarch_scattering(
|
|
|
116
116
|
let mie_absorption = mie_density * C_MIE_ABSORPTION;
|
|
117
117
|
let mie_scattering = mie_density * C_MIE_SCATTERING;
|
|
118
118
|
|
|
119
|
-
//
|
|
119
|
+
// Rayleigh does not absorb
|
|
120
120
|
let rayleigh_absorption = 0.0;
|
|
121
121
|
let rayleigh_scattering = local_density.x * C_RAYLEIGH;
|
|
122
122
|
|
|
@@ -17,8 +17,8 @@ export const MESH_SDF_BAKE_BUDGET_MAX: number;
|
|
|
17
17
|
* {@link alias} points a skinned clone's id at its source's cache, which readers follow.
|
|
18
18
|
*
|
|
19
19
|
* **Side.** A holder says whether it draws both sides of the geometry. A field is baked two-sided
|
|
20
|
-
* while any of its holders does: its vote then counts no back face, so nothing is inside it
|
|
21
|
-
*
|
|
20
|
+
* while any of its holders does: its vote then counts no back face, so nothing is inside it.
|
|
21
|
+
* A field whose holders' side has changed since its
|
|
22
22
|
* bake is baked again at the next bake, so holds moved within a frame bake nothing; a field no one
|
|
23
23
|
* holds keeps the side it has.
|
|
24
24
|
*
|
|
@@ -207,8 +207,8 @@ function grow_typed(array, length) {
|
|
|
207
207
|
* {@link alias} points a skinned clone's id at its source's cache, which readers follow.
|
|
208
208
|
*
|
|
209
209
|
* **Side.** A holder says whether it draws both sides of the geometry. A field is baked two-sided
|
|
210
|
-
* while any of its holders does: its vote then counts no back face, so nothing is inside it
|
|
211
|
-
*
|
|
210
|
+
* while any of its holders does: its vote then counts no back face, so nothing is inside it.
|
|
211
|
+
* A field whose holders' side has changed since its
|
|
212
212
|
* bake is baked again at the next bake, so holds moved within a frame bake nothing; a field no one
|
|
213
213
|
* holds keeps the side it has.
|
|
214
214
|
*
|
|
@@ -216,8 +216,8 @@ const vertex_code = ShaderDescriptor.from({
|
|
|
216
216
|
|
|
217
217
|
/*
|
|
218
218
|
The template is handed what the G-buffer pass hands it, in the geometry's local space, the card
|
|
219
|
-
being there: real derivatives, as this is a raster with neighbours of its own triangle, unbiased
|
|
220
|
-
|
|
219
|
+
being there: real derivatives, as this is a raster with neighbours of its own triangle, unbiased (mip
|
|
220
|
+
bias at 0). Both functions run first, in uniform control
|
|
221
221
|
flow, so a template may sample with implicit derivatives.
|
|
222
222
|
|
|
223
223
|
Coverage is drawn as the trace draws it, a texel's surface opaque with probability its opacity, from
|
|
@@ -7,7 +7,7 @@ export const MESH_CARDS_HISTOGRAM_SETTINGS: WebGPUStruct;
|
|
|
7
7
|
* six directions, over a resident geometry's level-0 occupancy — a brick is occupied when its entry
|
|
8
8
|
* holds a slot. Walking its column along the direction, a thread finds every run start: an occupied
|
|
9
9
|
* brick at layer z whose predecessor is empty or outside the grid. A run start's m is the layer after
|
|
10
|
-
* the previous run's end, or 0 for the first
|
|
10
|
+
* the previous run's end, or 0 for the first. The thread counts each run start into
|
|
11
11
|
* its direction's histogram by (m, z), which the layout's scratch holds cleared.
|
|
12
12
|
*
|
|
13
13
|
* @type {ComputeShader}
|
|
@@ -31,7 +31,7 @@ resources.createGroup()
|
|
|
31
31
|
* six directions, over a resident geometry's level-0 occupancy — a brick is occupied when its entry
|
|
32
32
|
* holds a slot. Walking its column along the direction, a thread finds every run start: an occupied
|
|
33
33
|
* brick at layer z whose predecessor is empty or outside the grid. A run start's m is the layer after
|
|
34
|
-
* the previous run's end, or 0 for the first
|
|
34
|
+
* the previous run's end, or 0 for the first. The thread counts each run start into
|
|
35
35
|
* its direction's histogram by (m, z), which the layout's scratch holds cleared.
|
|
36
36
|
*
|
|
37
37
|
* @type {ComputeShader}
|
|
@@ -10,8 +10,7 @@ export const BLAS_BAND_VOTE_STRATA: number;
|
|
|
10
10
|
*/
|
|
11
11
|
export const BLAS_BAND_VOTE_RAYS: number;
|
|
12
12
|
/**
|
|
13
|
-
* A geometry's signed distance within a band, signed by
|
|
14
|
-
* `FMeshDistanceFieldAsyncTask::DoWork`):
|
|
13
|
+
* A geometry's signed distance within a band, signed by a hemisphere ray vote:
|
|
15
14
|
*
|
|
16
15
|
* - The nearest point within the band, through the BLAS. With none, the point is a band away, outside,
|
|
17
16
|
* and casts no ray.
|
|
@@ -20,9 +19,9 @@ export const BLAS_BAND_VOTE_RAYS: number;
|
|
|
20
19
|
* than a quarter of them meet a back face.
|
|
21
20
|
* - A two-sided geometry has no back face: it is outside throughout, and casts no ray either.
|
|
22
21
|
*
|
|
23
|
-
* The directions are
|
|
24
|
-
*
|
|
25
|
-
* hemisphere's
|
|
22
|
+
* The directions are made as the LCG stream runs, ray after ray: a seed of 0 drives two
|
|
23
|
+
* 49-sample stratified uniform hemisphere sets on Shirley and Chiu's concentric map, and the second
|
|
24
|
+
* hemisphere's pole is negated (+Y and -Y hemispheres).
|
|
26
25
|
*
|
|
27
26
|
* ```wgsl
|
|
28
27
|
* fn blas_query_band_sdf(point: vec3<f32>, geometry_index: u32, band: f32, two_sided: bool, contact, stack, stack_top: u32) -> f32
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk_blas_query_band_sdf.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.js"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,oCAFU,MAAM,CAEuB;AAEvC;;;GAGG;AACH,kCAFU,MAAM,CAEqE;AAErF
|
|
1
|
+
{"version":3,"file":"chunk_blas_query_band_sdf.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/geometry/sdf/chunk_blas_query_band_sdf.js"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,oCAFU,MAAM,CAEuB;AAEvC;;;GAGG;AACH,kCAFU,MAAM,CAEqE;AAErF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wCAFU,SAAS,CAgHjB;0BAjJwB,oCAAoC"}
|
|
@@ -28,8 +28,7 @@ export const BLAS_BAND_VOTE_STRATA = 7;
|
|
|
28
28
|
export const BLAS_BAND_VOTE_RAYS = 2 * BLAS_BAND_VOTE_STRATA * BLAS_BAND_VOTE_STRATA;
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* A geometry's signed distance within a band, signed by
|
|
32
|
-
* `FMeshDistanceFieldAsyncTask::DoWork`):
|
|
31
|
+
* A geometry's signed distance within a band, signed by a hemisphere ray vote:
|
|
33
32
|
*
|
|
34
33
|
* - The nearest point within the band, through the BLAS. With none, the point is a band away, outside,
|
|
35
34
|
* and casts no ray.
|
|
@@ -38,9 +37,9 @@ export const BLAS_BAND_VOTE_RAYS = 2 * BLAS_BAND_VOTE_STRATA * BLAS_BAND_VOTE_ST
|
|
|
38
37
|
* than a quarter of them meet a back face.
|
|
39
38
|
* - A two-sided geometry has no back face: it is outside throughout, and casts no ray either.
|
|
40
39
|
*
|
|
41
|
-
* The directions are
|
|
42
|
-
*
|
|
43
|
-
* hemisphere's
|
|
40
|
+
* The directions are made as the LCG stream runs, ray after ray: a seed of 0 drives two
|
|
41
|
+
* 49-sample stratified uniform hemisphere sets on Shirley and Chiu's concentric map, and the second
|
|
42
|
+
* hemisphere's pole is negated (+Y and -Y hemispheres).
|
|
44
43
|
*
|
|
45
44
|
* ```wgsl
|
|
46
45
|
* fn blas_query_band_sdf(point: vec3<f32>, geometry_index: u32, band: f32, two_sided: bool, contact, stack, stack_top: u32) -> f32
|
|
@@ -55,7 +54,7 @@ const BLAS_BAND_VOTE_STRATA = ${BLAS_BAND_VOTE_STRATA}u;
|
|
|
55
54
|
const BLAS_BAND_VOTE_HEMISPHERE = ${BLAS_BAND_VOTE_STRATA * BLAS_BAND_VOTE_STRATA}u;
|
|
56
55
|
const BLAS_BAND_VOTE_RAYS = ${BLAS_BAND_VOTE_RAYS}u;
|
|
57
56
|
|
|
58
|
-
/**
|
|
57
|
+
/** Next LCG fraction in [0, 1) */
|
|
59
58
|
fn blas_band_vote_fraction(seed: ptr<function, u32>) -> f32 {
|
|
60
59
|
*seed = *seed * 196314165u + 907633515u;
|
|
61
60
|
|
|
@@ -145,7 +144,7 @@ fn blas_query_band_sdf(
|
|
|
145
144
|
}
|
|
146
145
|
}
|
|
147
146
|
|
|
148
|
-
//
|
|
147
|
+
// Inside when hits > 0 and back-face hits > 0.25 · samples (the first follows from the second)
|
|
149
148
|
return select(distance, -distance, 4u * back > BLAS_BAND_VOTE_RAYS);
|
|
150
149
|
}
|
|
151
150
|
`, [
|
|
@@ -128,7 +128,7 @@ The pin was then added on top to protect cut seams. The pin is *correct* and mus
|
|
|
128
128
|
Generalized quadrics — Garland & Heckbert 1998 (*Simplifying Surfaces with Color and Texture using
|
|
129
129
|
Quadric Error Metrics*) for the naive `(3+m)`-dimensional lift, **Hoppe 1999** (*New Quadric Metric
|
|
130
130
|
for Simplifying Meshes with Appearance Attributes*) for the form worth implementing. Unreal's Nanite
|
|
131
|
-
uses the latter (
|
|
131
|
+
uses the latter (attribute-carrying quadrics, per-attribute weights,
|
|
132
132
|
and a separate edge quadric for boundary and seam penalties); `meshoptimizer`'s
|
|
133
133
|
`meshopt_simplifyWithAttributes` is a far more readable second reference for the same maths and for
|
|
134
134
|
weight calibration.
|
|
@@ -179,10 +179,8 @@ band (`vgeo_assemble_pages`). A page is therefore spatially local, and a boundin
|
|
|
179
179
|
one means something. Pack pages arbitrarily and every page bound covers the model.
|
|
180
180
|
|
|
181
181
|
**Nanite does exactly this combination**, which settles the compatibility question outright.
|
|
182
|
-
Cluster data lives in a paged, streamed virtual byte buffer
|
|
183
|
-
|
|
184
|
-
`Nanite.StreamingManager.Hierarchy`; nodes form a BVH within a mesh connecting clusters
|
|
185
|
-
across detail levels; `PersistentNodeAndClusterCull` in `NaniteHierarchyTraversal.ush` walks
|
|
182
|
+
Cluster data lives in a paged, streamed virtual byte buffer with a separate hierarchy;
|
|
183
|
+
nodes form a BVH within a mesh connecting clusters across detail levels; a persistent traversal kernel walks
|
|
186
184
|
it on the GPU from an MPMC queue, where only nodes generate new work and clusters are only
|
|
187
185
|
consumed. And when a child's memory is not present, **processing stops at the parent and a
|
|
188
186
|
request is made for the child** — a lower-detail LOD is what you see until it arrives. That
|
|
@@ -207,7 +207,7 @@ With wedges, the same, once per wedge — plus the one new decision:
|
|
|
207
207
|
> wedge count does.
|
|
208
208
|
|
|
209
209
|
Attribute equality, within a tolerance. Two wedges that describe the same appearance are one wedge;
|
|
210
|
-
two that do not stay two. This is Nanite's rule (
|
|
210
|
+
two that do not stay two. This is Nanite's rule (matching corners by attribute
|
|
211
211
|
equality on a collapse) and it has the properties that matter:
|
|
212
212
|
|
|
213
213
|
- On a smooth mesh every wedge at a vertex is equal to every other, so there is exactly one, and the
|
|
@@ -185,8 +185,7 @@ Revision 2 made τ an absolute per-view value. That splits the one quality lever
|
|
|
185
185
|
slider sets `runtime.tau`, and an absolute shadow τ of 2 becomes *finer* than the main view the moment
|
|
186
186
|
the slider goes to 4 — and the reference it cited is relative. So a view carries **`tau_scale`**,
|
|
187
187
|
default 1, and cuts at `runtime.tau × tau_scale`. Whoever owns a view may set it; nothing in the runtime
|
|
188
|
-
knows what kind of view it is.
|
|
189
|
-
data point for shadow views; S4 measures before anything but 1 is set.
|
|
188
|
+
knows what kind of view it is. S4 measures before anything but 1 is set.
|
|
190
189
|
|
|
191
190
|
**Shadow views default to 2** *(after S4)*: the shadow context sets it on every view it owns
|
|
192
191
|
(`SHADOWMAP_VGEO_TAU_SCALE`), and the runtime still knows nothing of what kind of view it cuts for.
|
|
@@ -235,8 +234,7 @@ re-selects it. Its first draw is forced at creation, when little but the roots i
|
|
|
235
234
|
redraws it touches nothing, so the LRU evicts exactly the pages only it needs. Left alone it would keep
|
|
236
235
|
a root-level cut indefinitely. So a map whose own views' last reading was **clamped**, and under which
|
|
237
236
|
pages have installed since, is re-selected like an invalid one. That keys on the map's own incomplete
|
|
238
|
-
cut rather than on every LOD change, which
|
|
239
|
-
`r.Nanite.VSMInvalidateOnLODDelta` warns about.
|
|
237
|
+
cut rather than on every LOD change, which keeps it clear of an invalidation storm when pages stream in.
|
|
240
238
|
|
|
241
239
|
### 2.6 Room for proxies — not built
|
|
242
240
|
|
|
@@ -511,16 +509,11 @@ in turn. That flickers 0.17% of the screen per frame in the authored view and 0.
|
|
|
511
509
|
|
|
512
510
|
## References
|
|
513
511
|
|
|
514
|
-
Read 2026-09-28.
|
|
515
|
-
from a UE 5.4.4 console-variable reference that reproduces source locations.
|
|
512
|
+
Read 2026-09-28.
|
|
516
513
|
|
|
517
514
|
- Epic, *Virtual Shadow Maps in Unreal Engine* — per-view Nanite rendering, one pass per light
|
|
518
515
|
class, 17 directional clipmap levels, page caching and invalidation.
|
|
519
516
|
https://dev.epicgames.com/documentation/en-us/unreal-engine/virtual-shadow-maps-in-unreal-engine
|
|
520
|
-
- `r.Shadow.NaniteLODBias`, default 1, scale 2^−bias (ShadowSceneRenderer.cpp:50, :103 in 5.4.4).
|
|
521
|
-
https://indxzero.github.io/ue544cvarwiki/articles/r.shadow.nanitelodbias/
|
|
522
|
-
- `r.Nanite.VSMInvalidateOnLODDelta`, default 0, experimental (NaniteCullRaster.cpp:117).
|
|
523
|
-
https://indxzero.github.io/ue544cvarwiki/articles/r.nanite.vsminvalidateonloddelta/
|
|
524
517
|
- Epic, *Hardware Ray Tracing* — ray-traced shadows trace the Nanite fallback mesh.
|
|
525
518
|
https://dev.epicgames.com/documentation/en-us/unreal-engine/hardware-ray-tracing-in-unreal-engine
|
|
526
519
|
- Bevy, `crates/bevy_pbr/src/meshlet/cull_shared.wesl` (`lod_error_is_imperceptible`) and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GPUProbeClipmapGI.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js"],"names":[],"mappings":"AAeA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IA0DI;;OAEG;IACH,sBAFW,eAAe,EAMzB;IAED;;OAEG;IACH,qCAEC;IAED;;OAEG;IACH,qCAEC;IAED;;OAEG;IACH,oCAEC;IAED;;;;;;;;;;;;;;OAcG;IACH;QAT+B,KAAK,EAAzB,UAAU;QACc,IAAI,EAA5B,cAAc;QACgB,QAAQ,EAAtC,oBAAoB;QACJ,KAAK,EAArB,MAAM;QACU,MAAM,EAAtB,MAAM;QACK,IAAI;QACE,MAAM,GAAvB,MAAM;
|
|
1
|
+
{"version":3,"file":"GPUProbeClipmapGI.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js"],"names":[],"mappings":"AAeA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IA0DI;;OAEG;IACH,sBAFW,eAAe,EAMzB;IAED;;OAEG;IACH,qCAEC;IAED;;OAEG;IACH,qCAEC;IAED;;OAEG;IACH,oCAEC;IAED;;;;;;;;;;;;;;OAcG;IACH;QAT+B,KAAK,EAAzB,UAAU;QACc,IAAI,EAA5B,cAAc;QACgB,QAAQ,EAAtC,oBAAoB;QACJ,KAAK,EAArB,MAAM;QACU,MAAM,EAAtB,MAAM;QACK,IAAI;QACE,MAAM,GAAvB,MAAM;aAkGhB;IAED;;;OAGG;IACH,0BAEC;IAED;;;;;;;;;OASG;IACH,4CAUC;IAwDD;;;;;;;;;;OAUG;IACH;QAN+B,KAAK,EAAzB,UAAU;QACc,IAAI,EAA5B,cAAc;QACgB,QAAQ,EAAtC,oBAAoB;QACF,UAAU,EAA5B,MAAM,EAAE;QACN,MAAM,CAmBlB;IAED;;;;;OAKG;IACH,uBAFW,aAAa,QASvB;IAED;;;OAGG;IACH,0BAHW,aAAa,GACX,OAAO,CAanB;IAyCD;;;OAGG;IACH,gBAoBC;IAED,gBAcC;;CACJ;yBArcY,OAAO,8DAA8D,EAAE,UAAU;8BACjF,OAAO,0BAA0B,EAAE,eAAe;6BAClD,OAAO,8BAA8B,EAAE,cAAc;mCACrD,OAAO,2BAA2B,EAAE,oBAAoB;4BACxD,OAAO,4BAA4B,EAAE,aAAa;gCAjB/B,4BAA4B;gCAQ5B,4BAA4B;uCAErB,6BAA6B"}
|