@drawcall/lod 0.1.2 → 0.2.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/README.md +10 -69
- package/dist/at.d.ts +2 -0
- package/dist/at.js +8 -0
- package/dist/at.js.map +1 -0
- package/dist/baked/codec.d.ts +6 -3
- package/dist/baked/codec.js +22 -16
- package/dist/baked/codec.js.map +1 -1
- package/dist/baked/index.d.ts +4 -0
- package/dist/baked/index.js +2 -2
- package/dist/baked/index.js.map +1 -1
- package/dist/baked/low.d.ts +2 -2
- package/dist/baked/low.js +4 -4
- package/dist/baked/low.js.map +1 -1
- package/dist/bounds.d.ts +12 -2
- package/dist/bounds.js +72 -10
- package/dist/bounds.js.map +1 -1
- package/dist/compile.d.ts +4 -0
- package/dist/compile.js +100 -0
- package/dist/compile.js.map +1 -0
- package/dist/deferred.d.ts +12 -0
- package/dist/deferred.js +27 -0
- package/dist/deferred.js.map +1 -0
- package/dist/dispose.d.ts +7 -3
- package/dist/dispose.js +33 -4
- package/dist/dispose.js.map +1 -1
- package/dist/fade.d.ts +5 -13
- package/dist/fade.js +62 -28
- package/dist/fade.js.map +1 -1
- package/dist/impostor/bake/index.d.ts +1 -0
- package/dist/impostor/bake/index.js +1 -0
- package/dist/impostor/bake/index.js.map +1 -1
- package/dist/impostor/bake/materials.js +11 -1
- package/dist/impostor/bake/materials.js.map +1 -1
- package/dist/impostor/codec.d.ts +2 -7
- package/dist/impostor/codec.js +16 -27
- package/dist/impostor/codec.js.map +1 -1
- package/dist/impostor/mesh/card.js +4 -1
- package/dist/impostor/mesh/card.js.map +1 -1
- package/dist/impostor/mesh/index.d.ts +6 -4
- package/dist/impostor/mesh/index.js +8 -10
- package/dist/impostor/mesh/index.js.map +1 -1
- package/dist/impostor/mesh/material.d.ts +7 -5
- package/dist/impostor/mesh/material.js +29 -26
- package/dist/impostor/mesh/material.js.map +1 -1
- package/dist/impostor/mesh/surface.d.ts +20 -16
- package/dist/impostor/mesh/surface.js +74 -55
- package/dist/impostor/mesh/surface.js.map +1 -1
- package/dist/impostor/octahedral.d.ts +1 -8
- package/dist/impostor/octahedral.js +3 -18
- package/dist/impostor/octahedral.js.map +1 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/instanced/args.js +2 -2
- package/dist/instanced/args.js.map +1 -1
- package/dist/instanced/{bounds.d.ts → blocks.d.ts} +25 -9
- package/dist/instanced/{bounds.js → blocks.js} +76 -53
- package/dist/instanced/blocks.js.map +1 -0
- package/dist/instanced/dirty.d.ts +3 -0
- package/dist/instanced/dirty.js +40 -5
- package/dist/instanced/dirty.js.map +1 -1
- package/dist/instanced/index.d.ts +25 -51
- package/dist/instanced/index.js +189 -413
- package/dist/instanced/index.js.map +1 -1
- package/dist/instanced/meshes.d.ts +54 -13
- package/dist/instanced/meshes.js +178 -41
- package/dist/instanced/meshes.js.map +1 -1
- package/dist/instanced/parts.d.ts +14 -0
- package/dist/instanced/parts.js +79 -0
- package/dist/instanced/parts.js.map +1 -0
- package/dist/instanced/raycast.d.ts +13 -0
- package/dist/instanced/raycast.js +53 -0
- package/dist/instanced/raycast.js.map +1 -0
- package/dist/instanced/select.d.ts +17 -9
- package/dist/instanced/select.js +114 -63
- package/dist/instanced/select.js.map +1 -1
- package/dist/instanced/store.d.ts +31 -0
- package/dist/instanced/store.js +96 -0
- package/dist/instanced/store.js.map +1 -0
- package/dist/levels.d.ts +71 -48
- package/dist/levels.js +99 -74
- package/dist/levels.js.map +1 -1
- package/dist/loader/bundle.d.ts +25 -0
- package/dist/loader/bundle.js +241 -0
- package/dist/loader/bundle.js.map +1 -0
- package/dist/loader/cache.d.ts +15 -15
- package/dist/loader/cache.js +71 -33
- package/dist/loader/cache.js.map +1 -1
- package/dist/loader/provenance.d.ts +30 -0
- package/dist/loader/provenance.js +105 -0
- package/dist/loader/provenance.js.map +1 -0
- package/dist/loader/url.d.ts +13 -0
- package/dist/loader/url.js +31 -0
- package/dist/loader/url.js.map +1 -0
- package/dist/loader.d.ts +30 -74
- package/dist/loader.js +191 -186
- package/dist/loader.js.map +1 -1
- package/dist/lod.d.ts +20 -31
- package/dist/lod.js +105 -96
- package/dist/lod.js.map +1 -1
- package/dist/material.js +9 -4
- package/dist/material.js.map +1 -1
- package/dist/mesh/codec.d.ts +4 -0
- package/dist/mesh/codec.js +192 -0
- package/dist/mesh/codec.js.map +1 -0
- package/dist/queue.d.ts +2 -0
- package/dist/queue.js +33 -0
- package/dist/queue.js.map +1 -0
- package/dist/residency.d.ts +44 -0
- package/dist/residency.js +205 -0
- package/dist/residency.js.map +1 -0
- package/dist/simplify.js +5 -3
- package/dist/simplify.js.map +1 -1
- package/dist/source/{error.d.ts → deviation.d.ts} +3 -3
- package/dist/source/{error.js → deviation.js} +6 -6
- package/dist/source/deviation.js.map +1 -0
- package/dist/source/source.d.ts +1 -1
- package/dist/source/source.js +1 -1
- package/dist/three.d.ts +17 -5
- package/dist/three.js +24 -3
- package/dist/three.js.map +1 -1
- package/dist/tsl.d.ts +5 -5
- package/dist/tsl.js +12 -19
- package/dist/tsl.js.map +1 -1
- package/dist/view.d.ts +16 -1
- package/dist/view.js +57 -1
- package/dist/view.js.map +1 -1
- package/dist/wind/index.d.ts +2 -2
- package/dist/wind/index.js +31 -28
- package/dist/wind/index.js.map +1 -1
- package/dist/wind/sway.d.ts +2 -1
- package/package.json +9 -3
- package/skills/lod/SKILL.md +71 -109
- package/dist/impostor/cache.d.ts +0 -15
- package/dist/impostor/cache.js +0 -44
- package/dist/impostor/cache.js.map +0 -1
- package/dist/instanced/bounds.js.map +0 -1
- package/dist/lazy.d.ts +0 -64
- package/dist/lazy.js +0 -187
- package/dist/lazy.js.map +0 -1
- package/dist/loader/dispose.d.ts +0 -3
- package/dist/loader/dispose.js +0 -25
- package/dist/loader/dispose.js.map +0 -1
- package/dist/source/error.js.map +0 -1
package/dist/levels.d.ts
CHANGED
|
@@ -1,68 +1,85 @@
|
|
|
1
|
-
import { Color, type Object3D } from "three/webgpu";
|
|
2
|
-
/**
|
|
3
|
-
* A fade dithers over the top of a level's range: from maxPixels × (1 - FADE) to
|
|
4
|
-
* maxPixels. Instances inside it draw twice; a narrower fade pops no more visibly, as
|
|
5
|
-
* the dither spreads the switch over the frames an approach takes to cross it.
|
|
6
|
-
*/
|
|
1
|
+
import { Color, type Box3, type Object3D } from "three/webgpu";
|
|
2
|
+
/** Share of each level's range over which its finer neighbour fades out. */
|
|
7
3
|
export declare const FADE = 0.1;
|
|
8
|
-
/**
|
|
9
|
-
export
|
|
10
|
-
|
|
4
|
+
/** A reusable level description. Deferred objects arrive already placed in the owner's space. */
|
|
5
|
+
export type LodLevel = {
|
|
6
|
+
object: Object3D;
|
|
7
|
+
maxPixels?: number;
|
|
8
|
+
load?: never;
|
|
9
|
+
box?: never;
|
|
10
|
+
} | {
|
|
11
|
+
load: () => Promise<Object3D>;
|
|
12
|
+
maxPixels: number;
|
|
13
|
+
box: Box3;
|
|
14
|
+
object?: never;
|
|
15
|
+
};
|
|
16
|
+
/** One level of an owner, as `Lod.levels` and `InstancedLod.levels` show it. */
|
|
17
|
+
export interface LevelView {
|
|
18
|
+
/** Level 0 is the source. */
|
|
19
|
+
readonly index: number;
|
|
20
|
+
/**
|
|
21
|
+
* The level's object, undefined until a deferred level has arrived. For a Lod it is
|
|
22
|
+
* drawn, and its visibility is the Lod's switch. For an InstancedLod it is the template
|
|
23
|
+
* the level's instanced meshes are made from: never in the scene, so `levelOf` tells
|
|
24
|
+
* what draws.
|
|
25
|
+
*/
|
|
26
|
+
readonly object: Object3D | undefined;
|
|
27
|
+
/** A deferred level's bounds in the owner's space. */
|
|
28
|
+
readonly box: Box3 | undefined;
|
|
11
29
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* Unless set, it is where the level is about a pixel off: for a level `simplify` or
|
|
18
|
-
* `bakeMesh` returned, where its measured error reaches a pixel (a clone you make of
|
|
19
|
-
* it does not carry the error; a cloned Lod keeps it); for an ImpostorMesh, where two
|
|
20
|
-
* atlas texels span one pixel; else half the previous level's (512 px for level 1).
|
|
21
|
-
* Such defaults are raised to twice the next level's where they would leave no room
|
|
22
|
-
* for the fades.
|
|
30
|
+
* Largest on-screen height, in CSS pixels × Lod.quality, at which this level draws.
|
|
31
|
+
* Level 0 is Infinity. Every later threshold must be at most 0.9 of its predecessor.
|
|
32
|
+
* Defaults use measured surface deviation, impostor texels, or half the previous
|
|
33
|
+
* threshold (512 for level 1), raised where needed to leave room for fades.
|
|
23
34
|
*/
|
|
24
35
|
maxPixels: number;
|
|
25
36
|
}
|
|
26
|
-
|
|
27
|
-
|
|
37
|
+
/** One owner's resolved threshold and drawable, separate from its reusable description. */
|
|
38
|
+
export declare class Level implements LevelView {
|
|
39
|
+
readonly input: LodLevel;
|
|
28
40
|
readonly index: number;
|
|
29
|
-
/** A nested LOD switches its own levels and fades by them, not by its parent. */
|
|
30
|
-
readonly nested: boolean;
|
|
31
|
-
/** The levels this one is in, which its default depends on. */
|
|
32
41
|
private readonly ladder;
|
|
33
|
-
/** Debug tint (see `Lod.debug`), white when off; shared by every draw of the level. */
|
|
34
42
|
readonly tint: Color;
|
|
35
|
-
|
|
43
|
+
readonly box: Box3 | undefined;
|
|
44
|
+
object: Object3D | undefined;
|
|
45
|
+
nested: boolean;
|
|
36
46
|
explicit: number | null;
|
|
37
|
-
/** The default before raising for the fades: see `resolve`. */
|
|
38
47
|
base: number;
|
|
39
|
-
/** maxPixels as resolved; see `resolve` */
|
|
40
48
|
value: number;
|
|
41
|
-
constructor(
|
|
42
|
-
/** A nested LOD switches its own levels and fades by them, not by its parent. */
|
|
43
|
-
nested: boolean,
|
|
44
|
-
/** The levels this one is in, which its default depends on. */
|
|
45
|
-
ladder: readonly Level[]);
|
|
49
|
+
constructor(input: LodLevel, index: number, ladder: readonly Level[]);
|
|
46
50
|
get maxPixels(): number;
|
|
47
51
|
set maxPixels(value: number);
|
|
48
52
|
}
|
|
49
|
-
/**
|
|
50
|
-
export declare const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
*/
|
|
53
|
+
/** Surface deviation from the source, in the source's units. */
|
|
54
|
+
export declare const recordDeviation: (level: Object3D, deviation: number) => void;
|
|
55
|
+
export declare const deviationOf: (level: Object3D) => number | undefined;
|
|
56
|
+
/** Descriptions for a new owner, retaining threshold edits and sharing deferred decode. */
|
|
57
|
+
export declare function cloneLevels(levels: readonly Level[]): LodLevel[];
|
|
58
|
+
/** What a level's default threshold is measured from: surface deviation, else impostor texels. */
|
|
59
|
+
interface Measured {
|
|
60
|
+
deviation?: number;
|
|
61
|
+
texels?: number;
|
|
62
|
+
}
|
|
63
|
+
export declare function measure(object: Object3D): Measured;
|
|
64
|
+
/** A level to resolve: `measured` is absent for a deferred level, whose own maxPixels stands in. */
|
|
65
|
+
interface Measurable {
|
|
66
|
+
maxPixels?: number;
|
|
67
|
+
measured?: Measured;
|
|
68
|
+
}
|
|
69
|
+
/** Resolve thresholds from measurements without constructing renderer state. */
|
|
70
|
+
export declare function resolveThresholds(levels: readonly Measurable[], diameter: number): number[];
|
|
71
|
+
/** Resolve defaults once, retaining writable owner thresholds. */
|
|
61
72
|
export declare function estimate(levels: readonly Level[], diameter: number): void;
|
|
62
|
-
/** Throws
|
|
63
|
-
export declare function validate(levels: readonly
|
|
73
|
+
/** Throws when neighbouring fades overlap. */
|
|
74
|
+
export declare function validate(levels: readonly {
|
|
75
|
+
maxPixels: number;
|
|
76
|
+
}[]): void;
|
|
64
77
|
/** The level drawn at `height`: the last one it fits, or `forceLevel`. */
|
|
65
78
|
export declare function levelAt(levels: readonly Level[], height: number, forceLevel: number | null): Level;
|
|
79
|
+
/** The coarsest level whose maxPixels `height` still fits; level 0 fits any height. */
|
|
80
|
+
export declare function lastFitting(levels: readonly {
|
|
81
|
+
maxPixels: number;
|
|
82
|
+
}[], height: number): number;
|
|
66
83
|
/**
|
|
67
84
|
* How far `level` has faded in over its finer neighbour at `height`, in [0, 1): 0 when
|
|
68
85
|
* no fade is under way (the finer level is gone). See fade.ts for how both draw it.
|
|
@@ -70,3 +87,9 @@ export declare function levelAt(levels: readonly Level[], height: number, forceL
|
|
|
70
87
|
export declare function fadeProgress(levels: readonly Level[], level: Level, height: number): number;
|
|
71
88
|
/** Give each level its debug tint, or white. */
|
|
72
89
|
export declare function tintLevels(levels: readonly Level[], debug: boolean): void;
|
|
90
|
+
export declare const DEMAND = 0.8;
|
|
91
|
+
/** Logical demand and the next finer fade partner, including a small approach margin. */
|
|
92
|
+
export declare function demandLevels(levels: readonly Level[], height: number, forced: number | null): Level[];
|
|
93
|
+
/** Nearest ready finer level, else nearest coarser; -1 draws nothing until one is ready. */
|
|
94
|
+
export declare function fallbacks(levels: readonly Level[], ready: ReadonlySet<Level>): number[];
|
|
95
|
+
export {};
|
package/dist/levels.js
CHANGED
|
@@ -1,106 +1,110 @@
|
|
|
1
1
|
import { Color } from "three/webgpu";
|
|
2
2
|
import { texelPixels } from "./impostor/impostor.js";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A fade dithers over the top of a level's range: from maxPixels × (1 - FADE) to
|
|
8
|
-
* maxPixels. Instances inside it draw twice; a narrower fade pops no more visibly, as
|
|
9
|
-
* the dither spreads the switch over the frames an approach takes to cross it.
|
|
10
|
-
*/
|
|
3
|
+
import { isImpostorMesh, isLOD } from "./three.js";
|
|
4
|
+
import { at } from "./at.js";
|
|
5
|
+
/** Share of each level's range over which its finer neighbour fades out. */
|
|
11
6
|
export const FADE = 0.1;
|
|
7
|
+
/** One owner's resolved threshold and drawable, separate from its reusable description. */
|
|
12
8
|
export class Level {
|
|
13
|
-
|
|
9
|
+
input;
|
|
14
10
|
index;
|
|
15
|
-
nested;
|
|
16
11
|
ladder;
|
|
17
|
-
/** Debug tint (see `Lod.debug`), white when off; shared by every draw of the level. */
|
|
18
12
|
tint = new Color(1, 1, 1);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
box;
|
|
14
|
+
object;
|
|
15
|
+
nested;
|
|
16
|
+
explicit;
|
|
22
17
|
base = Infinity;
|
|
23
|
-
/** maxPixels as resolved; see `resolve` */
|
|
24
18
|
value = Infinity;
|
|
25
|
-
constructor(
|
|
26
|
-
|
|
27
|
-
nested,
|
|
28
|
-
/** The levels this one is in, which its default depends on. */
|
|
29
|
-
ladder) {
|
|
30
|
-
this.object = object;
|
|
19
|
+
constructor(input, index, ladder) {
|
|
20
|
+
this.input = input;
|
|
31
21
|
this.index = index;
|
|
32
|
-
this.nested = nested;
|
|
33
22
|
this.ladder = ladder;
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
this.explicit = input.maxPixels ?? null;
|
|
24
|
+
if (input.maxPixels !== undefined)
|
|
25
|
+
checkThreshold(input.maxPixels, index);
|
|
26
|
+
this.box = input.box;
|
|
27
|
+
if (this.box && !this.box.isEmpty() && ![...this.box.min.toArray(), ...this.box.max.toArray()].every(Number.isFinite))
|
|
28
|
+
throw new Error("Lod: a deferred level's box must be finite");
|
|
29
|
+
this.object = input.object?.clone();
|
|
30
|
+
this.nested = this.object ? isLOD(this.object) : false;
|
|
36
31
|
}
|
|
37
32
|
get maxPixels() {
|
|
38
33
|
return this.value;
|
|
39
34
|
}
|
|
40
35
|
set maxPixels(value) {
|
|
41
|
-
|
|
42
|
-
throw new Error(`Lod: level 0, the source, is used at any height: its maxPixels is Infinity, not ${value}`);
|
|
43
|
-
if (this.index === 0)
|
|
44
|
-
return;
|
|
45
|
-
if (!(value > 0))
|
|
46
|
-
throw new Error(`Lod: maxPixels must be > 0, got ${value}`);
|
|
36
|
+
checkThreshold(value, this.index);
|
|
47
37
|
this.explicit = value;
|
|
48
38
|
resolve(this.ladder);
|
|
49
39
|
}
|
|
50
40
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
41
|
+
function checkThreshold(value, index) {
|
|
42
|
+
if (index === 0 && value !== Infinity)
|
|
43
|
+
throw new Error(`Lod: level 0, the source, is used at any height: its maxPixels is Infinity, not ${value}`);
|
|
44
|
+
if (!(value > 0))
|
|
45
|
+
throw new Error(`Lod: maxPixels must be > 0, got ${value}`);
|
|
46
|
+
}
|
|
47
|
+
const deviations = new WeakMap();
|
|
48
|
+
/** Surface deviation from the source, in the source's units. */
|
|
49
|
+
export const recordDeviation = (level, deviation) => void deviations.set(level, deviation);
|
|
50
|
+
export const deviationOf = (level) => deviations.get(level);
|
|
51
|
+
/** Descriptions for a new owner, retaining threshold edits and sharing deferred decode. */
|
|
58
52
|
export function cloneLevels(levels) {
|
|
59
|
-
return levels.map((
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return clone;
|
|
53
|
+
return levels.map((level) => {
|
|
54
|
+
const { input, explicit } = level;
|
|
55
|
+
if (input.load)
|
|
56
|
+
return { ...input, maxPixels: level.maxPixels };
|
|
57
|
+
return { object: input.object, ...(explicit === null ? {} : { maxPixels: explicit }) };
|
|
65
58
|
});
|
|
66
59
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
60
|
+
export function measure(object) {
|
|
61
|
+
return { deviation: deviationOf(object), texels: isImpostorMesh(object) ? texelPixels(object.impostor) : undefined };
|
|
62
|
+
}
|
|
63
|
+
function bases(levels, diameter) {
|
|
64
|
+
let finer = 1024;
|
|
65
|
+
return levels.map(({ maxPixels, measured }, index) => {
|
|
66
|
+
if (index === 0)
|
|
67
|
+
return Infinity;
|
|
68
|
+
const base = !measured
|
|
69
|
+
? maxPixels
|
|
70
|
+
: measured.deviation !== undefined
|
|
71
|
+
? diameter / Math.max(measured.deviation, diameter * 1e-4)
|
|
72
|
+
: (measured.texels ?? finer / 2);
|
|
73
|
+
if (base === undefined)
|
|
74
|
+
throw new Error("Lod: a deferred level needs maxPixels");
|
|
75
|
+
finer = base;
|
|
76
|
+
return base;
|
|
73
77
|
});
|
|
74
78
|
}
|
|
75
|
-
/**
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
/** Resolve thresholds from measurements without constructing renderer state. */
|
|
80
|
+
export function resolveThresholds(levels, diameter) {
|
|
81
|
+
const defaults = bases(levels, diameter);
|
|
82
|
+
const thresholds = levels.map((level, index) => {
|
|
83
|
+
if (level.maxPixels !== undefined)
|
|
84
|
+
checkThreshold(level.maxPixels, index);
|
|
85
|
+
return { index, explicit: level.maxPixels ?? null, base: defaults[index] ?? Infinity, value: Infinity };
|
|
86
|
+
});
|
|
87
|
+
resolve(thresholds);
|
|
88
|
+
validate(thresholds.map(({ value }) => ({ maxPixels: value })));
|
|
89
|
+
return thresholds.map(({ value }) => value);
|
|
90
|
+
}
|
|
91
|
+
/** Resolve defaults once, retaining writable owner thresholds. */
|
|
79
92
|
export function estimate(levels, diameter) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
level.base = level.object.maxPixels;
|
|
85
|
-
else if (error !== undefined)
|
|
86
|
-
level.base = diameter / Math.max(error, diameter * 1e-4);
|
|
87
|
-
else if (isImpostorMesh(level.object))
|
|
88
|
-
level.base = texelPixels(level.object.impostor);
|
|
89
|
-
else
|
|
90
|
-
level.base = finer / 2;
|
|
91
|
-
finer = level.base;
|
|
92
|
-
}
|
|
93
|
+
const defaults = bases(levels.map(({ input }) => ({ maxPixels: input.maxPixels, measured: input.object && measure(input.object) })), diameter);
|
|
94
|
+
levels.forEach((level, index) => {
|
|
95
|
+
level.base = defaults[index] ?? Infinity;
|
|
96
|
+
});
|
|
93
97
|
resolve(levels);
|
|
94
98
|
}
|
|
95
|
-
/** Each level's maxPixels: as set, else its base raised to twice the next level's, from the cheapest up. */
|
|
96
99
|
function resolve(levels) {
|
|
97
100
|
let next = 0;
|
|
98
|
-
for (
|
|
101
|
+
for (let i = levels.length - 1; i >= 0; i--) {
|
|
102
|
+
const level = at(levels, i);
|
|
99
103
|
level.value = level.index === 0 ? Infinity : (level.explicit ?? Math.max(level.base, 2 * next));
|
|
100
104
|
next = level.value;
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
|
-
/** Throws
|
|
107
|
+
/** Throws when neighbouring fades overlap. */
|
|
104
108
|
export function validate(levels) {
|
|
105
109
|
levels.forEach((level, i) => {
|
|
106
110
|
const finer = levels[i - 1];
|
|
@@ -115,12 +119,11 @@ export function levelAt(levels, height, forceLevel) {
|
|
|
115
119
|
throw new Error(`Lod: forceLevel ${forceLevel} is not a level`);
|
|
116
120
|
return level;
|
|
117
121
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (
|
|
122
|
+
/** The coarsest level whose maxPixels `height` still fits; level 0 fits any height. */
|
|
123
|
+
export function lastFitting(levels, height) {
|
|
124
|
+
for (let i = levels.length - 1; i > 0; i--)
|
|
125
|
+
if (height <= at(levels, i).maxPixels)
|
|
122
126
|
return i;
|
|
123
|
-
}
|
|
124
127
|
return 0;
|
|
125
128
|
}
|
|
126
129
|
/**
|
|
@@ -143,4 +146,26 @@ export function tintLevels(levels, debug) {
|
|
|
143
146
|
for (const level of levels)
|
|
144
147
|
level.tint.set(debug ? (TINTS[level.index % TINTS.length] ?? 0xffffff) : 0xffffff);
|
|
145
148
|
}
|
|
149
|
+
// Start refinement 20% below its lower fade bound, leaving time for decode and GPU preparation.
|
|
150
|
+
export const DEMAND = 0.8;
|
|
151
|
+
/** Logical demand and the next finer fade partner, including a small approach margin. */
|
|
152
|
+
export function demandLevels(levels, height, forced) {
|
|
153
|
+
const desired = levelAt(levels, height, forced);
|
|
154
|
+
if (forced !== null)
|
|
155
|
+
return [desired];
|
|
156
|
+
const finer = levels[desired.index - 1];
|
|
157
|
+
return finer && height >= DEMAND * desired.maxPixels * (1 - FADE) ? [desired, finer] : [desired];
|
|
158
|
+
}
|
|
159
|
+
/** Nearest ready finer level, else nearest coarser; -1 draws nothing until one is ready. */
|
|
160
|
+
export function fallbacks(levels, ready) {
|
|
161
|
+
return levels.map((_, index) => {
|
|
162
|
+
for (let finer = index; finer >= 0; finer--)
|
|
163
|
+
if (ready.has(at(levels, finer)))
|
|
164
|
+
return finer;
|
|
165
|
+
for (let coarser = index + 1; coarser < levels.length; coarser++)
|
|
166
|
+
if (ready.has(at(levels, coarser)))
|
|
167
|
+
return coarser;
|
|
168
|
+
return -1;
|
|
169
|
+
});
|
|
170
|
+
}
|
|
146
171
|
//# sourceMappingURL=levels.js.map
|
package/dist/levels.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"levels.js","sourceRoot":"","sources":["../src/levels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"levels.js","sourceRoot":"","sources":["../src/levels.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Object3D } from "three/webgpu";
|
|
2
|
+
import { disposeRejected } from "../dispose.js";
|
|
3
|
+
import { type ImpostorMeshOptions } from "../impostor/mesh/index.js";
|
|
4
|
+
import { type LodLevel } from "../levels.js";
|
|
5
|
+
import type { LevelRequest } from "../loader.js";
|
|
6
|
+
export type Kind = "source" | LevelRequest["type"];
|
|
7
|
+
/** The ladder indices whose payload is saved as its own entry: every derived drawable level except the inlined coarsest. */
|
|
8
|
+
export declare function separateLevels(kinds: readonly Kind[]): number[];
|
|
9
|
+
/**
|
|
10
|
+
* Inline coarse derived payloads; a source-only request leaves its source deferred. The index
|
|
11
|
+
* keeps what thresholds are measured from, not thresholds or impostor draw options, so changing
|
|
12
|
+
* either reuses the cache. `levels` maps each deferred level index to its payload.
|
|
13
|
+
*/
|
|
14
|
+
export declare function encode(objects: readonly Object3D[], kinds: readonly Kind[]): Promise<{
|
|
15
|
+
index: Uint8Array;
|
|
16
|
+
levels: Map<number, Uint8Array>;
|
|
17
|
+
}>;
|
|
18
|
+
/** What a request sets per level at decode, without changing cached content. */
|
|
19
|
+
interface Requested {
|
|
20
|
+
maxPixels?: number;
|
|
21
|
+
draw?: ImpostorMeshOptions;
|
|
22
|
+
}
|
|
23
|
+
/** Index metadata exposes every drawable level without decoding its payload. `requested` holds level i's request at i. */
|
|
24
|
+
export declare function decode(bytes: Uint8Array, requested: readonly Requested[], loadSource: () => Promise<Object3D>, loadLevel: (index: number) => Promise<Uint8Array>, onLevel?: (object: Object3D, index: number) => void | Promise<void>, release?: typeof disposeRejected): LodLevel[];
|
|
25
|
+
export {};
|