@woosh/meep-engine 3.53.0 → 3.54.0
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/package.json +1 -1
- package/src/core/math/noise/worley_noise_2d.d.ts +14 -0
- package/src/core/math/noise/worley_noise_2d.d.ts.map +1 -0
- package/src/core/math/noise/worley_noise_2d.js +74 -0
- package/src/engine/graphics/texture/atlas/CachingTextureAtlas.d.ts +6 -1
- package/src/engine/graphics/texture/atlas/CachingTextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/CachingTextureAtlas.js +363 -325
- package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.d.ts +93 -14
- package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.js +322 -183
- package/src/engine/graphics/texture/atlas/ReferencedTextureAtlas.d.ts +9 -0
- package/src/engine/graphics/texture/atlas/ReferencedTextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +110 -83
- package/src/engine/graphics/texture/atlas/SpriteAtlas.d.ts +42 -0
- package/src/engine/graphics/texture/atlas/SpriteAtlas.d.ts.map +1 -0
- package/src/engine/{graphics3/decal/DecalAtlas.js → graphics/texture/atlas/SpriteAtlas.js} +202 -194
- package/src/engine/graphics/texture/atlas/SpriteAtlasFill.d.ts +12 -0
- package/src/engine/graphics/texture/atlas/SpriteAtlasFill.d.ts.map +1 -0
- package/src/engine/graphics/texture/atlas/SpriteAtlasFill.js +30 -0
- package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts +7 -0
- package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/TextureAtlas.js +11 -1
- package/src/engine/graphics/texture/atlas/sprite_atlas_border.d.ts +52 -0
- package/src/engine/graphics/texture/atlas/sprite_atlas_border.d.ts.map +1 -0
- package/src/engine/{graphics3/decal/decal_atlas_border.js → graphics/texture/atlas/sprite_atlas_border.js} +69 -69
- package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
- package/src/engine/graphics3/DecalSystem.js +447 -450
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +9 -22
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/GPUParticleEmitterSystem.js +892 -951
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/generation/foliage/FOLIAGE_DESIGN.md +2 -1
- package/src/generation/foliage/config/BarkMaterialConfig.d.ts +4 -3
- package/src/generation/foliage/config/BarkMaterialConfig.d.ts.map +1 -1
- package/src/generation/foliage/config/BarkMaterialConfig.js +6 -6
- package/src/generation/foliage/config/FoliageBarkType.d.ts +11 -0
- package/src/generation/foliage/config/FoliageBarkType.d.ts.map +1 -0
- package/src/generation/foliage/config/FoliageBarkType.js +16 -0
- package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +58 -5
- package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -1
- package/src/generation/foliage/config/FoliageMaterialConfig.js +279 -181
- package/src/generation/foliage/index.d.ts +2 -1
- package/src/generation/foliage/index.js +44 -43
- package/src/generation/foliage/material/make_bark_material.d.ts.map +1 -1
- package/src/generation/foliage/material/make_bark_material.js +23 -95
- package/src/generation/foliage/material/make_foliage_material.d.ts +29 -3
- package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -1
- package/src/generation/foliage/material/make_foliage_material.js +605 -359
- package/src/generation/foliage/mesh/branch_collar_project.d.ts.map +1 -1
- package/src/generation/foliage/mesh/branch_collar_project.js +205 -203
- package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +15 -0
- package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -1
- package/src/generation/foliage/mesh/foliage_collect_attachments.js +569 -502
- package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1049 -1047
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +2 -1
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +454 -415
- package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
- package/src/generation/foliage/presets/make_tree_species_preset.js +870 -837
- package/src/generation/foliage/skeleton/crown_envelope_evaluate.js +121 -121
- package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts +10 -7
- package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js +206 -179
- package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/tree_skeleton_grow.js +1871 -1104
- package/src/shade/playground/foliage_wind/foliage_world.d.ts +6 -0
- package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
- package/src/shade/playground/foliage_wind/foliage_world.js +602 -593
- package/src/shade/playground/foliage_wind/index.html +260 -254
- package/src/shade/playground/foliage_wind/main.js +275 -263
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
- package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +1 -1
- package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +3 -3
- package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
- package/src/shade/renderer/hiz/HierarchicalZBuffer.js +350 -294
- package/src/shade/renderer/hiz/generate_downsampler_code.d.ts +0 -2
- package/src/shade/renderer/hiz/generate_downsampler_code.d.ts.map +1 -1
- package/src/shade/renderer/hiz/generate_downsampler_code.js +99 -100
- package/src/shade/renderer/hiz/hzb_pick_alignment.d.ts +15 -0
- package/src/shade/renderer/hiz/hzb_pick_alignment.d.ts.map +1 -0
- package/src/shade/renderer/hiz/hzb_pick_alignment.js +148 -0
- package/src/shade/renderer/hiz/hzb_plan_reduction_steps.d.ts +28 -0
- package/src/shade/renderer/hiz/hzb_plan_reduction_steps.d.ts.map +1 -0
- package/src/shade/renderer/hiz/hzb_plan_reduction_steps.js +58 -0
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +5 -5
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +57 -67
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +3 -3
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +1 -1
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.js +111 -112
- package/src/shade/renderer/hiz/shader_hzb_spd.d.ts +5 -0
- package/src/shade/renderer/hiz/shader_hzb_spd.d.ts.map +1 -0
- package/src/shade/renderer/hiz/shader_hzb_spd.js +160 -0
- package/src/shade/renderer/light/GPULightCollection.d.ts +8 -0
- package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
- package/src/shade/renderer/light/GPULightCollection.js +67 -0
- package/src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.d.ts +7 -0
- package/src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.js +13 -0
- package/src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.d.ts +10 -0
- package/src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.js +72 -0
- package/src/shade/renderer/light/world_cluster/WORLD_LIGHT_CLUSTER.d.ts +39 -0
- package/src/shade/renderer/light/world_cluster/WORLD_LIGHT_CLUSTER.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/WORLD_LIGHT_CLUSTER.js +90 -0
- package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.d.ts +12 -0
- package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.js +56 -0
- package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.d.ts +31 -0
- package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.js +196 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.d.ts +10 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.js +163 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_cull_lights.d.ts +4 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_cull_lights.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_cull_lights.js +137 -0
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +4 -3
- package/src/shade/renderer/particles/graph_particles_avboit.d.ts +4 -3
- package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles_avboit.js +28 -11
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +9 -13
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +25 -20
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +21 -38
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/shader/chunk/depth/chunk_query_depth_from_screen_space_bb.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/depth/chunk_query_depth_from_screen_space_bb.js +62 -62
- package/src/shade/renderer/shader/chunk/random/lowbias/chunk_hash_lowbias32_vec2u.d.ts +6 -0
- package/src/shade/renderer/shader/chunk/random/lowbias/chunk_hash_lowbias32_vec2u.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/random/lowbias/chunk_hash_lowbias32_vec2u.js +19 -0
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_get_mip_resolution.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_get_mip_resolution.js +16 -10
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_hierarchical_raymarch.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_hierarchical_raymarch.js +118 -117
- package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts +41 -7
- package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts.map +1 -1
- package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.js +162 -58
- package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.js +1 -1
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +10 -12
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +583 -606
- package/src/shade/renderer/volumetrics/chunk_volumetrics_froxel_sample.d.ts +24 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_froxel_sample.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi_sample.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +640 -640
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts +113 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.js +484 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.d.ts +50 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.js +60 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP_STRUCT.d.ts +25 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP_STRUCT.js +47 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IrradianceCascadePlacement.d.ts +74 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IrradianceCascadePlacement.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IrradianceCascadePlacement.js +173 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts +26 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.js +83 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_local_light.d.ts +31 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_local_light.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_local_light.js +113 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_sample.d.ts +121 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_sample.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_sample.js +356 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.d.ts +16 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.js +191 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_classify_froxels.d.ts +16 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_classify_froxels.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_lighting_regimes.d.ts +23 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_lighting_regimes.d.ts.map +1 -0
- package/src/shade/renderer/wind/GPUSceneWind.d.ts +1 -1
- package/src/shade/renderer/wind/GPUSceneWind.js +1 -1
- package/src/engine/graphics3/decal/DecalAtlasFill.js +0 -32
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_froxel_centre_ws.js +0 -49
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.js +0 -50
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi_sample.js +0 -105
- package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.js +0 -80
- package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi.js +0 -51
- package/src/shade/renderer/volumetrics/gi/volumetrics_gi_resources.js +0 -39
- package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.js +0 -121
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.js +0 -237
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* World-space irradiance clipmap (`GPUIrradianceClipmap`):
|
|
3
|
+
*
|
|
4
|
+
* Replaces the camera-frustum froxel irradiance volume with nested world-space clipmap cascades
|
|
5
|
+
* stored in a multi-texture {@link GPUTileAtlas3D} (`Y` in texture 0, `CoCg` in texture 1).
|
|
6
|
+
*
|
|
7
|
+
* - **Defaults (Decision 6.3):** 6 cascades (`c = 0..5`) of `32 × 32 × 32` content cells (plus a
|
|
8
|
+
* 1-texel trilinear skirt -> `34³` texels per tile), with finest voxel size `h0 = 0.25 m`
|
|
9
|
+
* (covering `8 m, 16 m, 32 m, 64 m, 128 m, 256 m`).
|
|
10
|
+
* - **Amortized Updates & Warp Detection (Decision 3.2):** Cascade `0` and the dyadic ruler cascade
|
|
11
|
+
* `fluid_cascade_ruler(tick, count)` update every frame. In addition, whenever a cascade's window
|
|
12
|
+
* shifts by 1 voxel (`placement.moved(c)`), an immediate update is forced on that cascade so the
|
|
13
|
+
* linear atlas tile never holds stale pre-shift texels.
|
|
14
|
+
*/
|
|
15
|
+
export class GPUIrradianceClipmap {
|
|
16
|
+
/**
|
|
17
|
+
* @param {GPUDevice} device
|
|
18
|
+
* @param {Object} [options]
|
|
19
|
+
* @param {number} [options.cascade_count=IRRADIANCE_CLIPMAP_DEFAULT_CASCADE_COUNT]
|
|
20
|
+
* @param {number|ArrayLike<number>} [options.resolution=IRRADIANCE_CLIPMAP_DEFAULT_RESOLUTION]
|
|
21
|
+
* @param {number} [options.cell_size=IRRADIANCE_CLIPMAP_DEFAULT_CELL_SIZE]
|
|
22
|
+
* @param {number} [options.blend_skirt=IRRADIANCE_CLIPMAP_DEFAULT_BLEND_SKIRT]
|
|
23
|
+
*/
|
|
24
|
+
constructor(device: GPUDevice, { cascade_count, resolution, cell_size, blend_skirt, }?: {
|
|
25
|
+
cascade_count?: number;
|
|
26
|
+
resolution?: number | ArrayLike<number>;
|
|
27
|
+
cell_size?: number;
|
|
28
|
+
blend_skirt?: number;
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* @returns {GPUTileAtlas3D}
|
|
32
|
+
*/
|
|
33
|
+
get atlas(): GPUTileAtlas3D;
|
|
34
|
+
/**
|
|
35
|
+
* @returns {GPUTextureContext}
|
|
36
|
+
*/
|
|
37
|
+
get texture_y(): GPUTextureContext;
|
|
38
|
+
/**
|
|
39
|
+
* @returns {GPUTextureContext}
|
|
40
|
+
*/
|
|
41
|
+
get texture_cocg(): GPUTextureContext;
|
|
42
|
+
/**
|
|
43
|
+
* @returns {GPUBuffer}
|
|
44
|
+
*/
|
|
45
|
+
get uniform(): GPUBuffer;
|
|
46
|
+
/**
|
|
47
|
+
* @returns {number}
|
|
48
|
+
*/
|
|
49
|
+
get cascade_count(): number;
|
|
50
|
+
/**
|
|
51
|
+
* Number of voxels at each cascade window's outer faces where blending takes place.
|
|
52
|
+
* @returns {number}
|
|
53
|
+
*/
|
|
54
|
+
get blend_skirt(): number;
|
|
55
|
+
/**
|
|
56
|
+
* @returns {IrradianceCascadePlacement}
|
|
57
|
+
*/
|
|
58
|
+
get placement(): IrradianceCascadePlacement;
|
|
59
|
+
/**
|
|
60
|
+
* Forces all cascades to rebuild on the next executed frame.
|
|
61
|
+
*/
|
|
62
|
+
invalidate_all(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Updates cascade window placements around `anchor` (`[x, y, z]` in world metres), detects
|
|
65
|
+
* warp events (`placement.moved(c)`), schedules cascade updates, and uploads the uniform table.
|
|
66
|
+
*
|
|
67
|
+
* @param {number} x
|
|
68
|
+
* @param {number} y
|
|
69
|
+
* @param {number} z
|
|
70
|
+
* @param {ShaderSwitchSet} [shader_switches]
|
|
71
|
+
*/
|
|
72
|
+
update_placement(x: number, y: number, z: number, shader_switches?: ShaderSwitchSet): void;
|
|
73
|
+
/**
|
|
74
|
+
* Records the world-space light cluster clipmap build and the irradiance clipmap cascade update
|
|
75
|
+
* passes into `graph`.
|
|
76
|
+
*
|
|
77
|
+
* Neither pass is marked a side effect, so if nothing in the frame reads `Y` or `CoCg` (e.g. a
|
|
78
|
+
* frame with no volumetrics and no lit particles), the frame graph culls both passes and `#dirty`
|
|
79
|
+
* remains set until a frame actually executes them.
|
|
80
|
+
*
|
|
81
|
+
* @param {Object} options
|
|
82
|
+
* @param {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} options.graph
|
|
83
|
+
* @param {import("../../camera/GPUCameraContext.js").GPUCameraContext} options.camera
|
|
84
|
+
* @param {import("../../scene/GPUSceneContext.js").GPUSceneContext} options.scene_ctx
|
|
85
|
+
* @param {number} options.shadowmap_atlas
|
|
86
|
+
* @param {ShaderSwitchSet} [options.shader_switches]
|
|
87
|
+
* @param {import("../../global_illumination/brick4/Brick4LightMap.js").Brick4LightMap} [options.brick4]
|
|
88
|
+
* @param {import("../../global_illumination/lpv/GPULightProbeVolume.js").GPULightProbeVolume} [options.lpv]
|
|
89
|
+
* @returns {{Y: number, CoCg: number, uniform: number}}
|
|
90
|
+
*/
|
|
91
|
+
graph_update({ graph, camera, scene_ctx, shadowmap_atlas, shader_switches, brick4, lpv, }: {
|
|
92
|
+
graph: import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph;
|
|
93
|
+
camera: import("../../camera/GPUCameraContext.js").GPUCameraContext;
|
|
94
|
+
scene_ctx: import("../../scene/GPUSceneContext.js").GPUSceneContext;
|
|
95
|
+
shadowmap_atlas: number;
|
|
96
|
+
shader_switches?: ShaderSwitchSet;
|
|
97
|
+
brick4?: import("../../global_illumination/brick4/Brick4LightMap.js").Brick4LightMap;
|
|
98
|
+
lpv?: import("../../global_illumination/lpv/GPULightProbeVolume.js").GPULightProbeVolume;
|
|
99
|
+
}): {
|
|
100
|
+
Y: number;
|
|
101
|
+
CoCg: number;
|
|
102
|
+
uniform: number;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Releases GPU resources owned by the clipmap. Safe to call twice.
|
|
106
|
+
*/
|
|
107
|
+
destroy(): void;
|
|
108
|
+
#private;
|
|
109
|
+
}
|
|
110
|
+
import { GPUTileAtlas3D } from "../../texture/atlas/GPUTileAtlas3D.js";
|
|
111
|
+
import { IrradianceCascadePlacement } from "./IrradianceCascadePlacement.js";
|
|
112
|
+
import { ShaderSwitchSet } from "../../shader/compiler/ShaderSwitchSet.js";
|
|
113
|
+
//# sourceMappingURL=GPUIrradianceClipmap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GPUIrradianceClipmap.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.js"],"names":[],"mappings":"AA6CA;;;;;;;;;;;;;GAaG;AACH;IA2CI;;;;;;;OAOG;IACH;QAL4B,aAAa,GAA9B,MAAM;QAC6B,UAAU,GAA7C,MAAM,GAAC,UAAU,MAAM,CAAC;QACP,SAAS,GAA1B,MAAM;QACW,WAAW,GAA5B,MAAM;OA8DhB;IAED;;OAEG;IACH,4BAEC;IAED;;OAEG;IACH,mCAEC;IAED;;OAEG;IACH,sCAEC;IAED;;OAEG;IACH,yBAEC;IAED;;OAEG;IACH,4BAEC;IAED;;;OAGG;IACH,0BAEC;IAED;;OAEG;IACH,4CAEC;IAED;;OAEG;IACH,uBAEC;IAED;;;;;;;;OAQG;IACH,oBALW,MAAM,KACN,MAAM,KACN,MAAM,oBACN,eAAe,QAgFzB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH;QATsG,KAAK,EAAhG,OAAO,8DAA8D,EAAE,UAAU;QACZ,MAAM,EAA3E,OAAO,kCAAkC,EAAE,gBAAgB;QACO,SAAS,EAA3E,OAAO,gCAAgC,EAAE,eAAe;QACxC,eAAe,EAA/B,MAAM;QACoB,eAAe,GAAzC,eAAe;QACuE,MAAM,GAA5F,OAAO,oDAAoD,EAAE,cAAc;QACkB,GAAG,GAAhG,OAAO,sDAAsD,EAAE,mBAAmB;QAChF;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAuItD;IAED;;OAEG;IACH,gBAQC;;CACJ;+BAzd8B,uCAAuC;2CAe3B,iCAAiC;gCApB5C,0CAA0C"}
|
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { fluid_cascade_ruler } from "../../fluid/fluid_cascade_ruler.js";
|
|
3
|
+
import { INDIRECT_LIGHTING } from "../../INDIRECT_LIGHTING.js";
|
|
4
|
+
import { graph_build_world_light_clusters } from "../../light/world_cluster/graph_build_world_light_clusters.js";
|
|
5
|
+
import { CLIPMAP_LEVEL_STRUCT } from "../../shader/chunk/clipmap/CLIPMAP_LEVEL_STRUCT.js";
|
|
6
|
+
import { ShaderSwitchSet } from "../../shader/compiler/ShaderSwitchSet.js";
|
|
7
|
+
import { graph_import_buffer } from "../../shader/graph/graph_import_buffer.js";
|
|
8
|
+
import { graph_import_texture } from "../../shader/graph/graph_import_texture.js";
|
|
9
|
+
import { encoder_prepare_shader_bindings_defaults } from "../../shader/resource/encoder_prepare_shader_bindings_defaults.js";
|
|
10
|
+
import { SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR } from "../../shadow/map/SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR.js";
|
|
11
|
+
import { GPUTileAtlas3D } from "../../texture/atlas/GPUTileAtlas3D.js";
|
|
12
|
+
import { DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR } from "../../texture/DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR.js";
|
|
13
|
+
import {
|
|
14
|
+
IRRADIANCE_CLIPMAP_CASCADE_LIMIT,
|
|
15
|
+
IRRADIANCE_CLIPMAP_DEFAULT_BLEND_SKIRT,
|
|
16
|
+
IRRADIANCE_CLIPMAP_DEFAULT_CASCADE_COUNT,
|
|
17
|
+
IRRADIANCE_CLIPMAP_DEFAULT_CELL_SIZE,
|
|
18
|
+
IRRADIANCE_CLIPMAP_DEFAULT_RESOLUTION,
|
|
19
|
+
IRRADIANCE_CLIPMAP_TILE_BORDER,
|
|
20
|
+
IRRADIANCE_CLIPMAP_TILE_FORMAT,
|
|
21
|
+
} from "./IRRADIANCE_CLIPMAP.js";
|
|
22
|
+
import {
|
|
23
|
+
IRRADIANCE_CASCADE_STRUCT,
|
|
24
|
+
IRRADIANCE_CLIPMAP_STRUCT,
|
|
25
|
+
} from "./IRRADIANCE_CLIPMAP_STRUCT.js";
|
|
26
|
+
import { IrradianceCascadePlacement } from "./IrradianceCascadePlacement.js";
|
|
27
|
+
import {
|
|
28
|
+
IRRADIANCE_CLIPMAP_BUILD_STRUCT,
|
|
29
|
+
shader_irradiance_clipmap_build,
|
|
30
|
+
} from "./shader_irradiance_clipmap_build.js";
|
|
31
|
+
|
|
32
|
+
// Word offsets in IRRADIANCE_CLIPMAP_STRUCT
|
|
33
|
+
const LEVELS = IRRADIANCE_CLIPMAP_STRUCT.get("levels").offset >>> 2;
|
|
34
|
+
const LEVEL_STRIDE = CLIPMAP_LEVEL_STRUCT.aligned_size >>> 2;
|
|
35
|
+
const LEVEL_CORNER = CLIPMAP_LEVEL_STRUCT.get("corner").offset >>> 2;
|
|
36
|
+
const LEVEL_CELL_SIZE = CLIPMAP_LEVEL_STRUCT.get("cell_size").offset >>> 2;
|
|
37
|
+
const LEVEL_SIZE = CLIPMAP_LEVEL_STRUCT.get("size").offset >>> 2;
|
|
38
|
+
const CASCADES = IRRADIANCE_CLIPMAP_STRUCT.get("cascades").offset >>> 2;
|
|
39
|
+
const CASCADE_STRIDE = IRRADIANCE_CASCADE_STRUCT.aligned_size >>> 2;
|
|
40
|
+
const CASCADE_CONTENT_ORIGIN = IRRADIANCE_CASCADE_STRUCT.get("content_origin").offset >>> 2;
|
|
41
|
+
const INVERSE_ATLAS_SIZE = IRRADIANCE_CLIPMAP_STRUCT.get("inverse_atlas_size").offset >>> 2;
|
|
42
|
+
const CASCADE_COUNT = IRRADIANCE_CLIPMAP_STRUCT.get("cascade_count").offset >>> 2;
|
|
43
|
+
const ANCHOR = IRRADIANCE_CLIPMAP_STRUCT.get("anchor").offset >>> 2;
|
|
44
|
+
const BLEND_SKIRT = IRRADIANCE_CLIPMAP_STRUCT.get("blend_skirt").offset >>> 2;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* World-space irradiance clipmap (`GPUIrradianceClipmap`):
|
|
48
|
+
*
|
|
49
|
+
* Replaces the camera-frustum froxel irradiance volume with nested world-space clipmap cascades
|
|
50
|
+
* stored in a multi-texture {@link GPUTileAtlas3D} (`Y` in texture 0, `CoCg` in texture 1).
|
|
51
|
+
*
|
|
52
|
+
* - **Defaults (Decision 6.3):** 6 cascades (`c = 0..5`) of `32 × 32 × 32` content cells (plus a
|
|
53
|
+
* 1-texel trilinear skirt -> `34³` texels per tile), with finest voxel size `h0 = 0.25 m`
|
|
54
|
+
* (covering `8 m, 16 m, 32 m, 64 m, 128 m, 256 m`).
|
|
55
|
+
* - **Amortized Updates & Warp Detection (Decision 3.2):** Cascade `0` and the dyadic ruler cascade
|
|
56
|
+
* `fluid_cascade_ruler(tick, count)` update every frame. In addition, whenever a cascade's window
|
|
57
|
+
* shifts by 1 voxel (`placement.moved(c)`), an immediate update is forced on that cascade so the
|
|
58
|
+
* linear atlas tile never holds stale pre-shift texels.
|
|
59
|
+
*/
|
|
60
|
+
export class GPUIrradianceClipmap {
|
|
61
|
+
/** @type {GPUDevice} */
|
|
62
|
+
#device;
|
|
63
|
+
|
|
64
|
+
/** @type {GPUTileAtlas3D} */
|
|
65
|
+
#atlas;
|
|
66
|
+
|
|
67
|
+
/** @type {IrradianceCascadePlacement} */
|
|
68
|
+
#placement;
|
|
69
|
+
|
|
70
|
+
/** @type {GPUBuffer} */
|
|
71
|
+
#uniform;
|
|
72
|
+
|
|
73
|
+
/** @type {ArrayBuffer} */
|
|
74
|
+
#bytes = new ArrayBuffer(IRRADIANCE_CLIPMAP_STRUCT.size);
|
|
75
|
+
#f32 = new Float32Array(this.#bytes);
|
|
76
|
+
#i32 = new Int32Array(this.#bytes);
|
|
77
|
+
#u32 = new Uint32Array(this.#bytes);
|
|
78
|
+
|
|
79
|
+
/** @type {Uint32Array} */
|
|
80
|
+
#slots = new Uint32Array(IRRADIANCE_CLIPMAP_CASCADE_LIMIT);
|
|
81
|
+
|
|
82
|
+
/** @type {Uint8Array} */
|
|
83
|
+
#dirty = new Uint8Array(IRRADIANCE_CLIPMAP_CASCADE_LIMIT);
|
|
84
|
+
|
|
85
|
+
/** @type {Object[]} */
|
|
86
|
+
#build_records = [];
|
|
87
|
+
|
|
88
|
+
/** @type {number[]} */
|
|
89
|
+
#origin = [0, 0, 0];
|
|
90
|
+
|
|
91
|
+
/** @type {number} */
|
|
92
|
+
#tick = 0;
|
|
93
|
+
|
|
94
|
+
/** @type {number} */
|
|
95
|
+
#blend_skirt;
|
|
96
|
+
|
|
97
|
+
/** @type {number} */
|
|
98
|
+
#last_indirect_mode = -1;
|
|
99
|
+
|
|
100
|
+
/** @type {boolean} */
|
|
101
|
+
#destroyed = false;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @param {GPUDevice} device
|
|
105
|
+
* @param {Object} [options]
|
|
106
|
+
* @param {number} [options.cascade_count=IRRADIANCE_CLIPMAP_DEFAULT_CASCADE_COUNT]
|
|
107
|
+
* @param {number|ArrayLike<number>} [options.resolution=IRRADIANCE_CLIPMAP_DEFAULT_RESOLUTION]
|
|
108
|
+
* @param {number} [options.cell_size=IRRADIANCE_CLIPMAP_DEFAULT_CELL_SIZE]
|
|
109
|
+
* @param {number} [options.blend_skirt=IRRADIANCE_CLIPMAP_DEFAULT_BLEND_SKIRT]
|
|
110
|
+
*/
|
|
111
|
+
constructor(device, {
|
|
112
|
+
cascade_count = IRRADIANCE_CLIPMAP_DEFAULT_CASCADE_COUNT,
|
|
113
|
+
resolution = IRRADIANCE_CLIPMAP_DEFAULT_RESOLUTION,
|
|
114
|
+
cell_size = IRRADIANCE_CLIPMAP_DEFAULT_CELL_SIZE,
|
|
115
|
+
blend_skirt = IRRADIANCE_CLIPMAP_DEFAULT_BLEND_SKIRT,
|
|
116
|
+
} = {}) {
|
|
117
|
+
assert.defined(device, "device");
|
|
118
|
+
assert.isPositiveInteger(cascade_count, "cascade_count");
|
|
119
|
+
assert.lessThanOrEqual(cascade_count, IRRADIANCE_CLIPMAP_CASCADE_LIMIT, "cascade_count");
|
|
120
|
+
assert.isNumber(blend_skirt, "blend_skirt");
|
|
121
|
+
assert.greaterThan(blend_skirt, 0, "blend_skirt");
|
|
122
|
+
|
|
123
|
+
const res = typeof resolution === "number"
|
|
124
|
+
? [resolution, resolution, resolution]
|
|
125
|
+
: [resolution[0], resolution[1], resolution[2]];
|
|
126
|
+
|
|
127
|
+
this.#device = device;
|
|
128
|
+
this.#blend_skirt = blend_skirt;
|
|
129
|
+
this.#placement = new IrradianceCascadePlacement({
|
|
130
|
+
cascade_count,
|
|
131
|
+
resolution: res,
|
|
132
|
+
cell_size,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const tile_z = res[2] + 2 * IRRADIANCE_CLIPMAP_TILE_BORDER;
|
|
136
|
+
|
|
137
|
+
this.#atlas = new GPUTileAtlas3D({
|
|
138
|
+
device,
|
|
139
|
+
formats: [IRRADIANCE_CLIPMAP_TILE_FORMAT, IRRADIANCE_CLIPMAP_TILE_FORMAT],
|
|
140
|
+
content_size: res,
|
|
141
|
+
border: IRRADIANCE_CLIPMAP_TILE_BORDER,
|
|
142
|
+
slots_x: 1,
|
|
143
|
+
slots_y: 1,
|
|
144
|
+
capacity: Math.max(1, Math.min(cascade_count, Math.floor(device.limits.maxTextureDimension3D / tile_z))),
|
|
145
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING,
|
|
146
|
+
label: "GPUIrradianceClipmap/atlas",
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
for (let c = 0; c < cascade_count; c++) {
|
|
150
|
+
this.#slots[c] = this.#atlas.allocate();
|
|
151
|
+
this.#dirty[c] = 1;
|
|
152
|
+
this.#build_records.push({
|
|
153
|
+
tile_origin: [0, 0, 0],
|
|
154
|
+
cascade_index: c,
|
|
155
|
+
corner: [0, 0, 0],
|
|
156
|
+
cell_size: this.#placement.cell_size(c),
|
|
157
|
+
tile_size: [
|
|
158
|
+
this.#atlas.tile_size[0],
|
|
159
|
+
this.#atlas.tile_size[1],
|
|
160
|
+
this.#atlas.tile_size[2],
|
|
161
|
+
],
|
|
162
|
+
border: IRRADIANCE_CLIPMAP_TILE_BORDER,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this.#uniform = device.createBuffer({
|
|
167
|
+
label: "GPUIrradianceClipmap/table",
|
|
168
|
+
size: IRRADIANCE_CLIPMAP_STRUCT.size,
|
|
169
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @returns {GPUTileAtlas3D}
|
|
175
|
+
*/
|
|
176
|
+
get atlas() {
|
|
177
|
+
return this.#atlas;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* @returns {GPUTextureContext}
|
|
182
|
+
*/
|
|
183
|
+
get texture_y() {
|
|
184
|
+
return this.#atlas.texture_at(0);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @returns {GPUTextureContext}
|
|
189
|
+
*/
|
|
190
|
+
get texture_cocg() {
|
|
191
|
+
return this.#atlas.texture_at(1);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @returns {GPUBuffer}
|
|
196
|
+
*/
|
|
197
|
+
get uniform() {
|
|
198
|
+
return this.#uniform;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* @returns {number}
|
|
203
|
+
*/
|
|
204
|
+
get cascade_count() {
|
|
205
|
+
return this.#placement.cascade_count;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Number of voxels at each cascade window's outer faces where blending takes place.
|
|
210
|
+
* @returns {number}
|
|
211
|
+
*/
|
|
212
|
+
get blend_skirt() {
|
|
213
|
+
return this.#blend_skirt;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* @returns {IrradianceCascadePlacement}
|
|
218
|
+
*/
|
|
219
|
+
get placement() {
|
|
220
|
+
return this.#placement;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Forces all cascades to rebuild on the next executed frame.
|
|
225
|
+
*/
|
|
226
|
+
invalidate_all() {
|
|
227
|
+
this.#dirty.fill(1, 0, this.#placement.cascade_count);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Updates cascade window placements around `anchor` (`[x, y, z]` in world metres), detects
|
|
232
|
+
* warp events (`placement.moved(c)`), schedules cascade updates, and uploads the uniform table.
|
|
233
|
+
*
|
|
234
|
+
* @param {number} x
|
|
235
|
+
* @param {number} y
|
|
236
|
+
* @param {number} z
|
|
237
|
+
* @param {ShaderSwitchSet} [shader_switches]
|
|
238
|
+
*/
|
|
239
|
+
update_placement(x, y, z, shader_switches = ShaderSwitchSet.EMPTY) {
|
|
240
|
+
assert.notOk(this.#destroyed, "destroyed");
|
|
241
|
+
|
|
242
|
+
const placement = this.#placement;
|
|
243
|
+
const count = placement.cascade_count;
|
|
244
|
+
const res = placement.resolution;
|
|
245
|
+
|
|
246
|
+
const indirect_mode = shader_switches.get(INDIRECT_LIGHTING);
|
|
247
|
+
if (indirect_mode !== this.#last_indirect_mode) {
|
|
248
|
+
this.#last_indirect_mode = indirect_mode;
|
|
249
|
+
this.#dirty.fill(1, 0, count);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
placement.begin();
|
|
253
|
+
placement.place_all(x, y, z);
|
|
254
|
+
|
|
255
|
+
// Always schedule cascade 0 and the dyadic ruler cascade
|
|
256
|
+
this.#dirty[0] = 1;
|
|
257
|
+
const ruler_cascade = fluid_cascade_ruler(this.#tick, count);
|
|
258
|
+
if (ruler_cascade >= 0) {
|
|
259
|
+
this.#dirty[ruler_cascade] = 1;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Force immediate update on any cascade whose window crossed a hysteretic voxel boundary (warp)
|
|
263
|
+
for (let c = 0; c < count; c++) {
|
|
264
|
+
if (placement.moved(c)) {
|
|
265
|
+
this.#dirty[c] = 1;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const atlas = this.#atlas;
|
|
270
|
+
const origin = this.#origin;
|
|
271
|
+
const f32 = this.#f32;
|
|
272
|
+
const i32 = this.#i32;
|
|
273
|
+
|
|
274
|
+
for (let c = 0; c < count; c++) {
|
|
275
|
+
const cx = placement.corner(c, 0);
|
|
276
|
+
const cy = placement.corner(c, 1);
|
|
277
|
+
const cz = placement.corner(c, 2);
|
|
278
|
+
const h = placement.cell_size(c);
|
|
279
|
+
|
|
280
|
+
const level = LEVELS + c * LEVEL_STRIDE;
|
|
281
|
+
i32[level + LEVEL_CORNER] = cx;
|
|
282
|
+
i32[level + LEVEL_CORNER + 1] = cy;
|
|
283
|
+
i32[level + LEVEL_CORNER + 2] = cz;
|
|
284
|
+
f32[level + LEVEL_CELL_SIZE] = h;
|
|
285
|
+
i32[level + LEVEL_SIZE] = res[0];
|
|
286
|
+
i32[level + LEVEL_SIZE + 1] = res[1];
|
|
287
|
+
i32[level + LEVEL_SIZE + 2] = res[2];
|
|
288
|
+
|
|
289
|
+
atlas.slot_origin(this.#slots[c], origin);
|
|
290
|
+
|
|
291
|
+
const cascade = CASCADES + c * CASCADE_STRIDE + CASCADE_CONTENT_ORIGIN;
|
|
292
|
+
f32[cascade] = origin[0] + IRRADIANCE_CLIPMAP_TILE_BORDER;
|
|
293
|
+
f32[cascade + 1] = origin[1] + IRRADIANCE_CLIPMAP_TILE_BORDER;
|
|
294
|
+
f32[cascade + 2] = origin[2] + IRRADIANCE_CLIPMAP_TILE_BORDER;
|
|
295
|
+
|
|
296
|
+
const record = this.#build_records[c];
|
|
297
|
+
record.tile_origin[0] = origin[0];
|
|
298
|
+
record.tile_origin[1] = origin[1];
|
|
299
|
+
record.tile_origin[2] = origin[2];
|
|
300
|
+
record.corner[0] = cx;
|
|
301
|
+
record.corner[1] = cy;
|
|
302
|
+
record.corner[2] = cz;
|
|
303
|
+
record.cell_size = h;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const tile = atlas.tile_size;
|
|
307
|
+
f32[INVERSE_ATLAS_SIZE] = 1 / (atlas.slots_x * tile[0]);
|
|
308
|
+
f32[INVERSE_ATLAS_SIZE + 1] = 1 / (atlas.slots_y * tile[1]);
|
|
309
|
+
f32[INVERSE_ATLAS_SIZE + 2] = 1 / (atlas.slots_z * tile[2]);
|
|
310
|
+
this.#u32[CASCADE_COUNT] = count;
|
|
311
|
+
f32[ANCHOR] = x;
|
|
312
|
+
f32[ANCHOR + 1] = y;
|
|
313
|
+
f32[ANCHOR + 2] = z;
|
|
314
|
+
f32[BLEND_SKIRT] = this.#blend_skirt;
|
|
315
|
+
|
|
316
|
+
this.#device.queue.writeBuffer(this.#uniform, 0, this.#bytes);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Records the world-space light cluster clipmap build and the irradiance clipmap cascade update
|
|
321
|
+
* passes into `graph`.
|
|
322
|
+
*
|
|
323
|
+
* Neither pass is marked a side effect, so if nothing in the frame reads `Y` or `CoCg` (e.g. a
|
|
324
|
+
* frame with no volumetrics and no lit particles), the frame graph culls both passes and `#dirty`
|
|
325
|
+
* remains set until a frame actually executes them.
|
|
326
|
+
*
|
|
327
|
+
* @param {Object} options
|
|
328
|
+
* @param {import("../../../../engine/graphics/render/frame_graph/FrameGraph.js").FrameGraph} options.graph
|
|
329
|
+
* @param {import("../../camera/GPUCameraContext.js").GPUCameraContext} options.camera
|
|
330
|
+
* @param {import("../../scene/GPUSceneContext.js").GPUSceneContext} options.scene_ctx
|
|
331
|
+
* @param {number} options.shadowmap_atlas
|
|
332
|
+
* @param {ShaderSwitchSet} [options.shader_switches]
|
|
333
|
+
* @param {import("../../global_illumination/brick4/Brick4LightMap.js").Brick4LightMap} [options.brick4]
|
|
334
|
+
* @param {import("../../global_illumination/lpv/GPULightProbeVolume.js").GPULightProbeVolume} [options.lpv]
|
|
335
|
+
* @returns {{Y: number, CoCg: number, uniform: number}}
|
|
336
|
+
*/
|
|
337
|
+
graph_update({
|
|
338
|
+
graph,
|
|
339
|
+
camera,
|
|
340
|
+
scene_ctx,
|
|
341
|
+
shadowmap_atlas,
|
|
342
|
+
shader_switches = ShaderSwitchSet.EMPTY,
|
|
343
|
+
brick4,
|
|
344
|
+
lpv,
|
|
345
|
+
}) {
|
|
346
|
+
const transform = camera?.camera?.transform;
|
|
347
|
+
const x = transform !== undefined ? transform.translation_x : 0;
|
|
348
|
+
const y = transform !== undefined ? transform.translation_y : 0;
|
|
349
|
+
const z = transform !== undefined ? transform.translation_z : 0;
|
|
350
|
+
|
|
351
|
+
this.update_placement(x, y, z, shader_switches);
|
|
352
|
+
|
|
353
|
+
const gr_uniform = graph_import_buffer(graph, this.#uniform, "irradiance clipmap table");
|
|
354
|
+
const count = this.#placement.cascade_count;
|
|
355
|
+
const coarsest = count - 1;
|
|
356
|
+
const coarsest_record = this.#build_records[coarsest];
|
|
357
|
+
const coarsest_h = coarsest_record.cell_size;
|
|
358
|
+
const border = IRRADIANCE_CLIPMAP_TILE_BORDER;
|
|
359
|
+
const res = this.#placement.resolution;
|
|
360
|
+
|
|
361
|
+
const coarsest_min = [
|
|
362
|
+
(coarsest_record.corner[0] - border) * coarsest_h,
|
|
363
|
+
(coarsest_record.corner[1] - border) * coarsest_h,
|
|
364
|
+
(coarsest_record.corner[2] - border) * coarsest_h,
|
|
365
|
+
];
|
|
366
|
+
const coarsest_max = [
|
|
367
|
+
(coarsest_record.corner[0] + res[0] + border) * coarsest_h,
|
|
368
|
+
(coarsest_record.corner[1] + res[1] + border) * coarsest_h,
|
|
369
|
+
(coarsest_record.corner[2] + res[2] + border) * coarsest_h,
|
|
370
|
+
];
|
|
371
|
+
|
|
372
|
+
const world_clusters = graph_build_world_light_clusters({
|
|
373
|
+
graph,
|
|
374
|
+
lights: scene_ctx.lights,
|
|
375
|
+
irradiance_clipmap_uniform: gr_uniform,
|
|
376
|
+
cascade_count: count,
|
|
377
|
+
coarsest_min,
|
|
378
|
+
coarsest_max,
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
const gr_atlas_y = graph_import_texture(graph, this.texture_y, "irradiance clipmap Y");
|
|
382
|
+
const gr_atlas_cocg = graph_import_texture(graph, this.texture_cocg, "irradiance clipmap CoCg");
|
|
383
|
+
|
|
384
|
+
const data = {};
|
|
385
|
+
|
|
386
|
+
const pass = graph.add(shader_irradiance_clipmap_build.descriptor.label, data, (data, resources, context) => {
|
|
387
|
+
if (this.#destroyed) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const encoder = context.encoder;
|
|
392
|
+
const output_Y = resources.get(data.irradiance_Y);
|
|
393
|
+
const output_CoCg = resources.get(data.irradiance_CoCg);
|
|
394
|
+
const world_cluster_lookup = resources.get(data.world_cluster_lookup);
|
|
395
|
+
const world_cluster_data = resources.get(data.world_cluster_data);
|
|
396
|
+
const shadowmap_view = resources.get(data.shadowmap_atlas).obtainView();
|
|
397
|
+
const sCompareLinear = context.graphics.samplers.obtain(SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR);
|
|
398
|
+
|
|
399
|
+
const tile = this.#atlas.tile_size;
|
|
400
|
+
const count = this.#placement.cascade_count;
|
|
401
|
+
const variant = shader_irradiance_clipmap_build.variant(shader_switches);
|
|
402
|
+
|
|
403
|
+
for (let c = 0; c < count; c++) {
|
|
404
|
+
if (this.#dirty[c] === 0) {
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const bindings = {
|
|
409
|
+
build_settings: encoder.allocateTransientValueBuffer(
|
|
410
|
+
IRRADIANCE_CLIPMAP_BUILD_STRUCT,
|
|
411
|
+
this.#build_records[c],
|
|
412
|
+
GPUBufferUsage.UNIFORM
|
|
413
|
+
),
|
|
414
|
+
camera: camera.buffer.buffer,
|
|
415
|
+
environment_sh: scene_ctx.lights.environment_sh,
|
|
416
|
+
light_data: scene_ctx.lights.buffer_data,
|
|
417
|
+
world_cluster_lookup,
|
|
418
|
+
world_cluster_data,
|
|
419
|
+
shadowmapAtlas: shadowmap_view,
|
|
420
|
+
sCompareLinear,
|
|
421
|
+
atlas_y: output_Y.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
|
|
422
|
+
atlas_cocg: output_CoCg.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
if (brick4 !== undefined) {
|
|
426
|
+
bindings.brick4 = brick4.buffer;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (lpv !== undefined) {
|
|
430
|
+
bindings.lpv_lookup = lpv.buffer_mesh_bvh;
|
|
431
|
+
bindings.lpv_metadata = lpv.buffer_metadata;
|
|
432
|
+
bindings.lpv_mesh = lpv.buffer_mesh;
|
|
433
|
+
bindings.lpv_probes = lpv.buffer_probes;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
encoder_prepare_shader_bindings_defaults(bindings, context, variant.descriptor.resources);
|
|
437
|
+
|
|
438
|
+
variant.dispatchThreads({
|
|
439
|
+
encoder,
|
|
440
|
+
thread_count_x: tile[0],
|
|
441
|
+
thread_count_y: tile[1],
|
|
442
|
+
thread_count_z: tile[2],
|
|
443
|
+
bindings,
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
this.#dirty[c] = 0;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
this.#tick++;
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
data.world_cluster_lookup = pass.read(world_clusters.lookup);
|
|
453
|
+
data.world_cluster_data = pass.read(world_clusters.data);
|
|
454
|
+
data.shadowmap_atlas = pass.read(shadowmap_atlas);
|
|
455
|
+
pass.read(gr_atlas_y);
|
|
456
|
+
data.irradiance_Y = pass.write(gr_atlas_y);
|
|
457
|
+
pass.read(gr_atlas_cocg);
|
|
458
|
+
data.irradiance_CoCg = pass.write(gr_atlas_cocg);
|
|
459
|
+
|
|
460
|
+
// Allow the frame graph to cull the clipmap build (and upstream world cluster passes) on
|
|
461
|
+
// frames where neither volumetric fog nor lit particles read `Y` or `CoCg`. `#dirty` stays
|
|
462
|
+
// set until a surviving frame actually executes the pass.
|
|
463
|
+
graph.__pass_nodes[graph.__pass_nodes.length - 1].has_side_effects = false;
|
|
464
|
+
|
|
465
|
+
return {
|
|
466
|
+
Y: data.irradiance_Y,
|
|
467
|
+
CoCg: data.irradiance_CoCg,
|
|
468
|
+
uniform: gr_uniform,
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Releases GPU resources owned by the clipmap. Safe to call twice.
|
|
474
|
+
*/
|
|
475
|
+
destroy() {
|
|
476
|
+
if (this.#destroyed) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
this.#destroyed = true;
|
|
481
|
+
this.#atlas.destroy();
|
|
482
|
+
this.#uniform.destroy();
|
|
483
|
+
}
|
|
484
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default number of cascades in the world-space irradiance clipmap (Decision 6.3).
|
|
3
|
+
* Covers 8 m, 16 m, 32 m, 64 m, 128 m, 256 m at 32³ and h0 = 0.25 m.
|
|
4
|
+
* @type {number}
|
|
5
|
+
*/
|
|
6
|
+
export const IRRADIANCE_CLIPMAP_DEFAULT_CASCADE_COUNT: number;
|
|
7
|
+
/**
|
|
8
|
+
* Maximum number of cascades supported by the irradiance clipmap table.
|
|
9
|
+
* @type {number}
|
|
10
|
+
*/
|
|
11
|
+
export const IRRADIANCE_CLIPMAP_CASCADE_LIMIT: number;
|
|
12
|
+
/**
|
|
13
|
+
* Default resolution (cells per axis) of each irradiance clipmap cascade (Decision 6.3).
|
|
14
|
+
* @type {number}
|
|
15
|
+
*/
|
|
16
|
+
export const IRRADIANCE_CLIPMAP_DEFAULT_RESOLUTION: number;
|
|
17
|
+
/**
|
|
18
|
+
* Default finest cascade cell size h0 in metres (25 cm, Decision 6.3).
|
|
19
|
+
* @type {number}
|
|
20
|
+
*/
|
|
21
|
+
export const IRRADIANCE_CLIPMAP_DEFAULT_CELL_SIZE: number;
|
|
22
|
+
/**
|
|
23
|
+
* Texels of skirt on each side of a cascade's tile in the 3D atlas: 1 texel for hardware trilinear
|
|
24
|
+
* filtering (`tile_size = resolution + 2`).
|
|
25
|
+
* @type {number}
|
|
26
|
+
*/
|
|
27
|
+
export const IRRADIANCE_CLIPMAP_TILE_BORDER: number;
|
|
28
|
+
/**
|
|
29
|
+
* Default blend-skirt width in voxels (cells of that cascade) at the outer faces of each cascade
|
|
30
|
+
* window where blending takes place. At the very outer edge of the border voxel (`edge = 0`), the
|
|
31
|
+
* finer cascade's weight is `0.0` (`edge_weight = 1.0`); `blend_skirt` voxels inward, the finer
|
|
32
|
+
* cascade's weight is `1.0` (`edge_weight = 0.0`).
|
|
33
|
+
* @type {number}
|
|
34
|
+
*/
|
|
35
|
+
export const IRRADIANCE_CLIPMAP_DEFAULT_BLEND_SKIRT: number;
|
|
36
|
+
/**
|
|
37
|
+
* Format of the two synchronized 3D atlas textures (`Y` and `CoCg`).
|
|
38
|
+
* @type {GPUTextureFormat}
|
|
39
|
+
*/
|
|
40
|
+
export const IRRADIANCE_CLIPMAP_TILE_FORMAT: GPUTextureFormat;
|
|
41
|
+
/**
|
|
42
|
+
* Sampler used for trilinear taps of the irradiance clipmap atlas textures.
|
|
43
|
+
*/
|
|
44
|
+
export const IRRADIANCE_CLIPMAP_SAMPLER_DESCRIPTOR: Readonly<import("../../../descriptor/texture/SamplerDescriptor.js").SamplerDescriptor>;
|
|
45
|
+
/**
|
|
46
|
+
* Maximum number of point or spot lights evaluated per voxel in the irradiance clipmap build pass.
|
|
47
|
+
* @type {number}
|
|
48
|
+
*/
|
|
49
|
+
export const IRRADIANCE_CLIPMAP_LIGHT_BUDGET: number;
|
|
50
|
+
//# sourceMappingURL=IRRADIANCE_CLIPMAP.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IRRADIANCE_CLIPMAP.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.js"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,uDAFU,MAAM,CAE0C;AAE1D;;;GAGG;AACH,+CAFU,MAAM,CAEoD;AAEpE;;;GAGG;AACH,oDAFU,MAAM,CAEwC;AAExD;;;GAGG;AACH,mDAFU,MAAM,CAEyC;AAEzD;;;;GAIG;AACH,6CAFU,MAAM,CAEgC;AAEhD;;;;;;GAMG;AACH,qDAFU,MAAM,CAEwC;AAExD;;;GAGG;AACH,8DAA4D;AAE5D;;GAEG;AACH,2IAA4E;AAE5E;;;GAGG;AACH,8CAFU,MAAM,CAEkC"}
|