@drawcall/lod 0.0.0-stage → 0.1.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.
Files changed (178) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -2
  3. package/dist/baked/codec.d.ts +10 -0
  4. package/dist/baked/codec.js +291 -0
  5. package/dist/baked/codec.js.map +1 -0
  6. package/dist/baked/coverage.d.ts +3 -0
  7. package/dist/baked/coverage.js +45 -0
  8. package/dist/baked/coverage.js.map +1 -0
  9. package/dist/baked/index.d.ts +51 -0
  10. package/dist/baked/index.js +151 -0
  11. package/dist/baked/index.js.map +1 -0
  12. package/dist/baked/interior/faces.d.ts +26 -0
  13. package/dist/baked/interior/faces.js +105 -0
  14. package/dist/baked/interior/faces.js.map +1 -0
  15. package/dist/baked/interior/material.d.ts +31 -0
  16. package/dist/baked/interior/material.js +157 -0
  17. package/dist/baked/interior/material.js.map +1 -0
  18. package/dist/baked/interior/rooms.d.ts +22 -0
  19. package/dist/baked/interior/rooms.js +78 -0
  20. package/dist/baked/interior/rooms.js.map +1 -0
  21. package/dist/baked/low.d.ts +20 -0
  22. package/dist/baked/low.js +75 -0
  23. package/dist/baked/low.js.map +1 -0
  24. package/dist/baked/raster.d.ts +20 -0
  25. package/dist/baked/raster.js +71 -0
  26. package/dist/baked/raster.js.map +1 -0
  27. package/dist/baked/transfer.d.ts +36 -0
  28. package/dist/baked/transfer.js +243 -0
  29. package/dist/baked/transfer.js.map +1 -0
  30. package/dist/baked/unwrap.d.ts +9 -0
  31. package/dist/baked/unwrap.js +167 -0
  32. package/dist/baked/unwrap.js.map +1 -0
  33. package/dist/baked/xatlas.d.ts +2 -0
  34. package/dist/baked/xatlas.js +31 -0
  35. package/dist/baked/xatlas.js.map +1 -0
  36. package/dist/bounds.d.ts +33 -0
  37. package/dist/bounds.js +127 -0
  38. package/dist/bounds.js.map +1 -0
  39. package/dist/dispose.d.ts +5 -0
  40. package/dist/dispose.js +28 -0
  41. package/dist/dispose.js.map +1 -0
  42. package/dist/fade.d.ts +44 -0
  43. package/dist/fade.js +78 -0
  44. package/dist/fade.js.map +1 -0
  45. package/dist/impostor/bake/atlas.d.ts +51 -0
  46. package/dist/impostor/bake/atlas.js +190 -0
  47. package/dist/impostor/bake/atlas.js.map +1 -0
  48. package/dist/impostor/bake/index.d.ts +50 -0
  49. package/dist/impostor/bake/index.js +221 -0
  50. package/dist/impostor/bake/index.js.map +1 -0
  51. package/dist/impostor/bake/materials.d.ts +29 -0
  52. package/dist/impostor/bake/materials.js +156 -0
  53. package/dist/impostor/bake/materials.js.map +1 -0
  54. package/dist/impostor/bake/source.d.ts +3 -0
  55. package/dist/impostor/bake/source.js +23 -0
  56. package/dist/impostor/bake/source.js.map +1 -0
  57. package/dist/impostor/cache.d.ts +15 -0
  58. package/dist/impostor/cache.js +44 -0
  59. package/dist/impostor/cache.js.map +1 -0
  60. package/dist/impostor/codec.d.ts +14 -0
  61. package/dist/impostor/codec.js +137 -0
  62. package/dist/impostor/codec.js.map +1 -0
  63. package/dist/impostor/impostor.d.ts +67 -0
  64. package/dist/impostor/impostor.js +79 -0
  65. package/dist/impostor/impostor.js.map +1 -0
  66. package/dist/impostor/mesh/card.d.ts +38 -0
  67. package/dist/impostor/mesh/card.js +79 -0
  68. package/dist/impostor/mesh/card.js.map +1 -0
  69. package/dist/impostor/mesh/index.d.ts +66 -0
  70. package/dist/impostor/mesh/index.js +174 -0
  71. package/dist/impostor/mesh/index.js.map +1 -0
  72. package/dist/impostor/mesh/material.d.ts +63 -0
  73. package/dist/impostor/mesh/material.js +199 -0
  74. package/dist/impostor/mesh/material.js.map +1 -0
  75. package/dist/impostor/mesh/surface.d.ts +63 -0
  76. package/dist/impostor/mesh/surface.js +162 -0
  77. package/dist/impostor/mesh/surface.js.map +1 -0
  78. package/dist/impostor/mesh/textures.d.ts +4 -0
  79. package/dist/impostor/mesh/textures.js +37 -0
  80. package/dist/impostor/mesh/textures.js.map +1 -0
  81. package/dist/impostor/octahedral.d.ts +29 -0
  82. package/dist/impostor/octahedral.js +83 -0
  83. package/dist/impostor/octahedral.js.map +1 -0
  84. package/dist/index.d.ts +15 -0
  85. package/dist/index.js +16 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/instanced/args.d.ts +20 -0
  88. package/dist/instanced/args.js +77 -0
  89. package/dist/instanced/args.js.map +1 -0
  90. package/dist/instanced/bounds.d.ts +50 -0
  91. package/dist/instanced/bounds.js +271 -0
  92. package/dist/instanced/bounds.js.map +1 -0
  93. package/dist/instanced/dirty.d.ts +12 -0
  94. package/dist/instanced/dirty.js +61 -0
  95. package/dist/instanced/dirty.js.map +1 -0
  96. package/dist/instanced/index.d.ts +116 -0
  97. package/dist/instanced/index.js +573 -0
  98. package/dist/instanced/index.js.map +1 -0
  99. package/dist/instanced/meshes.d.ts +14 -0
  100. package/dist/instanced/meshes.js +54 -0
  101. package/dist/instanced/meshes.js.map +1 -0
  102. package/dist/instanced/select.d.ts +84 -0
  103. package/dist/instanced/select.js +264 -0
  104. package/dist/instanced/select.js.map +1 -0
  105. package/dist/lazy.d.ts +64 -0
  106. package/dist/lazy.js +187 -0
  107. package/dist/lazy.js.map +1 -0
  108. package/dist/levels.d.ts +72 -0
  109. package/dist/levels.js +146 -0
  110. package/dist/levels.js.map +1 -0
  111. package/dist/loader/cache.d.ts +15 -0
  112. package/dist/loader/cache.js +37 -0
  113. package/dist/loader/cache.js.map +1 -0
  114. package/dist/loader/dispose.d.ts +3 -0
  115. package/dist/loader/dispose.js +25 -0
  116. package/dist/loader/dispose.js.map +1 -0
  117. package/dist/loader.d.ts +99 -0
  118. package/dist/loader.js +234 -0
  119. package/dist/loader.js.map +1 -0
  120. package/dist/lod.d.ts +78 -0
  121. package/dist/lod.js +211 -0
  122. package/dist/lod.js.map +1 -0
  123. package/dist/material.d.ts +12 -0
  124. package/dist/material.js +52 -0
  125. package/dist/material.js.map +1 -0
  126. package/dist/pause.d.ts +6 -0
  127. package/dist/pause.js +20 -0
  128. package/dist/pause.js.map +1 -0
  129. package/dist/renderer.d.ts +21 -0
  130. package/dist/renderer.js +83 -0
  131. package/dist/renderer.js.map +1 -0
  132. package/dist/simplify.d.ts +24 -0
  133. package/dist/simplify.js +148 -0
  134. package/dist/simplify.js.map +1 -0
  135. package/dist/source/error.d.ts +14 -0
  136. package/dist/source/error.js +94 -0
  137. package/dist/source/error.js.map +1 -0
  138. package/dist/source/frame.d.ts +11 -0
  139. package/dist/source/frame.js +25 -0
  140. package/dist/source/frame.js.map +1 -0
  141. package/dist/source/shading.d.ts +96 -0
  142. package/dist/source/shading.js +224 -0
  143. package/dist/source/shading.js.map +1 -0
  144. package/dist/source/source.d.ts +23 -0
  145. package/dist/source/source.js +50 -0
  146. package/dist/source/source.js.map +1 -0
  147. package/dist/source/surface.d.ts +31 -0
  148. package/dist/source/surface.js +110 -0
  149. package/dist/source/surface.js.map +1 -0
  150. package/dist/source/texels.d.ts +45 -0
  151. package/dist/source/texels.js +191 -0
  152. package/dist/source/texels.js.map +1 -0
  153. package/dist/source/trace.d.ts +42 -0
  154. package/dist/source/trace.js +153 -0
  155. package/dist/source/trace.js.map +1 -0
  156. package/dist/three.d.ts +55 -0
  157. package/dist/three.js +103 -0
  158. package/dist/three.js.map +1 -0
  159. package/dist/tsl.d.ts +45 -0
  160. package/dist/tsl.js +99 -0
  161. package/dist/tsl.js.map +1 -0
  162. package/dist/view.d.ts +30 -0
  163. package/dist/view.js +75 -0
  164. package/dist/view.js.map +1 -0
  165. package/dist/wind/bounds.d.ts +3 -0
  166. package/dist/wind/bounds.js +47 -0
  167. package/dist/wind/bounds.js.map +1 -0
  168. package/dist/wind/hooks.d.ts +5 -0
  169. package/dist/wind/hooks.js +3 -0
  170. package/dist/wind/hooks.js.map +1 -0
  171. package/dist/wind/index.d.ts +57 -0
  172. package/dist/wind/index.js +196 -0
  173. package/dist/wind/index.js.map +1 -0
  174. package/dist/wind/sway.d.ts +29 -0
  175. package/dist/wind/sway.js +71 -0
  176. package/dist/wind/sway.js.map +1 -0
  177. package/package.json +69 -3
  178. package/skills/lod/SKILL.md +137 -0
