@woosh/meep-engine 3.60.5 → 3.60.6
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/CHANGELOG.md +19 -0
- package/package.json +1 -1
- package/src/shade/renderer/Renderer.d.ts +11 -0
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +43 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +26 -43
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +109 -117
- package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +20 -2
- package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +66 -2
- package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts +19 -0
- package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.js +25 -0
- package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +15 -0
- package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +38 -0
- package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts +28 -59
- package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.js +84 -789
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +2 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +2 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +2 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +2 -2
- package/src/shade/renderer/material/GPUMaterialManager.d.ts +4 -1
- package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
- package/src/shade/renderer/material/GPUMaterialManager.js +5 -8
- package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +7 -3
- package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/GTAO.js +26 -13
- package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts +14 -0
- package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +196 -68
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +42 -28
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +429 -414
- package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts +16 -0
- package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.js +156 -0
- package/src/shade/renderer/scene/GPUSceneContext.d.ts +2 -2
- package/src/shade/renderer/scene/GPUSceneContext.js +5 -5
- package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts +0 -47
- package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.js +0 -80
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts +0 -16
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.js +0 -67
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts +0 -17
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.js +0 -145
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts +0 -12
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.js +0 -105
|
@@ -56,15 +56,6 @@ import { MeshSDFLayout } from "./MeshSDFLayout.js";
|
|
|
56
56
|
* @typedef {import("../../material/GPUMaterialManager.js").GPUMaterialManager} GPUMaterialManager
|
|
57
57
|
*/
|
|
58
58
|
|
|
59
|
-
/**
|
|
60
|
-
* What makes caches for geometries the bake cannot bake from a tree of their own
|
|
61
|
-
* ({@link GPUGeometrySDFManager#add_source}): it learns what is asked for from `onRequested`, records its own work in
|
|
62
|
-
* each frame's graph ahead of the bake, and hands each cache in through `adopt`.
|
|
63
|
-
*
|
|
64
|
-
* @typedef {Object} MeshSDFSource
|
|
65
|
-
* @property {function(FrameGraph): void} graph_update records the source's work for the frame, ahead of the bake
|
|
66
|
-
*/
|
|
67
|
-
|
|
68
59
|
/*
|
|
69
60
|
What the host knows of a geometry id. `Queued` is the host's alone: the header reads None until the
|
|
70
61
|
bake is admitted and the indirection range is the geometry's.
|
|
@@ -204,7 +195,8 @@ function grow_typed(array, length) {
|
|
|
204
195
|
* queues a bake; the last one going leaves the cache in place until {@link trim}, which only a user of
|
|
205
196
|
* the caches calls, so a cache outlives a mode that stops using it and is there when the mode comes
|
|
206
197
|
* back (D28). {@link forget} drops a geometry the geometry manager has let go of, whatever holds it.
|
|
207
|
-
* {@link alias} points a
|
|
198
|
+
* {@link alias} points a geometry's id at another's cache, which readers follow, and whose holders and card sets
|
|
199
|
+
* the aliased geometry's become: a skinned clone's at its source's, a virtual geometry's at its proxy's.
|
|
208
200
|
*
|
|
209
201
|
* **Side.** A holder says whether it draws both sides of the geometry. A field is baked two-sided
|
|
210
202
|
* while any of its holders does: its vote then counts no back face, so nothing is inside it.
|
|
@@ -226,11 +218,11 @@ function grow_typed(array, length) {
|
|
|
226
218
|
* {@link cards}, whose card sets — one per (geometry, material) pair — are captured after the bake,
|
|
227
219
|
* `capture_budget` pages a frame.
|
|
228
220
|
*
|
|
229
|
-
* **
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* geometry
|
|
221
|
+
* **A geometry with no tree of its own** to bake from, a virtual geometry's, waits queued, as one whose
|
|
222
|
+
* tree is not resident yet does, until it is pointed at a stand-in ({@link alias}): an ordinary geometry
|
|
223
|
+
* in the same local space, baked, placed and captured here as any is. Whoever makes stand-ins hears of
|
|
224
|
+
* each geometry queued ({@link onRequested}) and let go ({@link onForgotten}), and aliases between
|
|
225
|
+
* frames, its stand-in added to the geometry manager as any geometry is.
|
|
234
226
|
*
|
|
235
227
|
* **Readers** bind {@link headers}, {@link indirection}, {@link texture} and {@link MESH_SDF_SAMPLER}
|
|
236
228
|
* (see {@link write_bindings}) and sample through `mesh_sdf_sample`, which only a resident header
|
|
@@ -251,22 +243,25 @@ export class GPUGeometrySDFManager {
|
|
|
251
243
|
#geometries;
|
|
252
244
|
|
|
253
245
|
/**
|
|
254
|
-
* Sent with a geometry id when its cache turns resident, on the frame its completion is read back
|
|
246
|
+
* Sent with a geometry id when its cache turns resident, on the frame its completion is read back, and with each
|
|
247
|
+
* geometry aliased to it, whose readers read that cache: also when the alias is made to a cache resident already.
|
|
255
248
|
* @type {Signal<number>}
|
|
256
249
|
*/
|
|
257
250
|
onBaked = new Signal();
|
|
258
251
|
|
|
259
252
|
/**
|
|
260
|
-
* Sent with a geometry's record each time its cache is queued for a bake: what a
|
|
253
|
+
* Sent with a geometry's record each time its cache is queued for a bake: what a maker of stand-ins
|
|
254
|
+
* listens to.
|
|
261
255
|
* @type {Signal<GPUGeometryMetadata>}
|
|
262
256
|
*/
|
|
263
257
|
onRequested = new Signal();
|
|
264
258
|
|
|
265
259
|
/**
|
|
266
|
-
*
|
|
267
|
-
*
|
|
260
|
+
* Sent with a geometry's record when {@link forget} lets it go: what a maker of stand-ins that made one for it
|
|
261
|
+
* listens to.
|
|
262
|
+
* @type {Signal<GPUGeometryMetadata>}
|
|
268
263
|
*/
|
|
269
|
-
|
|
264
|
+
onForgotten = new Signal();
|
|
270
265
|
|
|
271
266
|
#voxel_size = 0.125;
|
|
272
267
|
#max_bricks = 18;
|
|
@@ -578,7 +573,7 @@ export class GPUGeometrySDFManager {
|
|
|
578
573
|
}
|
|
579
574
|
|
|
580
575
|
/**
|
|
581
|
-
* One more holder of a geometry's cache; the first queues its bake.
|
|
576
|
+
* One more holder of a geometry's cache; the first queues its bake. A holder of an alias holds its source.
|
|
582
577
|
*
|
|
583
578
|
* @param {GPUGeometryMetadata} record
|
|
584
579
|
* @param {boolean} two_sided whether the holder draws both sides of the geometry
|
|
@@ -587,17 +582,40 @@ export class GPUGeometrySDFManager {
|
|
|
587
582
|
assert.defined(record, 'record');
|
|
588
583
|
assert.isBoolean(two_sided, 'two_sided');
|
|
589
584
|
|
|
590
|
-
|
|
585
|
+
this.#ensure_id(record.index);
|
|
591
586
|
|
|
592
|
-
this.#
|
|
587
|
+
if (this.#state[record.index] !== HOST_ALIAS) {
|
|
588
|
+
this.#records[record.index] = record;
|
|
589
|
+
}
|
|
593
590
|
|
|
594
|
-
this.#
|
|
591
|
+
this.#hold(this.#holder_id(record.index), 1, two_sided ? 1 : 0);
|
|
592
|
+
}
|
|
595
593
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
594
|
+
/**
|
|
595
|
+
* The id a holder of `id` holds: its source's, for an alias.
|
|
596
|
+
*
|
|
597
|
+
* @param {number} id
|
|
598
|
+
* @returns {number}
|
|
599
|
+
*/
|
|
600
|
+
#holder_id(id) {
|
|
601
|
+
return this.#state[id] === HOST_ALIAS ? this.#aliases.get(id) : id;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* `count` more holders of `id`, `two_sided` of them drawing both sides; the first queues its bake.
|
|
606
|
+
*
|
|
607
|
+
* @param {number} id
|
|
608
|
+
* @param {number} count
|
|
609
|
+
* @param {number} two_sided
|
|
610
|
+
*/
|
|
611
|
+
#hold(id, count, two_sided) {
|
|
612
|
+
this.#two_sided_references[id] += two_sided;
|
|
599
613
|
|
|
600
|
-
|
|
614
|
+
const before = this.#references[id];
|
|
615
|
+
|
|
616
|
+
this.#references[id] = before + count;
|
|
617
|
+
|
|
618
|
+
if (before === 0 && this.#state[id] === HOST_NONE) {
|
|
601
619
|
this.#request(id);
|
|
602
620
|
}
|
|
603
621
|
|
|
@@ -605,7 +623,7 @@ export class GPUGeometrySDFManager {
|
|
|
605
623
|
}
|
|
606
624
|
|
|
607
625
|
/**
|
|
608
|
-
* One holder fewer. The cache stays until {@link trim}.
|
|
626
|
+
* One holder fewer. The cache stays until {@link trim}. A holder of an alias holds its source.
|
|
609
627
|
*
|
|
610
628
|
* @param {GPUGeometryMetadata} record
|
|
611
629
|
* @param {boolean} two_sided as the holder acquired it
|
|
@@ -614,7 +632,7 @@ export class GPUGeometrySDFManager {
|
|
|
614
632
|
assert.defined(record, 'record');
|
|
615
633
|
assert.isBoolean(two_sided, 'two_sided');
|
|
616
634
|
|
|
617
|
-
const id = record.index;
|
|
635
|
+
const id = this.#holder_id(record.index);
|
|
618
636
|
|
|
619
637
|
assert.greaterThan(this.#references[id] ?? 0, 0, `geometry ${id} released more often than acquired`);
|
|
620
638
|
|
|
@@ -667,11 +685,19 @@ export class GPUGeometrySDFManager {
|
|
|
667
685
|
this.#two_sided_references[id] = 0;
|
|
668
686
|
this.#drop(id);
|
|
669
687
|
this.#records[id] = undefined;
|
|
688
|
+
|
|
689
|
+
this.onForgotten.send1(record);
|
|
670
690
|
}
|
|
671
691
|
|
|
672
692
|
/**
|
|
673
693
|
* Readers of `clone` read `source`'s cache: the hook for a skinned clone, whose unskinned shape is
|
|
674
|
-
* its source's (§6.3)
|
|
694
|
+
* its source's (§6.3), and for a virtual geometry, whose proxy is its stand-in (§17). Written once; it
|
|
695
|
+
* follows the source through its bake.
|
|
696
|
+
*
|
|
697
|
+
* Whatever held `clone`'s own cache holds `source`'s from here on, its side included, as does every holder of
|
|
698
|
+
* `clone` after; and `clone`'s card sets capture `source`'s layout through `source`'s meshlets
|
|
699
|
+
* ({@link GPUMeshCardSets#alias}). So a source whose stand-in arrives after `clone` was asked for needs
|
|
700
|
+
* nothing moved by its holders.
|
|
675
701
|
*
|
|
676
702
|
* @param {GPUGeometryMetadata} clone
|
|
677
703
|
* @param {GPUGeometryMetadata} source
|
|
@@ -693,6 +719,20 @@ export class GPUGeometrySDFManager {
|
|
|
693
719
|
|
|
694
720
|
this.#state[id] = HOST_ALIAS;
|
|
695
721
|
|
|
722
|
+
const held = this.#references[id];
|
|
723
|
+
const held_two_sided = this.#two_sided_references[id];
|
|
724
|
+
|
|
725
|
+
this.#references[id] = 0;
|
|
726
|
+
this.#two_sided_references[id] = 0;
|
|
727
|
+
|
|
728
|
+
if (this.#state[source.index] !== HOST_ALIAS) {
|
|
729
|
+
this.#records[source.index] = source;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
if (held > 0) {
|
|
733
|
+
this.#hold(source.index, held, held_two_sided);
|
|
734
|
+
}
|
|
735
|
+
|
|
696
736
|
if (this.#headers !== null) {
|
|
697
737
|
this.#ensure_headers(id + 1);
|
|
698
738
|
this.#write_header_alias(id, source.index);
|
|
@@ -700,6 +740,22 @@ export class GPUGeometrySDFManager {
|
|
|
700
740
|
|
|
701
741
|
this.#records[id] = clone;
|
|
702
742
|
this.#aliases.set(id, source.index);
|
|
743
|
+
|
|
744
|
+
let clones = this.#clones_of.get(source.index);
|
|
745
|
+
|
|
746
|
+
if (clones === undefined) {
|
|
747
|
+
clones = [];
|
|
748
|
+
this.#clones_of.set(source.index, clones);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
clones.push(id);
|
|
752
|
+
|
|
753
|
+
this.#cards.alias(id, source.index);
|
|
754
|
+
|
|
755
|
+
if (this.#state[source.index] === HOST_RESIDENT) {
|
|
756
|
+
// its readers read a resident cache from here on
|
|
757
|
+
this.onBaked.send1(id);
|
|
758
|
+
}
|
|
703
759
|
}
|
|
704
760
|
|
|
705
761
|
/**
|
|
@@ -708,6 +764,12 @@ export class GPUGeometrySDFManager {
|
|
|
708
764
|
*/
|
|
709
765
|
#aliases = new Map();
|
|
710
766
|
|
|
767
|
+
/**
|
|
768
|
+
* The ids aliased to each source id: the readers {@link onBaked} tells of the source's bake too.
|
|
769
|
+
* @type {Map<number, number[]>}
|
|
770
|
+
*/
|
|
771
|
+
#clones_of = new Map();
|
|
772
|
+
|
|
711
773
|
/**
|
|
712
774
|
* What a reader finds in the geometry's header.
|
|
713
775
|
*
|
|
@@ -748,82 +810,6 @@ export class GPUGeometrySDFManager {
|
|
|
748
810
|
return (this.#two_sided_references[record.index] ?? 0) > 0;
|
|
749
811
|
}
|
|
750
812
|
|
|
751
|
-
/**
|
|
752
|
-
* @param {MeshSDFSource} source run first in each {@link graph_bake} from here on
|
|
753
|
-
*/
|
|
754
|
-
add_source(source) {
|
|
755
|
-
assert.defined(source, 'source');
|
|
756
|
-
assert.equal(this.#sources.includes(source), false, 'source added already');
|
|
757
|
-
|
|
758
|
-
this.#sources.push(source);
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
/**
|
|
762
|
-
* @param {MeshSDFSource} source
|
|
763
|
-
*/
|
|
764
|
-
remove_source(source) {
|
|
765
|
-
const index = this.#sources.indexOf(source);
|
|
766
|
-
|
|
767
|
-
if (index !== -1) {
|
|
768
|
-
this.#sources.splice(index, 1);
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
/**
|
|
773
|
-
* Give `target` the resident cache baked for `proxy`: a source's hand-in, for a geometry with no tree of its own,
|
|
774
|
-
* of a proxy in the same local space baked as any geometry is. Nothing is copied. The target's header takes the
|
|
775
|
-
* proxy's layout, entries and side, and the proxy's reads None, as dropped; {@link onBaked} is sent with the
|
|
776
|
-
* target. The cache has no cards, the target having no tree to capture them with. Held for another side than the
|
|
777
|
-
* proxy was baked for, it is queued again at the next bake, as any cache is.
|
|
778
|
-
*
|
|
779
|
-
* @param {GPUGeometryMetadata} target waiting for its bake ({@link is_requested})
|
|
780
|
-
* @param {GPUGeometryMetadata} proxy whose cache is resident
|
|
781
|
-
* @returns {boolean} whether it was adopted: false, changing nothing, when `target` no longer waits or `proxy`'s
|
|
782
|
-
* cache is not resident
|
|
783
|
-
*/
|
|
784
|
-
adopt(target, proxy) {
|
|
785
|
-
assert.defined(target, 'target');
|
|
786
|
-
assert.defined(proxy, 'proxy');
|
|
787
|
-
assert.notEqual(target.index, proxy.index, 'a geometry cannot adopt its own cache');
|
|
788
|
-
|
|
789
|
-
const id = target.index;
|
|
790
|
-
const from = proxy.index;
|
|
791
|
-
|
|
792
|
-
if (!this.is_requested(target) || this.#state[from] !== HOST_RESIDENT) {
|
|
793
|
-
return false;
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
this.#drop_cards(from);
|
|
797
|
-
|
|
798
|
-
const range = this.#ranges[from];
|
|
799
|
-
|
|
800
|
-
this.#ranges[id] = range;
|
|
801
|
-
this.#ranges[from] = null;
|
|
802
|
-
this.#brick_count[id] = this.#brick_count[from];
|
|
803
|
-
this.#two_sided[id] = this.#two_sided[from];
|
|
804
|
-
this.#generation[id]++;
|
|
805
|
-
|
|
806
|
-
this.#state[from] = HOST_NONE;
|
|
807
|
-
this.#state[id] = HOST_RESIDENT;
|
|
808
|
-
|
|
809
|
-
// the layout the proxy was admitted with: a configure since would have dropped its cache
|
|
810
|
-
const layout = this.#layout;
|
|
811
|
-
|
|
812
|
-
layout.compute(proxy.geometry.bounding_box, this.#voxel_size, this.#max_bricks);
|
|
813
|
-
|
|
814
|
-
this.#write_header(id, layout, range.offset + 1, MeshSDFState.Resident);
|
|
815
|
-
|
|
816
|
-
this.#word_scratch[0] = MeshSDFState.None;
|
|
817
|
-
this.#device.queue.writeBuffer(this.#headers, from * HEADER_BYTES + HEADER_STATE, this.#word_scratch, 0, 1);
|
|
818
|
-
|
|
819
|
-
// the side its holders draw is checked at the next bake
|
|
820
|
-
this.#holders_changed.push(id);
|
|
821
|
-
|
|
822
|
-
this.onBaked.send1(id);
|
|
823
|
-
|
|
824
|
-
return true;
|
|
825
|
-
}
|
|
826
|
-
|
|
827
813
|
/**
|
|
828
814
|
* Geometries whose layout was coarsened by the cap, of those baked: coarser than asked.
|
|
829
815
|
* @returns {number}
|
|
@@ -994,13 +980,6 @@ export class GPUGeometrySDFManager {
|
|
|
994
980
|
|
|
995
981
|
this.#frame++;
|
|
996
982
|
|
|
997
|
-
// the sources first: a cache adopted here is not admitted to a bake of its own below
|
|
998
|
-
const sources = this.#sources;
|
|
999
|
-
|
|
1000
|
-
for (let i = 0; i < sources.length; i++) {
|
|
1001
|
-
sources[i].graph_update(graph);
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
983
|
this.#follow_sides();
|
|
1005
984
|
|
|
1006
985
|
// the last bake's commands were submitted before this call: what they read may be handed out
|
|
@@ -1233,7 +1212,7 @@ export class GPUGeometrySDFManager {
|
|
|
1233
1212
|
/**
|
|
1234
1213
|
* Whether a queued geometry's tree is traceable, so that a bake could admit it. A geometry that
|
|
1235
1214
|
* waits for its tree, or for a source's cache, records no bake while it waits. Drops from the queue
|
|
1236
|
-
* what was dropped, or
|
|
1215
|
+
* what was dropped, or aliased, since it was queued.
|
|
1237
1216
|
*
|
|
1238
1217
|
* @returns {boolean}
|
|
1239
1218
|
*/
|
|
@@ -1264,8 +1243,8 @@ export class GPUGeometrySDFManager {
|
|
|
1264
1243
|
}
|
|
1265
1244
|
|
|
1266
1245
|
/**
|
|
1267
|
-
* Whether a resident geometry's cards wait for placement. Drops from the queue what was dropped
|
|
1268
|
-
*
|
|
1246
|
+
* Whether a resident geometry's cards wait for placement. Drops from the queue what was dropped
|
|
1247
|
+
* since it was queued.
|
|
1269
1248
|
*
|
|
1270
1249
|
* @returns {boolean}
|
|
1271
1250
|
*/
|
|
@@ -1693,6 +1672,14 @@ export class GPUGeometrySDFManager {
|
|
|
1693
1672
|
this.#place_queue.push(id);
|
|
1694
1673
|
|
|
1695
1674
|
this.onBaked.send1(id);
|
|
1675
|
+
|
|
1676
|
+
const clones = this.#clones_of.get(id);
|
|
1677
|
+
|
|
1678
|
+
if (clones !== undefined) {
|
|
1679
|
+
for (let i = 0; i < clones.length; i++) {
|
|
1680
|
+
this.onBaked.send1(clones[i]);
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1696
1683
|
}
|
|
1697
1684
|
}
|
|
1698
1685
|
|
|
@@ -1779,7 +1766,12 @@ export class GPUGeometrySDFManager {
|
|
|
1779
1766
|
}
|
|
1780
1767
|
|
|
1781
1768
|
if (state === HOST_ALIAS) {
|
|
1769
|
+
const clones = this.#clones_of.get(this.#aliases.get(id));
|
|
1770
|
+
|
|
1771
|
+
clones.splice(clones.indexOf(id), 1);
|
|
1772
|
+
|
|
1782
1773
|
this.#aliases.delete(id);
|
|
1774
|
+
this.#cards.unalias(id);
|
|
1783
1775
|
} else {
|
|
1784
1776
|
if (state === HOST_BAKING) {
|
|
1785
1777
|
this.#baking--;
|
|
@@ -24,7 +24,8 @@ export const MESH_CARD_CAPTURE_BUDGET_MAX: number;
|
|
|
24
24
|
* - Its record (`MESH_CARD_SET_STRUCT`) is written when a capture starts.
|
|
25
25
|
*
|
|
26
26
|
* **Lifetime.** {@link acquire} makes a card set for a pair and {@link release} gives it back; the
|
|
27
|
-
* caller keeps one per pair. A card set
|
|
27
|
+
* caller keeps one per pair. A card set of an aliased geometry ({@link alias}) is its source's: it
|
|
28
|
+
* captures the source's layout through the source's meshlets. A card set waits until its geometry's layout is placed
|
|
28
29
|
* ({@link set_layout}), is then captured, and turns resident ({@link onResident}) on the frame its
|
|
29
30
|
* last page is recorded: the capture's writes come before any later pass reads it. A layout that
|
|
30
31
|
* goes ({@link drop_layout}) withdraws its card sets ({@link onWithdrawn}) back to waiting.
|
|
@@ -121,7 +122,8 @@ export class GPUMeshCardSets {
|
|
|
121
122
|
/**
|
|
122
123
|
* A card set for a pair. The caller keeps one per pair.
|
|
123
124
|
*
|
|
124
|
-
* @param {number} geometry the geometry id
|
|
125
|
+
* @param {number} geometry the geometry id the pair draws; an aliased one's card set captures its source's
|
|
126
|
+
* layout ({@link alias})
|
|
125
127
|
* @param {ShadeMaterial} material
|
|
126
128
|
* @returns {number} card set id
|
|
127
129
|
*/
|
|
@@ -152,6 +154,22 @@ export class GPUMeshCardSets {
|
|
|
152
154
|
* @param {number} geometry
|
|
153
155
|
*/
|
|
154
156
|
drop_layout(geometry: number): void;
|
|
157
|
+
/**
|
|
158
|
+
* The geometry `clone` is drawn as `source` from here on: its card sets, and those acquired for it after, capture
|
|
159
|
+
* `source`'s layout through `source`'s meshlets, the two being in one local space. A card set of `clone` waits
|
|
160
|
+
* for `source`'s layout, as one acquired for `source` does.
|
|
161
|
+
*
|
|
162
|
+
* @param {number} clone
|
|
163
|
+
* @param {number} source
|
|
164
|
+
*/
|
|
165
|
+
alias(clone: number, source: number): void;
|
|
166
|
+
/**
|
|
167
|
+
* `clone` is no longer aliased: card sets acquired for it from here on capture its own layout. Those it has keep
|
|
168
|
+
* capturing its source's until they are given back.
|
|
169
|
+
*
|
|
170
|
+
* @param {number} clone
|
|
171
|
+
*/
|
|
172
|
+
unalias(clone: number): void;
|
|
155
173
|
/**
|
|
156
174
|
* Record the frame's capture: at most `budget` pages. Records nothing when nothing waits. Card
|
|
157
175
|
* sets whose first capture this completes are resident from here, and {@link onResident} is sent
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GPUMeshCardSets.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js"],"names":[],"mappings":"AAyEA;;;;;;GAMG;AACH,sDAHW,aAAa,GACX,MAAM,CAUlB;AApCD;;;GAGG;AACH,2CAFU,MAAM,CAEmF;AA0DnG
|
|
1
|
+
{"version":3,"file":"GPUMeshCardSets.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js"],"names":[],"mappings":"AAyEA;;;;;;GAMG;AACH,sDAHW,aAAa,GACX,MAAM,CAUlB;AApCD;;;GAGG;AACH,2CAFU,MAAM,CAEmF;AA0DnG;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH;IAiMI;;OAEG;IACH,+BAIC;IAjMD;;;OAGG;IACH,gBAA0B;IAE1B;;;OAGG;IACH,iBAA2B;IAyL3B;;;OAGG;IACH,oBAUC;IAED;;OAEG;IACH,6BAEC;IAED;;;OAGG;IACH,mCAEC;IAED;;;OAGG;IACH,6BAEC;IAED;;;;OAIG;IACH,mCAIC;IAED;;;OAGG;IACH,2BAcC;IASD;;;;;OAKG;IACH,+BAgBC;IA7BD;;OAEG;IACH,2BAEC;IA0BD;;;;;OAKG;IACH,gBAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;;;OAKG;IACH,gBAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,yBAIC;IAED;;;OAGG;IACH,4BAIC;IAED;;;;;;;OAOG;IACH,kBALW,MAAM,YAEN,aAAa,GACX,MAAM,CAiClB;IAED;;OAEG;IACH,YAFW,MAAM,QA2BhB;IAED;;;;;OAKG;IACH,cAFW,MAAM,QAqBhB;IAED;;;;;;;OAOG;IACH,qBALW,MAAM,SACN,MAAM,QACN,MAAM,QAqBhB;IAED;;;;OAIG;IACH,sBAFW,MAAM,QA+BhB;IAED;;;;;;;OAOG;IACH,aAHW,MAAM,UACN,MAAM,QAoChB;IAED;;;;;OAKG;IACH,eAFW,MAAM,QAIhB;IA0SD;;;;;;;;;;;;;;;;OAgBG;IACH;QAX+B,KAAK,EAAzB,UAAU;QACM,MAAM,EAAtB,MAAM;QACU,KAAK,EAArB,MAAM;QACa,OAAO;QACU,SAAS,EAA7C,0BAA0B;QAEE,iBAAiB,EAA7C,kBAAkB;QAEF,IAAI;aAsG9B;IAiTD;;OAEG;IACH,+BAuBC;IAED,gBAoBC;;CACJ;yBA95CY,OAAO,iEAAiE,EAAE,UAAU;4BACpF,OAAO,oCAAoC,EAAE,aAAa;yCAC1D,OAAO,0DAA0D,EAAE,0BAA0B;iCAC7F,OAAO,yCAAyC,EAAE,kBAAkB;iCACpE,OAAO,yCAAyC,EAAE,kBAAkB;yBACpE,OAAO,yDAAyD,EAAE,UAAU;+BAxB1D,0CAA0C"}
|
|
@@ -125,7 +125,8 @@ function grow_typed(array, length) {
|
|
|
125
125
|
* - Its record (`MESH_CARD_SET_STRUCT`) is written when a capture starts.
|
|
126
126
|
*
|
|
127
127
|
* **Lifetime.** {@link acquire} makes a card set for a pair and {@link release} gives it back; the
|
|
128
|
-
* caller keeps one per pair. A card set
|
|
128
|
+
* caller keeps one per pair. A card set of an aliased geometry ({@link alias}) is its source's: it
|
|
129
|
+
* captures the source's layout through the source's meshlets. A card set waits until its geometry's layout is placed
|
|
129
130
|
* ({@link set_layout}), is then captured, and turns resident ({@link onResident}) on the frame its
|
|
130
131
|
* last page is recorded: the capture's writes come before any later pass reads it. A layout that
|
|
131
132
|
* goes ({@link drop_layout}) withdraws its card sets ({@link onWithdrawn}) back to waiting.
|
|
@@ -160,6 +161,12 @@ export class GPUMeshCardSets {
|
|
|
160
161
|
|
|
161
162
|
#ids = new IdPool();
|
|
162
163
|
|
|
164
|
+
/**
|
|
165
|
+
* The source of each aliased geometry id.
|
|
166
|
+
* @type {Map<number, number>}
|
|
167
|
+
*/
|
|
168
|
+
#source_of = new Map();
|
|
169
|
+
|
|
163
170
|
// ---- per card set id ----
|
|
164
171
|
|
|
165
172
|
#state = new Uint8Array(64);
|
|
@@ -479,7 +486,8 @@ export class GPUMeshCardSets {
|
|
|
479
486
|
/**
|
|
480
487
|
* A card set for a pair. The caller keeps one per pair.
|
|
481
488
|
*
|
|
482
|
-
* @param {number} geometry the geometry id
|
|
489
|
+
* @param {number} geometry the geometry id the pair draws; an aliased one's card set captures its source's
|
|
490
|
+
* layout ({@link alias})
|
|
483
491
|
* @param {ShadeMaterial} material
|
|
484
492
|
* @returns {number} card set id
|
|
485
493
|
*/
|
|
@@ -487,6 +495,8 @@ export class GPUMeshCardSets {
|
|
|
487
495
|
assert.isNonNegativeInteger(geometry, 'geometry');
|
|
488
496
|
assert.defined(material, 'material');
|
|
489
497
|
|
|
498
|
+
geometry = this.#source_of.get(geometry) ?? geometry;
|
|
499
|
+
|
|
490
500
|
const id = this.#ids.get();
|
|
491
501
|
|
|
492
502
|
this.#ensure_id(id);
|
|
@@ -635,6 +645,60 @@ export class GPUMeshCardSets {
|
|
|
635
645
|
}
|
|
636
646
|
}
|
|
637
647
|
|
|
648
|
+
/**
|
|
649
|
+
* The geometry `clone` is drawn as `source` from here on: its card sets, and those acquired for it after, capture
|
|
650
|
+
* `source`'s layout through `source`'s meshlets, the two being in one local space. A card set of `clone` waits
|
|
651
|
+
* for `source`'s layout, as one acquired for `source` does.
|
|
652
|
+
*
|
|
653
|
+
* @param {number} clone
|
|
654
|
+
* @param {number} source
|
|
655
|
+
*/
|
|
656
|
+
alias(clone, source) {
|
|
657
|
+
assert.notEqual(clone, source, 'a geometry cannot alias itself');
|
|
658
|
+
|
|
659
|
+
this.#source_of.set(clone, source);
|
|
660
|
+
|
|
661
|
+
// its own layout, if it had one, went with its cache: what it has waits
|
|
662
|
+
this.drop_layout(clone);
|
|
663
|
+
|
|
664
|
+
const sets = this.#sets_of_geometry.get(clone);
|
|
665
|
+
|
|
666
|
+
if (sets === undefined) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
this.#sets_of_geometry.delete(clone);
|
|
671
|
+
|
|
672
|
+
for (let i = 0; i < sets.length; i++) {
|
|
673
|
+
const id = sets[i];
|
|
674
|
+
|
|
675
|
+
this.#geometry[id] = source;
|
|
676
|
+
|
|
677
|
+
let of_source = this.#sets_of_geometry.get(source);
|
|
678
|
+
|
|
679
|
+
if (of_source === undefined) {
|
|
680
|
+
of_source = [];
|
|
681
|
+
this.#sets_of_geometry.set(source, of_source);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
of_source.push(id);
|
|
685
|
+
|
|
686
|
+
if (this.#layout_pages.has(source)) {
|
|
687
|
+
this.#start(id);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* `clone` is no longer aliased: card sets acquired for it from here on capture its own layout. Those it has keep
|
|
694
|
+
* capturing its source's until they are given back.
|
|
695
|
+
*
|
|
696
|
+
* @param {number} clone
|
|
697
|
+
*/
|
|
698
|
+
unalias(clone) {
|
|
699
|
+
this.#source_of.delete(clone);
|
|
700
|
+
}
|
|
701
|
+
|
|
638
702
|
/**
|
|
639
703
|
* Pages from the atlas for a card set whose layout is placed, and its first capture queued.
|
|
640
704
|
*
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The triangles a virtual geometry's proxy is cut to by default: {@link VGEO_PROXY_TRIANGLE_SHARE} of the source's,
|
|
3
|
+
* at least one cluster's and at most {@link VGEO_PROXY_TRIANGLE_MAX}.
|
|
4
|
+
*
|
|
5
|
+
* @param {number} source_triangles
|
|
6
|
+
* @returns {number}
|
|
7
|
+
*/
|
|
8
|
+
export function vgeo_proxy_triangle_limit(source_triangles: number): number;
|
|
9
|
+
/**
|
|
10
|
+
* The share of the source's triangles a proxy keeps by default.
|
|
11
|
+
* @type {number}
|
|
12
|
+
*/
|
|
13
|
+
export const VGEO_PROXY_TRIANGLE_SHARE: number;
|
|
14
|
+
/**
|
|
15
|
+
* Most triangles a proxy has by default, however large the source.
|
|
16
|
+
* @type {number}
|
|
17
|
+
*/
|
|
18
|
+
export const VGEO_PROXY_TRIANGLE_MAX: number;
|
|
19
|
+
//# sourceMappingURL=vgeo_proxy_triangle_limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vgeo_proxy_triangle_limit.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.js"],"names":[],"mappings":"AAeA;;;;;;GAMG;AACH,4DAHW,MAAM,GACJ,MAAM,CAIlB;AArBD;;;GAGG;AACH,wCAFU,MAAM,CAE8B;AAE9C;;;GAGG;AACH,sCAFU,MAAM,CAE6B"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { clamp } from "../../../../../core/math/clamp.js";
|
|
2
|
+
import { VGEO_MAX_CLUSTER_TRIANGLE_COUNT } from "../format/cluster/VGEO_MAX_CLUSTER_TRIANGLE_COUNT.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The share of the source's triangles a proxy keeps by default.
|
|
6
|
+
* @type {number}
|
|
7
|
+
*/
|
|
8
|
+
export const VGEO_PROXY_TRIANGLE_SHARE = 0.01;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Most triangles a proxy has by default, however large the source.
|
|
12
|
+
* @type {number}
|
|
13
|
+
*/
|
|
14
|
+
export const VGEO_PROXY_TRIANGLE_MAX = 64000;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The triangles a virtual geometry's proxy is cut to by default: {@link VGEO_PROXY_TRIANGLE_SHARE} of the source's,
|
|
18
|
+
* at least one cluster's and at most {@link VGEO_PROXY_TRIANGLE_MAX}.
|
|
19
|
+
*
|
|
20
|
+
* @param {number} source_triangles
|
|
21
|
+
* @returns {number}
|
|
22
|
+
*/
|
|
23
|
+
export function vgeo_proxy_triangle_limit(source_triangles) {
|
|
24
|
+
return Math.floor(clamp(source_triangles * VGEO_PROXY_TRIANGLE_SHARE, VGEO_MAX_CLUSTER_TRIANGLE_COUNT, VGEO_PROXY_TRIANGLE_MAX));
|
|
25
|
+
}
|
|
@@ -36,7 +36,22 @@ export class VirtualGeometry extends MeshletGeometry {
|
|
|
36
36
|
* @type {number}
|
|
37
37
|
*/
|
|
38
38
|
vg_row: number;
|
|
39
|
+
/**
|
|
40
|
+
* An ordinary geometry standing in for this one where a plain mesh is needed: what its geometry cache is baked
|
|
41
|
+
* from and its cards are drawn from. A cut of the container ({@link vgeo_to_proxy_mesh}) at
|
|
42
|
+
* {@link vgeo_proxy_triangle_limit} of the source's triangles, in the geometry's own space, with its attributes;
|
|
43
|
+
* asked for once, and the same proxy every time after.
|
|
44
|
+
*
|
|
45
|
+
* TODO: a container is expected to be delivered with its proxy, baked offline, and the proxy loaded here. Until
|
|
46
|
+
* then it is cut here, through a reader of its own over the container's bytes: the shared {@link reader}'s pages
|
|
47
|
+
* are its residency's, and the cut would install pages behind that residency's budget.
|
|
48
|
+
*
|
|
49
|
+
* @returns {Promise<MeshletGeometry>}
|
|
50
|
+
*/
|
|
51
|
+
get_proxy(): Promise<MeshletGeometry>;
|
|
39
52
|
isVirtualGeometry: boolean;
|
|
53
|
+
#private;
|
|
40
54
|
}
|
|
41
55
|
import { MeshletGeometry } from "../../MeshletGeometry.js";
|
|
56
|
+
import { VGeoContainerReader } from "../format/read/VGeoContainerReader.js";
|
|
42
57
|
//# sourceMappingURL=VirtualGeometry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualGeometry.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VirtualGeometry.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;IAqBI;;OAEG;IACH,oBAFW,mBAAmB,EAuB7B;IA5CD;;;;OAIG;IACH,QAFU,mBAAmB,CAEtB;IAEP;;;;OAIG;IACH,QAFU,MAAM,CAEgB;IAkChC;;;;;;;;;;;OAWG;IACH,aAFa,QAAQ,eAAe,CAAC,CAQpC;IAwCL,2BAA2C;;CAF1C;gCAlI+B,0BAA0B;oCACtB,uCAAuC"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { assert } from "../../../../../core/assert.js";
|
|
2
2
|
import { MeshletGeometry } from "../../MeshletGeometry.js";
|
|
3
|
+
import { VGeoContainerReader } from "../format/read/VGeoContainerReader.js";
|
|
4
|
+
import { vgeo_proxy_triangle_limit } from "../proxy/vgeo_proxy_triangle_limit.js";
|
|
5
|
+
import { vgeo_to_proxy_mesh } from "../proxy/vgeo_to_proxy_mesh.js";
|
|
3
6
|
import { VGEO_GEOMETRY_ROW_NONE } from "./layout/VGEO_GEOMETRY_ROW_NONE.js";
|
|
4
7
|
|
|
5
8
|
/**
|
|
@@ -38,6 +41,12 @@ export class VirtualGeometry extends MeshletGeometry {
|
|
|
38
41
|
*/
|
|
39
42
|
vg_row = VGEO_GEOMETRY_ROW_NONE;
|
|
40
43
|
|
|
44
|
+
/**
|
|
45
|
+
* The proxy, once asked for.
|
|
46
|
+
* @type {Promise<MeshletGeometry>|null}
|
|
47
|
+
*/
|
|
48
|
+
#proxy = null;
|
|
49
|
+
|
|
41
50
|
/**
|
|
42
51
|
* @param {VGeoContainerReader} reader an open container
|
|
43
52
|
*/
|
|
@@ -64,6 +73,35 @@ export class VirtualGeometry extends MeshletGeometry {
|
|
|
64
73
|
this.primitive_count = Number(header.source_face_count);
|
|
65
74
|
}
|
|
66
75
|
|
|
76
|
+
/**
|
|
77
|
+
* An ordinary geometry standing in for this one where a plain mesh is needed: what its geometry cache is baked
|
|
78
|
+
* from and its cards are drawn from. A cut of the container ({@link vgeo_to_proxy_mesh}) at
|
|
79
|
+
* {@link vgeo_proxy_triangle_limit} of the source's triangles, in the geometry's own space, with its attributes;
|
|
80
|
+
* asked for once, and the same proxy every time after.
|
|
81
|
+
*
|
|
82
|
+
* TODO: a container is expected to be delivered with its proxy, baked offline, and the proxy loaded here. Until
|
|
83
|
+
* then it is cut here, through a reader of its own over the container's bytes: the shared {@link reader}'s pages
|
|
84
|
+
* are its residency's, and the cut would install pages behind that residency's budget.
|
|
85
|
+
*
|
|
86
|
+
* @returns {Promise<MeshletGeometry>}
|
|
87
|
+
*/
|
|
88
|
+
get_proxy() {
|
|
89
|
+
if (this.#proxy === null) {
|
|
90
|
+
this.#proxy = this.#cut_proxy();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return this.#proxy;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @returns {Promise<MeshletGeometry>}
|
|
98
|
+
*/
|
|
99
|
+
async #cut_proxy() {
|
|
100
|
+
const reader = await VGeoContainerReader.open(this.reader.source);
|
|
101
|
+
|
|
102
|
+
return vgeo_to_proxy_mesh(reader, vgeo_proxy_triangle_limit(this.primitive_count));
|
|
103
|
+
}
|
|
104
|
+
|
|
67
105
|
/**
|
|
68
106
|
* A virtual geometry's identity is its **container**, not its meshlets.
|
|
69
107
|
*
|