@woosh/meep-engine 3.61.0 → 3.61.2
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/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +4 -0
- package/src/engine/graphics/ecs/decal/v2/Decal.d.ts +46 -2
- package/src/engine/graphics/ecs/decal/v2/Decal.d.ts.map +1 -1
- package/src/engine/graphics/ecs/decal/v2/Decal.js +74 -5
- package/src/engine/graphics/ecs/decal/v2/DecalSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics/ecs/decal/v2/DecalSerializationAdapter.js +13 -1
- package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_1_2.d.ts +9 -0
- package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_1_2.d.ts.map +1 -0
- package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_1_2.js +37 -0
- package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
- package/src/engine/graphics3/DecalSystem.js +462 -447
- package/src/engine/graphics3/decal/DECAL_GPU_RECORD.d.ts +14 -0
- package/src/engine/graphics3/decal/DECAL_GPU_RECORD.d.ts.map +1 -1
- package/src/engine/graphics3/decal/DECAL_GPU_RECORD.js +53 -13
- package/src/engine/graphics3/decal/chunk_decal_record.d.ts +6 -1
- package/src/engine/graphics3/decal/chunk_decal_record.d.ts.map +1 -1
- package/src/engine/graphics3/decal/chunk_decal_record.js +28 -9
- package/src/engine/graphics3/decal/decal_gpu_records.d.ts +2 -1
- package/src/engine/graphics3/decal/decal_gpu_records.d.ts.map +1 -1
- package/src/engine/graphics3/decal/decal_gpu_records.js +26 -5
- package/src/engine/graphics3/decal/decal_material_samplers.d.ts +6 -0
- package/src/engine/graphics3/decal/decal_material_samplers.d.ts.map +1 -1
- package/src/engine/graphics3/decal/decal_material_samplers.js +13 -0
- package/src/engine/graphics3/decal/shader_cluster_assign_decals.js +1 -1
- package/src/engine/graphics3/decal/shader_cull_decals_frustum.js +1 -1
- package/src/engine/graphics3/decal/shader_decal_composite.d.ts +5 -0
- package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
- package/src/engine/graphics3/decal/shader_decal_composite.js +69 -28
- package/src/engine/network/sim/SimActionExecutor.d.ts +4 -0
- package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
- package/src/engine/network/sim/SimActionExecutor.js +4 -0
- package/src/generation/foliage/material/foliage_atlas_cutout.d.ts.map +1 -1
- package/src/generation/foliage/material/foliage_atlas_cutout.js +21 -5
- package/src/generation/foliage/mesh/tree_cluster_representatives.d.ts +8 -0
- package/src/generation/foliage/mesh/tree_cluster_representatives.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_cluster_representatives.js +178 -78
- package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_mesh_build_bark.js +178 -97
- package/src/generation/foliage/skeleton/ShootLightField.d.ts +1 -0
- package/src/generation/foliage/skeleton/ShootLightField.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/ShootLightField.js +88 -17
- package/src/generation/foliage/skeleton/ShootWoodHash.d.ts +8 -4
- package/src/generation/foliage/skeleton/ShootWoodHash.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/ShootWoodHash.js +216 -27
- package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
- package/src/shade/playground/probe_clipmap/main.js +4 -0
- package/src/shade/playground/probe_clipmap_box/README.md +55 -0
- package/src/shade/playground/probe_clipmap_box/index.html +185 -0
- package/src/shade/playground/probe_clipmap_box/main.d.ts +8 -0
- package/src/shade/playground/probe_clipmap_box/main.d.ts.map +1 -0
- package/src/shade/playground/probe_clipmap_box/main.js +323 -0
- package/src/shade/playground/probe_clipmap_box/scene.d.ts +93 -0
- package/src/shade/playground/probe_clipmap_box/scene.d.ts.map +1 -0
- package/src/shade/playground/probe_clipmap_box/scene.js +256 -0
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +6 -1
- package/src/shade/renderer/buffer/graph_read_buffer.d.ts +3 -1
- package/src/shade/renderer/buffer/graph_read_buffer.d.ts.map +1 -1
- package/src/shade/renderer/buffer/graph_read_buffer.js +9 -6
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_decode.d.ts +12 -0
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_decode.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_decode.js +49 -24
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_encode.d.ts +12 -0
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_encode.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_brick4_sh3_color_encode.js +50 -19
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_sh3_compress.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v2/chunk_sh3_compress.js +6 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +5 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +7 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +6 -4
- 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 +10 -9
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +12 -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 +14 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +17 -22
- 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 +53 -65
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts +2 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.js +9 -20
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts +2 -2
- 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 +14 -19
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +1 -1
- 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 +8 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.js +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.d.ts +2 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_bounce.js +13 -18
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_candidate.d.ts +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_candidate.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_candidate.js +4 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_diffuse.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_diffuse.js +4 -6
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.js +4 -7
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts +4 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.js +14 -13
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts +3 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +7 -15
- 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 +5 -1
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +1 -7
- package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts +26 -8
- package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.js +170 -142
- package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.d.ts +1 -1
- package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.js +5 -8
- package/src/shade/renderer/restir/di/chunk_restir_resolve.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/chunk_restir_resolve.js +91 -94
- package/src/shade/renderer/restir/reservoir/chunk_rtxdi_stream_sample.js +1 -1
- package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.d.ts +14 -0
- package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_decode.js +36 -21
- package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.d.ts +22 -0
- package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/rgbe9995/chunk_rgbe9995_sample_gather.js +64 -0
- package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts +15 -4
- package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.js +33 -7
- package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_vertex_normal.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_vertex_normal.js +13 -18
- package/src/shade/renderer/shader/chunk/geometry/normal/chunk_encode_vertex_normal.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/normal/chunk_encode_vertex_normal.js +28 -30
- package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_u32_to_vec2.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_u32_to_vec2.js +15 -16
- package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_vec2_to_u32.d.ts +0 -1
- package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_vec2_to_u32.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/vec2/chunk_unit_vec2_to_u32.js +15 -18
- package/src/shade/renderer/shader/chunk/noise/chunk_sobol_sample_vec2.d.ts +40 -0
- package/src/shade/renderer/shader/chunk/noise/chunk_sobol_sample_vec2.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/noise/chunk_sobol_sample_vec2.js +75 -0
- package/src/shade/renderer/shader/chunk/noise/chunk_vdc_radical_inverse.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/noise/chunk_vdc_radical_inverse.js +3 -1
- package/src/shade/renderer/shader/chunk/random/chunk_hash_lk.d.ts +28 -0
- package/src/shade/renderer/shader/chunk/random/chunk_hash_lk.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/random/chunk_hash_lk.js +41 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh3_color_add_scaled.d.ts +12 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh3_color_add_scaled.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/spherical_harmonics/chunk_sh3_color_add_scaled.js +24 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts +3 -2
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.js +4 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts +2 -5
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.js +3 -20
- package/src/shade/renderer/water/chunk_water_gi.d.ts +1 -1
- package/src/shade/renderer/water/chunk_water_gi.d.ts.map +1 -1
- package/src/shade/renderer/water/chunk_water_gi.js +6 -8
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +8 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +79 -35
- package/src/core/math/hash/squirrel3.d.ts +0 -17
- package/src/core/math/hash/squirrel3.d.ts.map +0 -1
- package/src/core/math/hash/squirrel3.js +0 -30
- package/src/shade/renderer/global_illumination/brick4/cpu/brick4_sh3_color_encode.d.ts +0 -2
- package/src/shade/renderer/global_illumination/brick4/cpu/brick4_sh3_color_encode.d.ts.map +0 -1
- package/src/shade/renderer/global_illumination/brick4/cpu/brick4_sh3_color_encode.js +0 -6
- package/src/shade/renderer/shader/chunk/random/chunk_hash_squirrel3.d.ts +0 -12
- package/src/shade/renderer/shader/chunk/random/chunk_hash_squirrel3.d.ts.map +0 -1
- package/src/shade/renderer/shader/chunk/random/chunk_hash_squirrel3.js +0 -30
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { aabb3_intersects_segment3 } from "../../../core/geom/3d/aabb/aabb3_intersects_segment3.js";
|
|
1
2
|
import { line3_compute_segment_segment_closest_points } from "../../../core/geom/3d/line/line3_compute_segment_segment_closest_points.js";
|
|
2
3
|
import { shoot_radius } from "./shoot_geometry.js";
|
|
3
4
|
|
|
@@ -20,6 +21,14 @@ const CLEARANCE = 0.001;
|
|
|
20
21
|
*/
|
|
21
22
|
const KEY_SPAN = 2048;
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Margin (m) a cell is widened by when asking whether an axis line crosses it: far above the rounding of a point at
|
|
26
|
+
* the key's 205 m span, far below any wood, so a line along a cell's face or through its edge is under the cells either
|
|
27
|
+
* side of it.
|
|
28
|
+
* @type {number}
|
|
29
|
+
*/
|
|
30
|
+
const CROSSING_TOLERANCE = WOOD_CELL * 2 ** -20;
|
|
31
|
+
|
|
23
32
|
const SCRATCH_ST = new Float64Array(2);
|
|
24
33
|
|
|
25
34
|
/**
|
|
@@ -27,10 +36,10 @@ const SCRATCH_ST = new Float64Array(2);
|
|
|
27
36
|
* wood, and thinner wood that thicker wood has grown into can be found. A unit is added once, when it has grown, under
|
|
28
37
|
* the cells its axis line crosses; a query reads every unit's place and radius from its axis as they are then, and
|
|
29
38
|
* reaches as far round as the thickest wood ({@link max_radius}), so wood that thickens needs no re-adding. The units
|
|
30
|
-
* of an axis that has died are passed over.
|
|
39
|
+
* of an axis that has died are passed over, and leave the hash at the next {@link refresh}.
|
|
31
40
|
*/
|
|
32
41
|
export class ShootWoodHash {
|
|
33
|
-
/** @type {Map<number, number[]>} */
|
|
42
|
+
/** @type {Map<number, number[] & {max?: number}>} */
|
|
34
43
|
cells = new Map();
|
|
35
44
|
|
|
36
45
|
/**
|
|
@@ -66,6 +75,47 @@ export class ShootWoodHash {
|
|
|
66
75
|
|
|
67
76
|
query = 0;
|
|
68
77
|
|
|
78
|
+
/** @type {number[]} */
|
|
79
|
+
#min_x = [];
|
|
80
|
+
/** @type {number[]} */
|
|
81
|
+
#max_x = [];
|
|
82
|
+
/** @type {number[]} */
|
|
83
|
+
#min_y = [];
|
|
84
|
+
/** @type {number[]} */
|
|
85
|
+
#max_y = [];
|
|
86
|
+
/** @type {number[]} */
|
|
87
|
+
#min_z = [];
|
|
88
|
+
/** @type {number[]} */
|
|
89
|
+
#max_z = [];
|
|
90
|
+
/** @type {number[]} */
|
|
91
|
+
#bx0 = [];
|
|
92
|
+
/** @type {number[]} */
|
|
93
|
+
#bx1 = [];
|
|
94
|
+
/** @type {number[]} */
|
|
95
|
+
#by0 = [];
|
|
96
|
+
/** @type {number[]} */
|
|
97
|
+
#by1 = [];
|
|
98
|
+
/** @type {number[]} */
|
|
99
|
+
#bz0 = [];
|
|
100
|
+
/** @type {number[]} */
|
|
101
|
+
#bz1 = [];
|
|
102
|
+
/** @type {number[]} */
|
|
103
|
+
#thickest = [];
|
|
104
|
+
#refreshed_max = -1;
|
|
105
|
+
/** @type {number[]} */
|
|
106
|
+
#last_candidates = [];
|
|
107
|
+
#last_b0 = NaN;
|
|
108
|
+
#last_b1 = NaN;
|
|
109
|
+
#last_b2 = NaN;
|
|
110
|
+
#last_radius = NaN;
|
|
111
|
+
#last_min_radius = NaN;
|
|
112
|
+
#last_ax0 = NaN;
|
|
113
|
+
#last_ax1 = NaN;
|
|
114
|
+
#last_ay0 = NaN;
|
|
115
|
+
#last_ay1 = NaN;
|
|
116
|
+
#last_az0 = NaN;
|
|
117
|
+
#last_az1 = NaN;
|
|
118
|
+
|
|
69
119
|
/**
|
|
70
120
|
* @param {Array<{alive: boolean, points: number[], radii: number[], units: number[]}>} axes
|
|
71
121
|
*/
|
|
@@ -85,42 +135,93 @@ export class ShootWoodHash {
|
|
|
85
135
|
this.seen.push(0);
|
|
86
136
|
const p = this.axes[m].points;
|
|
87
137
|
const a = k * 3, b = a + 3;
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
const
|
|
138
|
+
const min_x = Math.min(p[a], p[b]), max_x = Math.max(p[a], p[b]);
|
|
139
|
+
const min_y = Math.min(p[a + 1], p[b + 1]), max_y = Math.max(p[a + 1], p[b + 1]);
|
|
140
|
+
const min_z = Math.min(p[a + 2], p[b + 2]), max_z = Math.max(p[a + 2], p[b + 2]);
|
|
141
|
+
const x0 = Math.floor(min_x / WOOD_CELL), x1 = Math.floor(max_x / WOOD_CELL);
|
|
142
|
+
const y0 = Math.floor(min_y / WOOD_CELL), y1 = Math.floor(max_y / WOOD_CELL);
|
|
143
|
+
const z0 = Math.floor(min_z / WOOD_CELL), z1 = Math.floor(max_z / WOOD_CELL);
|
|
144
|
+
this.#min_x.push(min_x);
|
|
145
|
+
this.#max_x.push(max_x);
|
|
146
|
+
this.#min_y.push(min_y);
|
|
147
|
+
this.#max_y.push(max_y);
|
|
148
|
+
this.#min_z.push(min_z);
|
|
149
|
+
this.#max_z.push(max_z);
|
|
150
|
+
this.#bx0.push(min_x);
|
|
151
|
+
this.#bx1.push(max_x);
|
|
152
|
+
this.#by0.push(min_y);
|
|
153
|
+
this.#by1.push(max_y);
|
|
154
|
+
this.#bz0.push(min_z);
|
|
155
|
+
this.#bz1.push(max_z);
|
|
156
|
+
this.#thickest.push(-1);
|
|
91
157
|
for (let x = x0; x <= x1; x++) for (let y = y0; y <= y1; y++) for (let z = z0; z <= z1; z++) {
|
|
92
|
-
|
|
158
|
+
if (!aabb3_intersects_segment3(
|
|
159
|
+
x * WOOD_CELL - CROSSING_TOLERANCE, y * WOOD_CELL - CROSSING_TOLERANCE, z * WOOD_CELL - CROSSING_TOLERANCE,
|
|
160
|
+
(x + 1) * WOOD_CELL + CROSSING_TOLERANCE, (y + 1) * WOOD_CELL + CROSSING_TOLERANCE, (z + 1) * WOOD_CELL + CROSSING_TOLERANCE,
|
|
161
|
+
p[a], p[a + 1], p[a + 2], p[b], p[b + 1], p[b + 2]
|
|
162
|
+
)) continue;
|
|
163
|
+
const key = (x * KEY_SPAN + y) * KEY_SPAN + z;
|
|
93
164
|
let list = this.cells.get(key);
|
|
94
165
|
if (list === undefined) {
|
|
95
166
|
list = [];
|
|
96
167
|
this.cells.set(key, list);
|
|
97
168
|
}
|
|
169
|
+
list.max = Infinity;
|
|
98
170
|
list.push(id);
|
|
99
171
|
this.cell_max.set(key, Infinity);
|
|
100
172
|
}
|
|
173
|
+
this.#refreshed_max = -1;
|
|
174
|
+
this.#last_b0 = NaN;
|
|
101
175
|
}
|
|
102
176
|
|
|
103
177
|
/**
|
|
104
178
|
* Records each cell's thickest living unit, after the wood has thickened, and the thickest of all
|
|
105
|
-
* ({@link max_radius}).
|
|
179
|
+
* ({@link max_radius}). A dead axis does not live again, so its units leave their cells, in the order the rest
|
|
180
|
+
* were added, and a cell left empty leaves the hash.
|
|
106
181
|
*/
|
|
107
182
|
refresh() {
|
|
108
183
|
const axes = this.axes;
|
|
184
|
+
const n = this.unit_axis.length;
|
|
185
|
+
for (let id = 0; id < n; id++) {
|
|
186
|
+
const axis = axes[this.unit_axis[id]];
|
|
187
|
+
if (!axis.alive) continue;
|
|
188
|
+
const k = this.unit_index[id];
|
|
189
|
+
const r = axis.radii.length > k + 1 ? Math.max(axis.radii[k], axis.radii[k + 1]) : shoot_radius(axis.units[k], 0);
|
|
190
|
+
if (r === this.#thickest[id]) continue;
|
|
191
|
+
this.#thickest[id] = r;
|
|
192
|
+
const pad = r + CLEARANCE;
|
|
193
|
+
this.#bx0[id] = this.#min_x[id] - pad;
|
|
194
|
+
this.#bx1[id] = this.#max_x[id] + pad;
|
|
195
|
+
this.#by0[id] = this.#min_y[id] - pad;
|
|
196
|
+
this.#by1[id] = this.#max_y[id] + pad;
|
|
197
|
+
this.#bz0[id] = this.#min_z[id] - pad;
|
|
198
|
+
this.#bz1[id] = this.#max_z[id] + pad;
|
|
199
|
+
}
|
|
109
200
|
let most = 0;
|
|
110
201
|
for (const [key, list] of this.cells) {
|
|
111
202
|
let max = 0;
|
|
203
|
+
let kept = 0;
|
|
112
204
|
for (let i = 0; i < list.length; i++) {
|
|
113
205
|
const id = list[i];
|
|
114
206
|
const axis = axes[this.unit_axis[id]];
|
|
115
207
|
if (!axis.alive) continue;
|
|
116
|
-
|
|
117
|
-
const thickest =
|
|
208
|
+
list[kept++] = id;
|
|
209
|
+
const thickest = this.#thickest[id];
|
|
118
210
|
if (thickest > max) max = thickest;
|
|
119
211
|
}
|
|
212
|
+
if (kept === 0) {
|
|
213
|
+
this.cells.delete(key);
|
|
214
|
+
this.cell_max.delete(key);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
list.length = kept;
|
|
218
|
+
list.max = max;
|
|
120
219
|
this.cell_max.set(key, max);
|
|
121
220
|
if (max > most) most = max;
|
|
122
221
|
}
|
|
123
222
|
this.max_radius = most;
|
|
223
|
+
this.#refreshed_max = most;
|
|
224
|
+
this.#last_b0 = NaN;
|
|
124
225
|
}
|
|
125
226
|
|
|
126
227
|
/**
|
|
@@ -149,44 +250,132 @@ export class ShootWoodHash {
|
|
|
149
250
|
* @returns {number}
|
|
150
251
|
*/
|
|
151
252
|
hits(a, b, radius, min_radius, skip) {
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
const y0 = Math.floor((Math.min(a[1], b[1]) - pad) / WOOD_CELL), y1 = Math.floor((Math.max(a[1], b[1]) + pad) / WOOD_CELL);
|
|
155
|
-
const z0 = Math.floor((Math.min(a[2], b[2]) - pad) / WOOD_CELL), z1 = Math.floor((Math.max(a[2], b[2]) + pad) / WOOD_CELL);
|
|
156
|
-
const query = ++this.query;
|
|
157
|
-
const axes = this.axes;
|
|
253
|
+
if (this.cells.size === 0) return -1;
|
|
254
|
+
const fresh = this.max_radius === this.#refreshed_max;
|
|
158
255
|
const ax0 = Math.min(a[0], b[0]) - radius, ax1 = Math.max(a[0], b[0]) + radius;
|
|
159
256
|
const ay0 = Math.min(a[1], b[1]) - radius, ay1 = Math.max(a[1], b[1]) + radius;
|
|
160
257
|
const az0 = Math.min(a[2], b[2]) - radius, az1 = Math.max(a[2], b[2]) + radius;
|
|
258
|
+
const axes = this.axes;
|
|
259
|
+
const bx0 = this.#bx0, bx1 = this.#bx1, by0 = this.#by0, by1 = this.#by1, bz0 = this.#bz0, bz1 = this.#bz1;
|
|
260
|
+
const thickest_arr = this.#thickest;
|
|
261
|
+
const skip_geom_free = skip.length <= 2;
|
|
262
|
+
|
|
263
|
+
if (fresh && b[0] === this.#last_b0 && b[1] === this.#last_b1 && b[2] === this.#last_b2
|
|
264
|
+
&& radius === this.#last_radius && min_radius === this.#last_min_radius
|
|
265
|
+
&& ax0 >= this.#last_ax0 && ax1 <= this.#last_ax1
|
|
266
|
+
&& ay0 >= this.#last_ay0 && ay1 <= this.#last_ay1
|
|
267
|
+
&& az0 >= this.#last_az0 && az1 <= this.#last_az1) {
|
|
268
|
+
const cands = this.#last_candidates;
|
|
269
|
+
for (let i = 0; i < cands.length; i++) {
|
|
270
|
+
const id = cands[i];
|
|
271
|
+
if (bx0[id] > ax1 || bx1[id] < ax0 || by0[id] > ay1 || by1[id] < ay0 || bz0[id] > az1 || bz1[id] < az0) continue;
|
|
272
|
+
const m = this.unit_axis[id];
|
|
273
|
+
const k = this.unit_index[id];
|
|
274
|
+
if (skip_geom_free && skip(m, k, 0, 0)) continue;
|
|
275
|
+
const p = axes[m].points;
|
|
276
|
+
const q = k * 3;
|
|
277
|
+
line3_compute_segment_segment_closest_points(SCRATCH_ST, a[0], a[1], a[2], b[0], b[1], b[2], p[q], p[q + 1], p[q + 2], p[q + 3], p[q + 4], p[q + 5]);
|
|
278
|
+
const s = SCRATCH_ST[0], t = SCRATCH_ST[1];
|
|
279
|
+
const r = ShootWoodHash.radius_at(axes[m], k, t);
|
|
280
|
+
const dx = a[0] + (b[0] - a[0]) * s - (p[q] + (p[q + 3] - p[q]) * t);
|
|
281
|
+
const dy = a[1] + (b[1] - a[1]) * s - (p[q + 1] + (p[q + 4] - p[q + 1]) * t);
|
|
282
|
+
const dz = a[2] + (b[2] - a[2]) * s - (p[q + 2] + (p[q + 5] - p[q + 2]) * t);
|
|
283
|
+
const limit = r + radius + CLEARANCE;
|
|
284
|
+
if (dx * dx + dy * dy + dz * dz >= limit * limit) continue;
|
|
285
|
+
if (!skip_geom_free && skip(m, k, r, s)) continue;
|
|
286
|
+
return m;
|
|
287
|
+
}
|
|
288
|
+
return -1;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const reach = this.max_radius + CLEARANCE;
|
|
292
|
+
const x0 = Math.floor((ax0 - reach) / WOOD_CELL), x1 = Math.floor((ax1 + reach) / WOOD_CELL);
|
|
293
|
+
const y0 = Math.floor((ay0 - reach) / WOOD_CELL), y1 = Math.floor((ay1 + reach) / WOOD_CELL);
|
|
294
|
+
const z0 = Math.floor((az0 - reach) / WOOD_CELL), z1 = Math.floor((az1 + reach) / WOOD_CELL);
|
|
295
|
+
const single = x0 === x1 && y0 === y1 && z0 === z1;
|
|
296
|
+
const query = single ? 0 : ++this.query;
|
|
297
|
+
const seen = this.seen;
|
|
298
|
+
const cands = this.#last_candidates;
|
|
299
|
+
if (fresh) {
|
|
300
|
+
cands.length = 0;
|
|
301
|
+
this.#last_b0 = b[0];
|
|
302
|
+
this.#last_b1 = b[1];
|
|
303
|
+
this.#last_b2 = b[2];
|
|
304
|
+
this.#last_radius = radius;
|
|
305
|
+
this.#last_min_radius = min_radius;
|
|
306
|
+
this.#last_ax0 = ax0;
|
|
307
|
+
this.#last_ax1 = ax1;
|
|
308
|
+
this.#last_ay0 = ay0;
|
|
309
|
+
this.#last_ay1 = ay1;
|
|
310
|
+
this.#last_az0 = az0;
|
|
311
|
+
this.#last_az1 = az1;
|
|
312
|
+
}
|
|
161
313
|
for (let x = x0; x <= x1; x++) for (let y = y0; y <= y1; y++) for (let z = z0; z <= z1; z++) {
|
|
162
|
-
const key = (
|
|
314
|
+
const key = (x * KEY_SPAN + y) * KEY_SPAN + z;
|
|
163
315
|
const list = this.cells.get(key);
|
|
164
|
-
if (list === undefined ||
|
|
316
|
+
if (list === undefined || list.max < min_radius) continue;
|
|
317
|
+
if (fresh) {
|
|
318
|
+
const pad_c = list.max + CLEARANCE;
|
|
319
|
+
if (x * WOOD_CELL > ax1 + pad_c || (x + 1) * WOOD_CELL < ax0 - pad_c
|
|
320
|
+
|| y * WOOD_CELL > ay1 + pad_c || (y + 1) * WOOD_CELL < ay0 - pad_c
|
|
321
|
+
|| z * WOOD_CELL > az1 + pad_c || (z + 1) * WOOD_CELL < az0 - pad_c) continue;
|
|
322
|
+
}
|
|
165
323
|
for (let i = 0; i < list.length; i++) {
|
|
166
324
|
const id = list[i];
|
|
167
|
-
if (
|
|
168
|
-
|
|
325
|
+
if (fresh) {
|
|
326
|
+
if (bx0[id] > ax1 || bx1[id] < ax0 || by0[id] > ay1 || by1[id] < ay0 || bz0[id] > az1 || bz1[id] < az0) continue;
|
|
327
|
+
const thickest = thickest_arr[id];
|
|
328
|
+
if (thickest < min_radius) continue;
|
|
329
|
+
if (!single) {
|
|
330
|
+
if (seen[id] === query) continue;
|
|
331
|
+
seen[id] = query;
|
|
332
|
+
}
|
|
333
|
+
const m = this.unit_axis[id];
|
|
334
|
+
const axis = axes[m];
|
|
335
|
+
if (!axis.alive) continue;
|
|
336
|
+
cands.push(id);
|
|
337
|
+
const k = this.unit_index[id];
|
|
338
|
+
if (skip_geom_free && skip(m, k, 0, 0)) continue;
|
|
339
|
+
const p = axis.points;
|
|
340
|
+
const q = k * 3;
|
|
341
|
+
line3_compute_segment_segment_closest_points(SCRATCH_ST, a[0], a[1], a[2], b[0], b[1], b[2], p[q], p[q + 1], p[q + 2], p[q + 3], p[q + 4], p[q + 5]);
|
|
342
|
+
const s = SCRATCH_ST[0], t = SCRATCH_ST[1];
|
|
343
|
+
const r = ShootWoodHash.radius_at(axis, k, t);
|
|
344
|
+
const dx = a[0] + (b[0] - a[0]) * s - (p[q] + (p[q + 3] - p[q]) * t);
|
|
345
|
+
const dy = a[1] + (b[1] - a[1]) * s - (p[q + 1] + (p[q + 4] - p[q + 1]) * t);
|
|
346
|
+
const dz = a[2] + (b[2] - a[2]) * s - (p[q + 2] + (p[q + 5] - p[q + 2]) * t);
|
|
347
|
+
const limit = r + radius + CLEARANCE;
|
|
348
|
+
if (dx * dx + dy * dy + dz * dz >= limit * limit) continue;
|
|
349
|
+
if (!skip_geom_free && skip(m, k, r, s)) continue;
|
|
350
|
+
this.#last_b0 = NaN;
|
|
351
|
+
return m;
|
|
352
|
+
}
|
|
353
|
+
if (!single) {
|
|
354
|
+
if (seen[id] === query) continue;
|
|
355
|
+
seen[id] = query;
|
|
356
|
+
}
|
|
169
357
|
const m = this.unit_axis[id];
|
|
170
358
|
const axis = axes[m];
|
|
171
359
|
if (!axis.alive) continue;
|
|
172
360
|
const k = this.unit_index[id];
|
|
173
|
-
const p = axis.points;
|
|
174
|
-
const q = k * 3;
|
|
175
|
-
// the thickest the unit is, and whether its box padded by that meets the capsule's
|
|
176
361
|
const thickest = axis.radii.length > k + 1 ? Math.max(axis.radii[k], axis.radii[k + 1]) : shoot_radius(axis.units[k], 0);
|
|
177
362
|
if (thickest < min_radius) continue;
|
|
178
363
|
const pad_k = thickest + CLEARANCE;
|
|
179
|
-
if (
|
|
180
|
-
||
|
|
181
|
-
||
|
|
364
|
+
if (this.#min_x[id] - pad_k > ax1 || this.#max_x[id] + pad_k < ax0
|
|
365
|
+
|| this.#min_y[id] - pad_k > ay1 || this.#max_y[id] + pad_k < ay0
|
|
366
|
+
|| this.#min_z[id] - pad_k > az1 || this.#max_z[id] + pad_k < az0) continue;
|
|
367
|
+
if (skip_geom_free && skip(m, k, 0, 0)) continue;
|
|
368
|
+
const p = axis.points;
|
|
369
|
+
const q = k * 3;
|
|
182
370
|
line3_compute_segment_segment_closest_points(SCRATCH_ST, a[0], a[1], a[2], b[0], b[1], b[2], p[q], p[q + 1], p[q + 2], p[q + 3], p[q + 4], p[q + 5]);
|
|
183
371
|
const s = SCRATCH_ST[0], t = SCRATCH_ST[1];
|
|
184
372
|
const r = ShootWoodHash.radius_at(axis, k, t);
|
|
185
373
|
const dx = a[0] + (b[0] - a[0]) * s - (p[q] + (p[q + 3] - p[q]) * t);
|
|
186
374
|
const dy = a[1] + (b[1] - a[1]) * s - (p[q + 1] + (p[q + 4] - p[q + 1]) * t);
|
|
187
375
|
const dz = a[2] + (b[2] - a[2]) * s - (p[q + 2] + (p[q + 5] - p[q + 2]) * t);
|
|
188
|
-
|
|
189
|
-
if (
|
|
376
|
+
const limit = r + radius + CLEARANCE;
|
|
377
|
+
if (dx * dx + dy * dy + dz * dz >= limit * limit) continue;
|
|
378
|
+
if (!skip_geom_free && skip(m, k, r, s)) continue;
|
|
190
379
|
return m;
|
|
191
380
|
}
|
|
192
381
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/probe_clipmap/main.js"],"names":[],"mappings":"AA0FA;;;;;GAKG;AACH,yBAFa,QAAQ,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/probe_clipmap/main.js"],"names":[],"mappings":"AA0FA;;;;;GAKG;AACH,yBAFa,QAAQ,IAAI,CAAC,CA0SzB"}
|
|
@@ -214,6 +214,10 @@ export async function start() {
|
|
|
214
214
|
|
|
215
215
|
sun.transform.setRotation(rotation.x, rotation.y, rotation.z, rotation.w);
|
|
216
216
|
sun.transform.updateMatrix();
|
|
217
|
+
|
|
218
|
+
// a light changed in place reaches the GPU only through the collection's version; without it the
|
|
219
|
+
// shadow cascades, which read the transform themselves, turn and the light does not
|
|
220
|
+
scene.lights.needsUpdate = true;
|
|
217
221
|
}
|
|
218
222
|
|
|
219
223
|
aim_sun();
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Probe clipmap GI — a box with a hole
|
|
2
|
+
|
|
3
|
+
A closed box under `ShadeIndirectLightingMode.ProbeClipmap`
|
|
4
|
+
(`src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md`), built to watch how
|
|
5
|
+
the probes follow a change: the sun moved from one wall to another, or the only opening closed. Nothing but the
|
|
6
|
+
sun lights the inside, so what the probes should hold after a change is known without a reference renderer, and
|
|
7
|
+
with the hole closed it is nothing at all.
|
|
8
|
+
|
|
9
|
+
## Running it
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install
|
|
13
|
+
npm run dev
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
then open <http://localhost:5173/src/shade/playground/probe_clipmap_box/index.html>. The page needs no asset.
|
|
17
|
+
|
|
18
|
+
## The box
|
|
19
|
+
|
|
20
|
+
`scene.js` builds it, and a harness can build the same one through `build_hole_box`.
|
|
21
|
+
|
|
22
|
+
- The inside is 5 m a side: five spacings of the finest probe cascade at the GI's default spacing.
|
|
23
|
+
- Every slab is 0.25 m thick, two voxels of the finest brick, so a wall has an inside the distance field can
|
|
24
|
+
tell from its outside. Each slab is a geometry of its own size at unit scale, since a mesh's distance field
|
|
25
|
+
is cached per geometry and a scaled unit cube would not be one.
|
|
26
|
+
- The walls have the classic Cornell reflectances: white 0.73, red (0.63, 0.065, 0.05) at −x and green
|
|
27
|
+
(0.14, 0.45, 0.091) at +x.
|
|
28
|
+
- The hole is 1.25 m square in the middle of the ceiling. A flat sky of (0.2, 0.25, 0.35) is seen through it.
|
|
29
|
+
|
|
30
|
+
## The controls
|
|
31
|
+
|
|
32
|
+
| control | what it does |
|
|
33
|
+
|---|---|
|
|
34
|
+
| Sun (1, 2, 3) | through the hole onto the red wall or the green wall, from 45°, or straight down onto the floor |
|
|
35
|
+
| Hole open (H) | closed, a lid of the hole's size sits flush in the ceiling; it is placed into the scene and taken out again, so the bricks the rays march are rebuilt as a level's would be |
|
|
36
|
+
| Indirect light | the probe clipmap, or IBL to compare against |
|
|
37
|
+
| Debug view | the brick clipmap as the rays see it; the geometry caches' mesh SDF; the hits' albedo from the cards |
|
|
38
|
+
| Restart GI (K) | gives the clipmaps back and builds them again from nothing, the geometry caches kept: a cold start without a reload |
|
|
39
|
+
| Path tracer (P) | the accumulating path tracer, three bounces, for context; TAA is off while it is on |
|
|
40
|
+
| TAA | the resolve the probe pick's noise is meant for |
|
|
41
|
+
| Exposure | fixed f-stops; eye adaptation is off, so a change on screen is the light's. The probes' estimators state their thresholds in it too: a change below what the display shows is taken for noise and followed slowly |
|
|
42
|
+
|
|
43
|
+
The stats line counts the frames since the sun or the hole last changed.
|
|
44
|
+
|
|
45
|
+
## What to look for
|
|
46
|
+
|
|
47
|
+
- **Hole closed**: the inside should go black. Whatever light stays is what the probes still hold.
|
|
48
|
+
- **Sun moved between the walls**: the colour bleeding onto the back wall and the floor should swap from red
|
|
49
|
+
to green.
|
|
50
|
+
- **Restart**: until the brick clipmap has built (about 48 frames at the default build budget), the rays see
|
|
51
|
+
no walls and every probe sees the sky; the light then has to drain out of the probes.
|
|
52
|
+
|
|
53
|
+
Aiming the sun sets `scene.lights.needsUpdate`: a light changed in place reaches the GPU only when the light
|
|
54
|
+
collection's version moves, while the shadow cascades read the transform themselves, so without it the
|
|
55
|
+
shadow turns and the light does not.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>meep — probe clipmap GI, a box with a hole</title>
|
|
6
|
+
<style>
|
|
7
|
+
:root {
|
|
8
|
+
color-scheme: dark;
|
|
9
|
+
--panel: rgba(20, 22, 26, 0.88);
|
|
10
|
+
--line: #2b3038;
|
|
11
|
+
--text: #d6dae0;
|
|
12
|
+
--muted: #8b939f;
|
|
13
|
+
--pass: #55c46a;
|
|
14
|
+
--fail: #ff6b6b;
|
|
15
|
+
--warn: #e5b54a;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
* { box-sizing: border-box; }
|
|
19
|
+
|
|
20
|
+
html, body { margin: 0; height: 100%; overflow: hidden; background: #0d0f12; }
|
|
21
|
+
|
|
22
|
+
/* body carries tabindex so the camera controller's keyboard device has something focusable
|
|
23
|
+
to listen on; the focus ring around the whole viewport is not wanted */
|
|
24
|
+
body:focus { outline: none; }
|
|
25
|
+
|
|
26
|
+
#view { display: block; width: 100vw; height: 100vh; }
|
|
27
|
+
|
|
28
|
+
#panel {
|
|
29
|
+
position: fixed;
|
|
30
|
+
top: 12px;
|
|
31
|
+
left: 12px;
|
|
32
|
+
width: 320px;
|
|
33
|
+
padding: 12px 14px;
|
|
34
|
+
background: var(--panel);
|
|
35
|
+
border: 1px solid var(--line);
|
|
36
|
+
border-radius: 8px;
|
|
37
|
+
backdrop-filter: blur(6px);
|
|
38
|
+
color: var(--text);
|
|
39
|
+
font: 13px/1.5 system-ui, -apple-system, Segoe UI, sans-serif;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#panel h1 { font-size: 13px; font-weight: 600; margin: 0 0 8px; }
|
|
43
|
+
|
|
44
|
+
label { display: flex; align-items: center; gap: 8px; padding: 3px 0; cursor: pointer; }
|
|
45
|
+
label input[type="checkbox"] { margin: 0; }
|
|
46
|
+
label .hint { color: var(--muted); font-size: 11.5px; }
|
|
47
|
+
label > span:first-child { flex: 0 0 96px; }
|
|
48
|
+
|
|
49
|
+
select {
|
|
50
|
+
flex: 1 1 auto;
|
|
51
|
+
min-width: 0;
|
|
52
|
+
font: 12px system-ui, -apple-system, Segoe UI, sans-serif;
|
|
53
|
+
padding: 3px 6px;
|
|
54
|
+
border-radius: 5px;
|
|
55
|
+
border: 1px solid var(--line);
|
|
56
|
+
background: #14161a;
|
|
57
|
+
color: var(--text);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
button {
|
|
61
|
+
font: 12px system-ui, -apple-system, Segoe UI, sans-serif;
|
|
62
|
+
padding: 3px 10px;
|
|
63
|
+
border-radius: 5px;
|
|
64
|
+
border: 1px solid var(--line);
|
|
65
|
+
background: #1d2026;
|
|
66
|
+
color: var(--text);
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
input[type="range"] { flex: 1 1 auto; min-width: 0; }
|
|
71
|
+
|
|
72
|
+
output { flex: 0 0 34px; text-align: right; color: var(--muted); font: 12px ui-monospace, SFMono-Regular, Consolas, monospace; }
|
|
73
|
+
|
|
74
|
+
hr { border: 0; border-top: 1px solid var(--line); margin: 10px 0; }
|
|
75
|
+
|
|
76
|
+
#status { font-size: 12px; color: var(--muted); word-break: break-word; }
|
|
77
|
+
#status.pass { color: var(--pass); }
|
|
78
|
+
#status.fail { color: var(--fail); }
|
|
79
|
+
#status.warn { color: var(--warn); }
|
|
80
|
+
|
|
81
|
+
#stats {
|
|
82
|
+
margin-top: 6px;
|
|
83
|
+
font: 12px ui-monospace, SFMono-Regular, Consolas, monospace;
|
|
84
|
+
color: var(--text);
|
|
85
|
+
white-space: pre;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
p.note { margin: 8px 0 0; font-size: 11.5px; color: var(--muted); }
|
|
89
|
+
</style>
|
|
90
|
+
</head>
|
|
91
|
+
<body tabindex="0">
|
|
92
|
+
|
|
93
|
+
<canvas id="view"></canvas>
|
|
94
|
+
|
|
95
|
+
<div id="panel">
|
|
96
|
+
<h1>Probe clipmap GI — a box with a hole</h1>
|
|
97
|
+
|
|
98
|
+
<label>
|
|
99
|
+
<span>Sun</span>
|
|
100
|
+
<select id="sun_aim">
|
|
101
|
+
<option value="RedWall" selected>Onto the red wall</option>
|
|
102
|
+
<option value="GreenWall">Onto the green wall</option>
|
|
103
|
+
<option value="Down">Straight down</option>
|
|
104
|
+
</select>
|
|
105
|
+
</label>
|
|
106
|
+
|
|
107
|
+
<label>
|
|
108
|
+
<input type="checkbox" id="hole_open" checked>
|
|
109
|
+
<span>Hole open <span class="hint">— closed, nothing lights the inside; H flips it</span></span>
|
|
110
|
+
</label>
|
|
111
|
+
|
|
112
|
+
<p class="note">1, 2 and 3 aim the sun.</p>
|
|
113
|
+
|
|
114
|
+
<hr>
|
|
115
|
+
|
|
116
|
+
<label>
|
|
117
|
+
<span>Indirect light</span>
|
|
118
|
+
<select id="indirect">
|
|
119
|
+
<option value="ProbeClipmap" selected>Probe clipmap</option>
|
|
120
|
+
<option value="IBL">IBL</option>
|
|
121
|
+
</select>
|
|
122
|
+
</label>
|
|
123
|
+
|
|
124
|
+
<label>
|
|
125
|
+
<span>Debug view</span>
|
|
126
|
+
<select id="debug_view">
|
|
127
|
+
<option value="None" selected>None</option>
|
|
128
|
+
<option value="BrickClipmap">Brick clipmap — what the rays see</option>
|
|
129
|
+
<option value="MeshSDF">Mesh SDF — the geometry caches</option>
|
|
130
|
+
<option value="MeshCards">Mesh cards — the hits' albedo</option>
|
|
131
|
+
</select>
|
|
132
|
+
</label>
|
|
133
|
+
|
|
134
|
+
<label>
|
|
135
|
+
<span>Restart GI</span>
|
|
136
|
+
<button id="restart">Restart</button>
|
|
137
|
+
<span class="hint">K</span>
|
|
138
|
+
</label>
|
|
139
|
+
<p class="note">
|
|
140
|
+
Gives the probes and bricks back and builds them again from nothing, the geometry caches kept: the
|
|
141
|
+
convergence from a cold start, without reloading.
|
|
142
|
+
</p>
|
|
143
|
+
|
|
144
|
+
<label>
|
|
145
|
+
<input type="checkbox" id="path_tracing">
|
|
146
|
+
<span>Path tracer <span class="hint">— three bounces, for context; P flips it</span></span>
|
|
147
|
+
</label>
|
|
148
|
+
|
|
149
|
+
<label>
|
|
150
|
+
<input type="checkbox" id="taa" checked>
|
|
151
|
+
<span>TAA <span class="hint">— resolves the probe pick's noise</span></span>
|
|
152
|
+
</label>
|
|
153
|
+
|
|
154
|
+
<label>
|
|
155
|
+
<span>Exposure</span>
|
|
156
|
+
<input type="range" id="exposure" min="-4" max="8" step="0.5">
|
|
157
|
+
<output id="exposure_value"></output>
|
|
158
|
+
</label>
|
|
159
|
+
|
|
160
|
+
<hr>
|
|
161
|
+
|
|
162
|
+
<div id="status"></div>
|
|
163
|
+
<div id="stats"></div>
|
|
164
|
+
|
|
165
|
+
<p class="note">
|
|
166
|
+
Drag to orbit, wheel to zoom, WASD to move. The exposure is fixed, so a change you see is the light's,
|
|
167
|
+
not the eye's adapting.
|
|
168
|
+
</p>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
<script type="module">
|
|
172
|
+
import { start } from './main.js';
|
|
173
|
+
|
|
174
|
+
start().catch(error => {
|
|
175
|
+
const status = document.getElementById('status');
|
|
176
|
+
|
|
177
|
+
status.className = 'fail';
|
|
178
|
+
status.textContent = String(error?.message ?? error);
|
|
179
|
+
|
|
180
|
+
console.error(error);
|
|
181
|
+
});
|
|
182
|
+
</script>
|
|
183
|
+
|
|
184
|
+
</body>
|
|
185
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/probe_clipmap_box/main.js"],"names":[],"mappings":"AAsEA;;;;;GAKG;AACH,yBAFa,QAAQ,IAAI,CAAC,CAwPzB"}
|