package/dist/lazy.js ADDED
@@ -0,0 +1,187 @@
1
+ import { Frustum, Matrix4, Object3D, Sphere } from "three/webgpu";
2
+ import { ImpostorMesh } from "./impostor/mesh/index.js";
3
+ import { validateImpostor } from "./impostor/impostor.js";
4
+ import { isLazyImpostor, sameClass } from "./three.js";
5
+ /**
6
+ * An impostor level whose atlas is loaded only when a viewing camera may need it.
7
+ * Put it after an eager source in Lod or InstancedLod. Until ready, the nearest
8
+ * ready finer level draws instead. The factory can decode cached data or bake it;
9
+ * it runs once across clones and concurrent requests. It does not upload textures.
10
+ */
11
+ export class LazyImpostor extends Object3D {
12
+ isLazyImpostor = true;
13
+ options;
14
+ state;
15
+ constructor(load, options) {
16
+ super();
17
+ if (!(options.maxPixels > 0) || !Number.isFinite(options.maxPixels))
18
+ throw new Error("LazyImpostor: maxPixels must be finite and > 0");
19
+ this.options = { maxPixels: options.maxPixels, draw: { ...options.draw } };
20
+ this.state = {
21
+ shared: { factory: load, status: "idle", value: undefined, error: undefined, promise: undefined, attempt: 0, reported: -1, users: new Set([this]) },
22
+ mesh: undefined,
23
+ owners: 0,
24
+ disposed: false,
25
+ };
26
+ }
27
+ get maxPixels() {
28
+ return this.options.maxPixels;
29
+ }
30
+ get status() {
31
+ const state = this.state;
32
+ return state.disposed ? "disposed" : state.shared.status;
33
+ }
34
+ get error() {
35
+ return this.state.shared.error;
36
+ }
37
+ get impostor() {
38
+ return this.state.shared.value;
39
+ }
40
+ /** Prefetch atlas data, or explicitly retry a failed request. Errors reject. */
41
+ load() {
42
+ const state = this.state, shared = state.shared;
43
+ if (state.disposed)
44
+ return Promise.reject(new Error("LazyImpostor: already disposed"));
45
+ if (shared.status === "ready" && shared.value)
46
+ return Promise.resolve(shared.value);
47
+ if (shared.status === "loading" && shared.promise)
48
+ return shared.promise;
49
+ const factory = shared.factory;
50
+ if (!factory)
51
+ return Promise.reject(new Error("LazyImpostor: its source has been released"));
52
+ const attempt = ++shared.attempt;
53
+ shared.status = "loading";
54
+ shared.error = undefined;
55
+ shared.promise = Promise.resolve()
56
+ .then(factory)
57
+ .then((value) => {
58
+ validateImpostor(value);
59
+ if (shared.attempt !== attempt || shared.users.size === 0)
60
+ throw new Error("LazyImpostor: disposed before loading completed");
61
+ shared.value = value;
62
+ shared.status = "ready";
63
+ return value;
64
+ })
65
+ .catch((error) => {
66
+ if (shared.attempt === attempt && shared.users.size > 0) {
67
+ shared.status = "error";
68
+ shared.error = error;
69
+ for (const lazy of shared.users)
70
+ lazy.dispatchEvent({ type: "error", error });
71
+ }
72
+ throw error;
73
+ });
74
+ return shared.promise;
75
+ }
76
+ copy(source) {
77
+ const own = this.state, from = source.state;
78
+ if (own.mesh || own.owners || own.disposed || from.disposed)
79
+ throw new Error("LazyImpostor.copy: use an unused target and a live source");
80
+ own.shared.users.delete(this);
81
+ own.shared = from.shared;
82
+ own.shared.users.add(this);
83
+ this.options.maxPixels = source.maxPixels;
84
+ this.options.draw = { ...source.options.draw };
85
+ super.copy(source, false);
86
+ return this;
87
+ }
88
+ clone() {
89
+ const factory = this.state.shared.factory;
90
+ if (this.state.disposed || !factory)
91
+ throw new Error("LazyImpostor.clone: already disposed");
92
+ const clone = new LazyImpostor(factory, this.options).copy(this);
93
+ if (!sameClass(this, clone))
94
+ throw new Error("LazyImpostor.clone: a subclass must override clone");
95
+ return clone;
96
+ }
97
+ /** @internal LOD ownership; several crowds can share a template. */
98
+ retain() {
99
+ if (this.state.disposed)
100
+ throw new Error("LazyImpostor: a disposed level cannot be reused");
101
+ this.state.owners++;
102
+ }
103
+ /** @internal Release a LOD's ownership of this template. */
104
+ release() {
105
+ if (this.state.owners < 1)
106
+ throw new Error("LazyImpostor: no owner to release");
107
+ if (--this.state.owners === 0)
108
+ this.dispose();
109
+ }
110
+ /** @internal The card has been installed, not merely decoded. */
111
+ get available() {
112
+ return this.state.mesh !== undefined;
113
+ }
114
+ /** @internal Install this descriptor's card before its LOD attaches draw hooks. */
115
+ materialize() {
116
+ const state = this.state;
117
+ if (state.disposed || state.mesh || !state.shared.value)
118
+ return;
119
+ const mesh = new ImpostorMesh(state.shared.value, 1, this.options.draw);
120
+ mesh.castShadow = this.castShadow;
121
+ mesh.receiveShadow = this.receiveShadow;
122
+ this.add(mesh);
123
+ state.mesh = mesh;
124
+ }
125
+ /** @internal Demand starts one request, with one visible report on failure. */
126
+ request() {
127
+ const { shared, disposed } = this.state;
128
+ if (disposed || shared.status !== "idle")
129
+ return;
130
+ const promise = this.load(), attempt = shared.attempt;
131
+ void promise.catch((error) => {
132
+ if (shared.users.size === 0 || shared.reported === attempt)
133
+ return;
134
+ shared.reported = attempt;
135
+ console.error(error);
136
+ });
137
+ }
138
+ /** Stops demand and releases this template's card. Pending work cannot install it. */
139
+ dispose() {
140
+ const state = this.state;
141
+ if (state.disposed)
142
+ return;
143
+ state.disposed = true;
144
+ if (state.mesh) {
145
+ this.remove(state.mesh);
146
+ state.mesh.dispose();
147
+ state.mesh = undefined;
148
+ }
149
+ state.shared.users.delete(this);
150
+ if (state.shared.users.size === 0) {
151
+ state.shared.attempt++;
152
+ state.shared.value = undefined;
153
+ state.shared.promise = undefined;
154
+ // Factories often retain an authored source or a CPU-only geometry snapshot.
155
+ state.shared.factory = undefined;
156
+ }
157
+ }
158
+ }
159
+ export function available(object) {
160
+ return !isLazyImpostor(object) || object.available;
161
+ }
162
+ /** Each logical level's nearest available finer level; eager empty levels still cull. */
163
+ export function fallbacks(objects) {
164
+ let ready = 0;
165
+ return objects.map((object, index) => (available(object) ? (ready = index) : ready));
166
+ }
167
+ const views = new WeakMap();
168
+ const projectionView = new Matrix4(), worldSphere = new Sphere();
169
+ /** Demand only from the viewing frustum; lazy shadow work uses the ready fallback. */
170
+ export function inView(camera, root, sphere) {
171
+ if (sphere.isEmpty())
172
+ return false;
173
+ let cached = views.get(camera);
174
+ if (!cached) {
175
+ cached = { projection: new Matrix4().makeScale(0, 0, 0), world: new Matrix4(), frustum: new Frustum() };
176
+ views.set(camera, cached);
177
+ }
178
+ if (!cached.projection.equals(camera.projectionMatrix) || !cached.world.equals(camera.matrixWorld)) {
179
+ cached.projection.copy(camera.projectionMatrix);
180
+ cached.world.copy(camera.matrixWorld);
181
+ projectionView.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
182
+ cached.frustum.setFromProjectionMatrix(projectionView, camera.coordinateSystem, camera.reversedDepth);
183
+ }
184
+ worldSphere.copy(sphere).applyMatrix4(root);
185
+ return cached.frustum.intersectsSphere(worldSphere);
186
+ }
187
+ //# sourceMappingURL=lazy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy.js","sourceRoot":"","sources":["../src/lazy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
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
+ */
7
+ export declare const FADE = 0.1;
8
+ /** One entry of `Lod.levels`. */
9
+ export interface LodLevel {
10
+ readonly object: Object3D;
11
+ /**
12
+ * The largest on-screen height, in CSS pixels, at which this level is used
13
+ * (heights are × `Lod.quality`). Level 0, the source, has Infinity.
14
+ * Every further level's must be at most 0.9 of the previous one's, so that one fade has
15
+ * ended before the next begins.
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.
23
+ */
24
+ maxPixels: number;
25
+ }
26
+ export declare class Level implements LodLevel {
27
+ readonly object: Object3D;
28
+ 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
+ private readonly ladder;
33
+ /** Debug tint (see `Lod.debug`), white when off; shared by every draw of the level. */
34
+ readonly tint: Color;
35
+ /** maxPixels as set, or null for the default */
36
+ explicit: number | null;
37
+ /** The default before raising for the fades: see `resolve`. */
38
+ base: number;
39
+ /** maxPixels as resolved; see `resolve` */
40
+ value: number;
41
+ constructor(object: Object3D, index: number,
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[]);
46
+ get maxPixels(): number;
47
+ set maxPixels(value: number);
48
+ }
49
+ /** Record that `level` is `error` off its source (see `errors`). */
50
+ export declare const recordError: (level: Object3D, error: number) => void;
51
+ /** The error recorded for `level`, if any. */
52
+ export declare const errorOf: (level: Object3D) => number | undefined;
53
+ /** Clones of `levels`' objects, which keep the errors recorded for them. */
54
+ export declare function cloneLevels(levels: readonly Level[]): Object3D[];
55
+ /** Give `to` the maxPixels set on `from`, level by level. */
56
+ export declare function copyThresholds(from: readonly Level[], to: readonly Level[]): void;
57
+ /**
58
+ * Give each level its default `base`, for a source of bounding diameter `diameter` in its
59
+ * own units, and resolve the thresholds (see `LodLevel.maxPixels`).
60
+ */
61
+ export declare function estimate(levels: readonly Level[], diameter: number): void;
62
+ /** Throws unless each level's fade ends before the next one's begins (see `LodLevel.maxPixels`). */
63
+ export declare function validate(levels: readonly LodLevel[]): void;
64
+ /** The level drawn at `height`: the last one it fits, or `forceLevel`. */
65
+ export declare function levelAt(levels: readonly Level[], height: number, forceLevel: number | null): Level;
66
+ /**
67
+ * How far `level` has faded in over its finer neighbour at `height`, in [0, 1): 0 when
68
+ * no fade is under way (the finer level is gone). See fade.ts for how both draw it.
69
+ */
70
+ export declare function fadeProgress(levels: readonly Level[], level: Level, height: number): number;
71
+ /** Give each level its debug tint, or white. */
72
+ export declare function tintLevels(levels: readonly Level[], debug: boolean): void;
package/dist/levels.js ADDED
@@ -0,0 +1,146 @@
1
+ import { Color } from "three/webgpu";
2
+ import { texelPixels } from "./impostor/impostor.js";
3
+ import { isLazyImpostor, isImpostorMesh } from "./three.js";
4
+ // The levels Lod and InstancedLod share: their thresholds, the defaults of those, which
5
+ // level a height picks and how far it has faded in (see fade.ts).
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
+ */
11
+ export const FADE = 0.1;
12
+ export class Level {
13
+ object;
14
+ index;
15
+ nested;
16
+ ladder;
17
+ /** Debug tint (see `Lod.debug`), white when off; shared by every draw of the level. */
18
+ tint = new Color(1, 1, 1);
19
+ /** maxPixels as set, or null for the default */
20
+ explicit = null;
21
+ /** The default before raising for the fades: see `resolve`. */
22
+ base = Infinity;
23
+ /** maxPixels as resolved; see `resolve` */
24
+ value = Infinity;
25
+ constructor(object, index,
26
+ /** A nested LOD switches its own levels and fades by them, not by its parent. */
27
+ nested,
28
+ /** The levels this one is in, which its default depends on. */
29
+ ladder) {
30
+ this.object = object;
31
+ this.index = index;
32
+ this.nested = nested;
33
+ this.ladder = ladder;
34
+ if (isLazyImpostor(object))
35
+ this.explicit = object.maxPixels;
36
+ }
37
+ get maxPixels() {
38
+ return this.value;
39
+ }
40
+ set maxPixels(value) {
41
+ if (this.index === 0 && value !== Infinity)
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}`);
47
+ this.explicit = value;
48
+ resolve(this.ladder);
49
+ }
50
+ }
51
+ /** Error a built level reports: how far its surface is from its source's, in the source's units. */
52
+ const errors = new WeakMap();
53
+ /** Record that `level` is `error` off its source (see `errors`). */
54
+ export const recordError = (level, error) => void errors.set(level, error);
55
+ /** The error recorded for `level`, if any. */
56
+ export const errorOf = (level) => errors.get(level);
57
+ /** Clones of `levels`' objects, which keep the errors recorded for them. */
58
+ export function cloneLevels(levels) {
59
+ return levels.map(({ object }) => {
60
+ const clone = object.clone();
61
+ const error = errorOf(object);
62
+ if (error !== undefined)
63
+ errors.set(clone, error);
64
+ return clone;
65
+ });
66
+ }
67
+ /** Give `to` the maxPixels set on `from`, level by level. */
68
+ export function copyThresholds(from, to) {
69
+ to.forEach((level, i) => {
70
+ const explicit = from[i]?.explicit ?? null;
71
+ if (explicit !== null)
72
+ level.maxPixels = explicit;
73
+ });
74
+ }
75
+ /**
76
+ * Give each level its default `base`, for a source of bounding diameter `diameter` in its
77
+ * own units, and resolve the thresholds (see `LodLevel.maxPixels`).
78
+ */
79
+ export function estimate(levels, diameter) {
80
+ let finer = 1024;
81
+ for (const level of levels.slice(1)) {
82
+ const error = errorOf(level.object);
83
+ if (isLazyImpostor(level.object))
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
+ resolve(levels);
94
+ }
95
+ /** Each level's maxPixels: as set, else its base raised to twice the next level's, from the cheapest up. */
96
+ function resolve(levels) {
97
+ let next = 0;
98
+ for (const level of [...levels].reverse()) {
99
+ level.value = level.index === 0 ? Infinity : (level.explicit ?? Math.max(level.base, 2 * next));
100
+ next = level.value;
101
+ }
102
+ }
103
+ /** Throws unless each level's fade ends before the next one's begins (see `LodLevel.maxPixels`). */
104
+ export function validate(levels) {
105
+ levels.forEach((level, i) => {
106
+ const finer = levels[i - 1];
107
+ if (finer && level.maxPixels > finer.maxPixels * (1 - FADE))
108
+ throw new Error(`Lod: level ${i} has maxPixels ${level.maxPixels}, but at most ${finer.maxPixels * (1 - FADE)} (${1 - FADE} × level ${i - 1}'s ${finer.maxPixels}) leaves room for the fades`);
109
+ });
110
+ }
111
+ /** The level drawn at `height`: the last one it fits, or `forceLevel`. */
112
+ export function levelAt(levels, height, forceLevel) {
113
+ const level = levels[forceLevel ?? lastFitting(levels, height)];
114
+ if (!level)
115
+ throw new Error(`Lod: forceLevel ${forceLevel} is not a level`);
116
+ return level;
117
+ }
118
+ function lastFitting(levels, height) {
119
+ for (let i = levels.length - 1; i > 0; i--) {
120
+ const level = levels[i];
121
+ if (level && height <= level.maxPixels)
122
+ return i;
123
+ }
124
+ return 0;
125
+ }
126
+ /**
127
+ * How far `level` has faded in over its finer neighbour at `height`, in [0, 1): 0 when
128
+ * no fade is under way (the finer level is gone). See fade.ts for how both draw it.
129
+ */
130
+ export function fadeProgress(levels, level, height) {
131
+ const finer = levels[level.index - 1];
132
+ if (!finer || level.nested || finer.nested)
133
+ return 0;
134
+ const top = level.maxPixels;
135
+ const t = Math.min(Math.max((height - top * (1 - FADE)) / (top * FADE), 0), 1);
136
+ // smoothstep, as the GPU's selection computes it
137
+ return t * t * (3 - 2 * t);
138
+ }
139
+ /** Debug tints by level index, see `Lod.debug`. */
140
+ const TINTS = [0xff6060, 0x60ff60, 0x6080ff, 0xffd040, 0xff60ff, 0x60ffff].map((hex) => new Color(hex));
141
+ /** Give each level its debug tint, or white. */
142
+ export function tintLevels(levels, debug) {
143
+ for (const level of levels)
144
+ level.tint.set(debug ? (TINTS[level.index % TINTS.length] ?? 0xffffff) : 0xffffff);
145
+ }
146
+ //# sourceMappingURL=levels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"levels.js","sourceRoot":"","sources":["../src/levels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { GLTSSource } from "@drawcall/glts";
2
+ import type { Object3D } from "three/webgpu";
3
+ import type { Dependencies } from "vitecache";
4
+ import { type BakeImpostorOptions } from "../impostor/bake/index.js";
5
+ import { type ImpostorCacheOptions } from "../impostor/cache.js";
6
+ import type { Impostor } from "../impostor/impostor.js";
7
+ /** Cache location and additional inputs that GLTS does not track, such as generator packages. */
8
+ export interface LodCacheOptions extends ImpostorCacheOptions {
9
+ /** Extra vitecache dependencies. Names beginning with glts: or lod: are reserved. */
10
+ dependencies?: Dependencies;
11
+ }
12
+ /** Loaded GLTS scenes expose their run's source even outside an active script. */
13
+ export declare function originOf(object: Object3D): GLTSSource | undefined;
14
+ /** Capture dependencies when the bake starts, including files loaded since its request. */
15
+ export declare function impostor(source: Object3D, options: BakeImpostorOptions, origin?: GLTSSource, excluded?: readonly Object3D[], cacheOptions?: LodCacheOptions): Promise<Impostor>;
@@ -0,0 +1,37 @@
1
+ import { bake, bakeImpostor } from "../impostor/bake/index.js";
2
+ import { cached } from "../impostor/cache.js";
3
+ /** Loaded GLTS scenes expose their run's source even outside an active script. */
4
+ export function originOf(object) {
5
+ const source = Reflect.get(object, "source");
6
+ if (source === undefined)
7
+ return undefined;
8
+ if (!isSource(source))
9
+ throw new Error("LodLoader: invalid GLTS source metadata");
10
+ return source;
11
+ }
12
+ function isSource(source) {
13
+ if (typeof source !== "object" || source === null)
14
+ return false;
15
+ const url = Reflect.get(source, "url");
16
+ const dependencies = Reflect.get(source, "dependencyUrls");
17
+ return typeof url === "string" && Array.isArray(dependencies) && dependencies.every((url) => typeof url === "string");
18
+ }
19
+ /** Capture dependencies when the bake starts, including files loaded since its request. */
20
+ export async function impostor(source, options, origin, excluded = [], cacheOptions) {
21
+ const make = (settings) => (excluded.length > 0 ? bake(source, settings, excluded) : bakeImpostor(source, settings));
22
+ if (!origin)
23
+ return make(options);
24
+ const urls = origin.dependencyUrls;
25
+ const { dependencies = {}, ...location } = cacheOptions ?? {};
26
+ if (Object.keys(dependencies).some((name) => name.startsWith("glts:")))
27
+ throw new Error("LodLoader: dependency names beginning with glts: are reserved");
28
+ return cached(options, {
29
+ ...dependencies,
30
+ "glts:source": { url: origin.url },
31
+ // URL resolution tracks the file; retain its query parameters as inputs too.
32
+ "glts:query": { value: new URL(origin.url).search },
33
+ ...Object.fromEntries(urls.map((url, index) => [`glts:dependency:${index}`, { url }])),
34
+ "glts:dependencyQueries": { value: urls.map((url) => new URL(url).search) },
35
+ }, make, location);
36
+ }
37
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/loader/cache.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,YAAY,EAA4B,MAAM,2BAA2B,CAAC;AACzF,OAAO,EAAE,MAAM,EAA6B,MAAM,sBAAsB,CAAC;AASzE,kFAAkF;AAClF,MAAM,UAAU,QAAQ,CAAC,MAAgB;IACvC,MAAM,MAAM,GAAY,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACtD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC3C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAClF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,QAAQ,CAAC,MAAe;IAC/B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAChE,MAAM,GAAG,GAAY,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAChD,MAAM,YAAY,GAAY,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACpE,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC;AACjI,CAAC;AAED,2FAA2F;AAC3F,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAgB,EAChB,OAA4B,EAC5B,MAAmB,EACnB,WAAgC,EAAE,EAClC,YAA8B;IAE9B,MAAM,IAAI,GAAG,CAAC,QAA6B,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC1I,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,MAAM,CAAC,cAAc,CAAC;IACnC,MAAM,EAAE,YAAY,GAAG,EAAE,EAAE,GAAG,QAAQ,EAAE,GAAG,YAAY,IAAI,EAAE,CAAC;IAC9D,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;IACzJ,OAAO,MAAM,CACX,OAAO,EACP;QACE,GAAG,YAAY;QACf,aAAa,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE;QAClC,6EAA6E;QAC7E,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE;QACnD,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,mBAAmB,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACtF,wBAAwB,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE;KAC5E,EACD,IAAI,EACJ,QAAQ,CACT,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Object3D } from "three/webgpu";
2
+ /** Failed simplifications own new geometry, but borrow source materials and untouched geometry. */
3
+ export declare function disposeSimplified(copy: Object3D, source: Object3D): void;
@@ -0,0 +1,25 @@
1
+ import { isImpostorMesh, isInstancedMesh, isLazyImpostor, isMesh } from "../three.js";
2
+ /** Failed simplifications own new geometry, but borrow source materials and untouched geometry. */
3
+ export function disposeSimplified(copy, source) {
4
+ const kept = new Set();
5
+ source.traverse((node) => {
6
+ if (isMesh(node))
7
+ kept.add(node.geometry);
8
+ });
9
+ copy.traverse((node) => {
10
+ // These clones retain their own references; their disposal releases only those.
11
+ if (isImpostorMesh(node) || isLazyImpostor(node)) {
12
+ node.dispose();
13
+ return;
14
+ }
15
+ if (!isMesh(node))
16
+ return;
17
+ if (!kept.has(node.geometry)) {
18
+ node.geometry.dispose();
19
+ kept.add(node.geometry);
20
+ }
21
+ if (isInstancedMesh(node))
22
+ node.dispose();
23
+ });
24
+ }
25
+ //# sourceMappingURL=dispose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispose.js","sourceRoot":"","sources":["../../src/loader/dispose.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEtF,mGAAmG;AACnG,MAAM,UAAU,iBAAiB,CAAC,IAAc,EAAE,MAAgB;IAChE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE;QACvB,IAAI,MAAM,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE;QACrB,gFAAgF;QAChF,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,OAAO;QAC1B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI,eAAe,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,OAAO,EAAE,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,99 @@
1
+ import { Loader, type LoadingManager, type Object3D } from "three/webgpu";
2
+ import type { BakeImpostorOptions } from "./impostor/bake/index.js";
3
+ import { InstancedLod } from "./instanced/index.js";
4
+ import { Lod } from "./lod.js";
5
+ import { type LodCacheOptions } from "./loader/cache.js";
6
+ export type { LodCacheOptions } from "./loader/cache.js";
7
+ import { type SimplifyOptions } from "./simplify.js";
8
+ /** A level the loader builds from the source, cheapest last; `maxPixels` overrides its default (see `LodLevel.maxPixels`). */
9
+ export type LevelRequest = ({
10
+ type: "simplified";
11
+ maxPixels?: number;
12
+ } & SimplifyOptions) | ({
13
+ type: "baked";
14
+ maxPixels?: number;
15
+ textureSize?: number;
16
+ /**
17
+ * URL of the rooms to show through the model's glass (see `BakeMeshOptions.interior`),
18
+ * loaded like the model and relative to it. It is added to the model after every
19
+ * level is built, so up close the real rooms show through the real glass. Only one
20
+ * baked level of a model may have one.
21
+ */
22
+ interior?: string;
23
+ } & ({
24
+ /**
25
+ * URL of the mesh to bake onto (.glts, .glb or .gltf), loaded like the model. A
26
+ * relative URL is relative to the model's: a model and its low mesh live together.
27
+ */
28
+ low: string;
29
+ ratio?: never;
30
+ } | {
31
+ low?: never;
32
+ ratio?: number;
33
+ })) | ({
34
+ type: "impostor";
35
+ /** Build only when needed; requires an explicit positive maxPixels. Default false. */
36
+ lazy?: boolean;
37
+ } & BakeImpostorOptions);
38
+ /**
39
+ * A model URL (.glb, .gltf or .glts), or the complete asset passed from its active GLTS
40
+ * script. The whole GLTS asset is the cache unit, not individual parts of its scene.
41
+ * GLTS impostors persist through vitecache; its Vite plugin tracks the script and its
42
+ * dependency files. Pass an object only after its dependency loads have finished;
43
+ * deferred impostors read retained dependencies when loading begins.
44
+ */
45
+ export type LodRequest = string | Object3D | {
46
+ url: string;
47
+ levels?: readonly LevelRequest[];
48
+ } | {
49
+ source: Object3D;
50
+ levels?: readonly LevelRequest[];
51
+ };
52
+ /**
53
+ * Loads a model and builds a `Lod` of it: the model as level 0, then the requested
54
+ * levels (default: an impostor). Unless explicitly lazy, building runs at load time; impostors bake on a
55
+ * renderer this package keeps for that. Each level's maxPixels is its default (see
56
+ * `LodLevel.maxPixels`) unless the request sets it; a failed load frees what it built.
57
+ *
58
+ * Models load through the manager's handler for the URL if one is registered: a
59
+ * GLTFLoader with Draco or meshopt decoders, or for .glts a GLTSLoader from
60
+ * @drawcall/glts (inside a .glts script, the contextual `gltsLoader`, registered on the
61
+ * contextual `loadingManager`). Without one, .glb/.gltf load with a plain GLTFLoader and
62
+ * .glts fails. URLs resolve against `path` as GLTFLoader's do; a baked level's `low` and
63
+ * `interior` URLs load the same way, relative to the model's URL.
64
+ */
65
+ export declare class LodLoader extends Loader<Lod, LodRequest> {
66
+ private readonly cacheOptions?;
67
+ private gltf;
68
+ constructor(manager?: LoadingManager, cacheOptions?: LodCacheOptions | undefined);
69
+ load(request: LodRequest, onLoad: (lod: Lod) => void, _onProgress?: (event: ProgressEvent) => void, onError?: (error: unknown) => void): void;
70
+ loadAsync(request: LodRequest): Promise<Lod>;
71
+ /** Load `request` as `count` instances: an `InstancedLod`. */
72
+ loadInstancesAsync(request: LodRequest, count: number): Promise<InstancedLod>;
73
+ /** Build a `Lod` of the complete `object` inside GLTS. Relative low/interior URLs use the script's directory. */
74
+ parseAsync(object: Object3D, levels?: readonly LevelRequest[]): Promise<Lod>;
75
+ /** Build an `InstancedLod` of the complete `object` inside GLTS. */
76
+ parseInstancesAsync(object: Object3D, count: number, levels?: readonly LevelRequest[]): Promise<InstancedLod>;
77
+ /**
78
+ * `make` of `object` and its requested levels, with the maxPixels requested; `low` and
79
+ * `interior` URLs resolve against `base`. On failure, the levels built and interiors
80
+ * loaded are freed and `object` is left out of any Lod.
81
+ */
82
+ private build;
83
+ /** The level `request` asks for, and the interior a baked level loaded for the source. */
84
+ private buildLevel;
85
+ /**
86
+ * Bake `source` as `request` asks, loading its low mesh and interior relative to `base`.
87
+ * The low mesh is freed after: only the bake keeps it. The interior is returned for the
88
+ * source, or freed if the bake fails.
89
+ */
90
+ private bake;
91
+ /**
92
+ * Load `request`'s model and `build` it, reporting to the manager as one item; `build`
93
+ * gets the model's directory. On failure, the model is freed.
94
+ */
95
+ private loading;
96
+ private loadSource;
97
+ /** `loader` with this loader's request settings. */
98
+ private configure;
99
+ }