@drawcall/lod 0.3.0 → 0.5.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 +5 -8
- package/dist/bake.d.ts +16 -2
- package/dist/bake.js +92 -4
- package/dist/bake.js.map +1 -1
- package/dist/baked/index.d.ts +2 -2
- package/dist/baked/index.js +2 -2
- package/dist/baked/interior/faces.js +4 -2
- package/dist/baked/interior/faces.js.map +1 -1
- package/dist/baked/interior/material.js +1 -1
- package/dist/baked/interior/material.js.map +1 -1
- package/dist/baked/interior/rooms.d.ts +1 -1
- package/dist/baked/interior/rooms.js +1 -1
- package/dist/dispose.d.ts +3 -3
- package/dist/dispose.js +6 -6
- package/dist/dispose.js.map +1 -1
- package/dist/foliage.d.ts +32 -0
- package/dist/foliage.js +137 -0
- package/dist/foliage.js.map +1 -0
- package/dist/impostor/bake/index.d.ts +3 -3
- package/dist/impostor/bake/index.js +12 -3
- package/dist/impostor/bake/index.js.map +1 -1
- package/dist/impostor/bake/source.d.ts +2 -1
- package/dist/impostor/bake/source.js +2 -2
- package/dist/impostor/bake/source.js.map +1 -1
- package/dist/impostor/impostor.d.ts +1 -1
- package/dist/impostor/impostor.js +1 -1
- package/dist/impostor/ktx2/encode.js +5 -2
- package/dist/impostor/ktx2/encode.js.map +1 -1
- package/dist/impostor/ktx2/uastc.js +3 -2
- package/dist/impostor/ktx2/uastc.js.map +1 -1
- package/dist/impostor/ktx2/worker.js +0 -2
- package/dist/impostor/ktx2/worker.js.map +1 -1
- package/dist/impostor/mesh/card.d.ts +1 -1
- package/dist/impostor/mesh/index.d.ts +2 -2
- package/dist/impostor/mesh/index.js +3 -3
- package/dist/impostor/mesh/index.js.map +1 -1
- package/dist/index.d.ts +3 -6
- package/dist/index.js +3 -6
- package/dist/index.js.map +1 -1
- package/dist/instanced/camera.d.ts +13 -25
- package/dist/instanced/camera.js +17 -42
- package/dist/instanced/camera.js.map +1 -1
- package/dist/instanced/clusters.d.ts +68 -0
- package/dist/instanced/clusters.js +172 -0
- package/dist/instanced/clusters.js.map +1 -0
- package/dist/instanced/cull.d.ts +3 -3
- package/dist/instanced/cull.js +2 -2
- package/dist/instanced/cull.js.map +1 -1
- package/dist/instanced/instances.d.ts +39 -0
- package/dist/instanced/instances.js +104 -0
- package/dist/instanced/instances.js.map +1 -0
- package/dist/instanced/key.d.ts +1 -1
- package/dist/instanced/key.js +1 -1
- package/dist/instanced/key.js.map +1 -1
- package/dist/instanced/levels.d.ts +9 -9
- package/dist/instanced/levels.js +7 -6
- package/dist/instanced/levels.js.map +1 -1
- package/dist/instanced/lists.d.ts +29 -39
- package/dist/instanced/lists.js +45 -62
- package/dist/instanced/lists.js.map +1 -1
- package/dist/instanced/measure.d.ts +2 -2
- package/dist/instanced/measure.js +2 -2
- package/dist/instanced/meshes.d.ts +11 -9
- package/dist/instanced/meshes.js +26 -16
- package/dist/instanced/meshes.js.map +1 -1
- package/dist/instanced/mirror.d.ts +16 -12
- package/dist/instanced/mirror.js +51 -12
- package/dist/instanced/mirror.js.map +1 -1
- package/dist/instanced/raycast.d.ts +6 -9
- package/dist/instanced/raycast.js +15 -18
- package/dist/instanced/raycast.js.map +1 -1
- package/dist/instanced/rows.d.ts +22 -73
- package/dist/instanced/rows.js +24 -189
- package/dist/instanced/rows.js.map +1 -1
- package/dist/instanced/shape.d.ts +3 -1
- package/dist/instanced/shape.js +6 -3
- package/dist/instanced/shape.js.map +1 -1
- package/dist/instanced/sort.d.ts +36 -34
- package/dist/instanced/sort.js +168 -132
- package/dist/instanced/sort.js.map +1 -1
- package/dist/instanced/update.d.ts +17 -12
- package/dist/instanced/update.js +64 -85
- package/dist/instanced/update.js.map +1 -1
- package/dist/levels/compile/index.d.ts +4 -2
- package/dist/levels/compile/index.js +10 -2
- package/dist/levels/compile/index.js.map +1 -1
- package/dist/levels/compile/pipelines.d.ts +1 -1
- package/dist/levels/compile/pipelines.js +1 -6
- package/dist/levels/compile/pipelines.js.map +1 -1
- package/dist/levels/draw.d.ts +1 -1
- package/dist/levels/draw.js +3 -3
- package/dist/levels/fade.d.ts +13 -22
- package/dist/levels/fade.js +17 -38
- package/dist/levels/fade.js.map +1 -1
- package/dist/levels/index.d.ts +7 -7
- package/dist/levels/index.js +1 -1
- package/dist/levels/item.d.ts +10 -10
- package/dist/levels/item.js +15 -23
- package/dist/levels/item.js.map +1 -1
- package/dist/levels/load.d.ts +1 -1
- package/dist/levels/load.js +5 -3
- package/dist/levels/load.js.map +1 -1
- package/dist/levels/manager.d.ts +30 -31
- package/dist/levels/manager.js +75 -62
- package/dist/levels/manager.js.map +1 -1
- package/dist/levels/material.d.ts +2 -2
- package/dist/levels/material.js +2 -2
- package/dist/levels/renderer.d.ts +8 -5
- package/dist/levels/renderer.js +20 -4
- package/dist/levels/renderer.js.map +1 -1
- package/dist/levels/requests.d.ts +4 -1
- package/dist/levels/requests.js +3 -1
- package/dist/levels/requests.js.map +1 -1
- package/dist/loader/context.d.ts +9 -11
- package/dist/loader/context.js +12 -7
- package/dist/loader/context.js.map +1 -1
- package/dist/loader/entry.d.ts +4 -0
- package/dist/loader/entry.js +43 -0
- package/dist/loader/entry.js.map +1 -0
- package/dist/loader/index.d.ts +49 -35
- package/dist/loader/index.js +123 -135
- package/dist/loader/index.js.map +1 -1
- package/dist/loader/level.js +5 -5
- package/dist/loader/level.js.map +1 -1
- package/dist/loader/node.d.ts +26 -0
- package/dist/loader/node.js +199 -0
- package/dist/loader/node.js.map +1 -0
- package/dist/loader/request.d.ts +11 -44
- package/dist/loader/request.js +7 -47
- package/dist/loader/request.js.map +1 -1
- package/dist/loader/url.d.ts +10 -9
- package/dist/loader/url.js +21 -17
- package/dist/loader/url.js.map +1 -1
- package/dist/lod.d.ts +122 -62
- package/dist/lod.js +332 -187
- package/dist/lod.js.map +1 -1
- package/dist/meshopt.d.ts +1 -1
- package/dist/meshopt.js +3 -2
- package/dist/meshopt.js.map +1 -1
- package/dist/node-process.d.ts +5 -0
- package/dist/node-process.js +6 -0
- package/dist/node-process.js.map +1 -0
- package/dist/node.d.ts +2 -0
- package/dist/node.js +5 -0
- package/dist/node.js.map +1 -0
- package/dist/simplify/index.d.ts +2 -2
- package/dist/simplify/index.js +7 -7
- package/dist/simplify/index.js.map +1 -1
- package/dist/source/detail.d.ts +7 -2
- package/dist/source/detail.js +26 -22
- package/dist/source/detail.js.map +1 -1
- package/dist/source/sampler.js +5 -2
- package/dist/source/sampler.js.map +1 -1
- package/dist/three.d.ts +8 -7
- package/dist/three.js +5 -4
- package/dist/three.js.map +1 -1
- package/dist/wind/bounds.js +1 -1
- package/dist/wind/bounds.js.map +1 -1
- package/dist/wind/hooks.d.ts +1 -1
- package/dist/wind/hooks.js +1 -1
- package/dist/wind/index.d.ts +3 -3
- package/dist/wind/index.js +11 -9
- package/dist/wind/index.js.map +1 -1
- package/package.json +10 -6
- package/skills/lod/SKILL.md +65 -54
- package/dist/gpu.d.ts +0 -39
- package/dist/gpu.js +0 -41
- package/dist/gpu.js.map +0 -1
- package/dist/instanced/chunk.d.ts +0 -97
- package/dist/instanced/chunk.js +0 -156
- package/dist/instanced/chunk.js.map +0 -1
- package/dist/instanced/chunks.d.ts +0 -60
- package/dist/instanced/chunks.js +0 -208
- package/dist/instanced/chunks.js.map +0 -1
- package/dist/instanced/index.d.ts +0 -120
- package/dist/instanced/index.js +0 -290
- package/dist/instanced/index.js.map +0 -1
- package/dist/instanced/pages/buffers.d.ts +0 -37
- package/dist/instanced/pages/buffers.js +0 -15
- package/dist/instanced/pages/buffers.js.map +0 -1
- package/dist/instanced/pages/chunk.d.ts +0 -51
- package/dist/instanced/pages/chunk.js +0 -81
- package/dist/instanced/pages/chunk.js.map +0 -1
- package/dist/instanced/pages/index.d.ts +0 -74
- package/dist/instanced/pages/index.js +0 -269
- package/dist/instanced/pages/index.js.map +0 -1
- package/dist/instanced/pages/passes.d.ts +0 -21
- package/dist/instanced/pages/passes.js +0 -52
- package/dist/instanced/pages/passes.js.map +0 -1
- package/dist/instanced/pages/slots.d.ts +0 -11
- package/dist/instanced/pages/slots.js +0 -90
- package/dist/instanced/pages/slots.js.map +0 -1
- package/dist/instanced/pages/workgroup.d.ts +0 -14
- package/dist/instanced/pages/workgroup.js +0 -38
- package/dist/instanced/pages/workgroup.js.map +0 -1
- package/dist/levels/wait.d.ts +0 -27
- package/dist/levels/wait.js +0 -61
- package/dist/levels/wait.js.map +0 -1
- package/dist/loader/cache.d.ts +0 -12
- package/dist/loader/cache.js +0 -68
- package/dist/loader/cache.js.map +0 -1
- package/dist/loader/dependencies.d.ts +0 -32
- package/dist/loader/dependencies.js +0 -113
- package/dist/loader/dependencies.js.map +0 -1
package/dist/instanced/mirror.js
CHANGED
|
@@ -1,24 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/
|
|
1
|
+
import { StorageInstancedBufferAttribute } from "three/webgpu";
|
|
2
|
+
// Storage attributes the GPU reads a Lod's CPU attributes through, uploading what the app marks changed in them, as
|
|
3
|
+
// three uploads an InstancedMesh's: binding the app's own attribute through storage() would flag it as a storage
|
|
4
|
+
// attribute, which three then pads (an RGB colour to four floats) and treats as one wherever else the app draws it. Each
|
|
5
|
+
// takes and clears the source's update ranges, so an InstancedMesh also drawing the source uploads it whole.
|
|
6
|
+
/** A CPU instanceMatrix's mirror, over the source's own array. */
|
|
7
7
|
export class Mirror {
|
|
8
8
|
source;
|
|
9
|
-
/** A matrix per item, or floats one by one, which three never pads. */
|
|
10
9
|
attribute;
|
|
11
10
|
/** The source's version it last took in. */
|
|
12
11
|
version;
|
|
13
12
|
constructor(source) {
|
|
14
13
|
this.source = source;
|
|
15
|
-
this.attribute = new
|
|
14
|
+
this.attribute = new StorageInstancedBufferAttribute(source.array, 16);
|
|
16
15
|
this.version = source.version;
|
|
17
16
|
}
|
|
18
|
-
/**
|
|
19
|
-
* Take in the source's edits, whose array it shares: upload the ranges the app marked changed (all of it without any),
|
|
20
|
-
* which three would upload and clear were it drawing the source itself. Whether the source changed.
|
|
21
|
-
*/
|
|
17
|
+
/** Take in the source's edits: the ranges the app marked changed, all of it without any. Whether it changed. */
|
|
22
18
|
refresh() {
|
|
23
19
|
const { source, attribute } = this;
|
|
24
20
|
if (source.version === this.version)
|
|
@@ -34,4 +30,47 @@ export class Mirror {
|
|
|
34
30
|
this.attribute.dispose();
|
|
35
31
|
}
|
|
36
32
|
}
|
|
33
|
+
/** A CPU instanceColor's mirror: its RGB padded to the four floats a storage colour holds, in an array of its own. */
|
|
34
|
+
export class ColorMirror {
|
|
35
|
+
source;
|
|
36
|
+
attribute;
|
|
37
|
+
version;
|
|
38
|
+
constructor(source) {
|
|
39
|
+
this.source = source;
|
|
40
|
+
this.attribute = new StorageInstancedBufferAttribute(new Float32Array(source.count * 4), 4);
|
|
41
|
+
this.copy(0, source.count);
|
|
42
|
+
this.version = source.version;
|
|
43
|
+
}
|
|
44
|
+
/** Take in the source's edits: the instances of the ranges the app marked changed, all without any. Whether it changed. */
|
|
45
|
+
refresh() {
|
|
46
|
+
const { source, attribute } = this;
|
|
47
|
+
if (source.version === this.version)
|
|
48
|
+
return false;
|
|
49
|
+
this.version = source.version;
|
|
50
|
+
const ranges = source.updateRanges.length > 0 ? source.updateRanges : [{ start: 0, count: source.array.length }];
|
|
51
|
+
for (const { start, count } of ranges) {
|
|
52
|
+
const first = Math.floor(start / 3);
|
|
53
|
+
const end = Math.min(Math.ceil((start + count) / 3), source.count);
|
|
54
|
+
this.copy(first, end);
|
|
55
|
+
attribute.addUpdateRange(first * 4, (end - first) * 4);
|
|
56
|
+
}
|
|
57
|
+
source.clearUpdateRanges();
|
|
58
|
+
attribute.needsUpdate = true;
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
dispose() {
|
|
62
|
+
this.attribute.dispose();
|
|
63
|
+
}
|
|
64
|
+
/** Copy instances `first` to `end` (exclusive) of the source, white's alpha padding them. */
|
|
65
|
+
copy(first, end) {
|
|
66
|
+
const from = this.source.array;
|
|
67
|
+
const to = this.attribute.array;
|
|
68
|
+
for (let i = first; i < end; i++) {
|
|
69
|
+
to[i * 4] = from[i * 3] ?? 0;
|
|
70
|
+
to[i * 4 + 1] = from[i * 3 + 1] ?? 0;
|
|
71
|
+
to[i * 4 + 2] = from[i * 3 + 2] ?? 0;
|
|
72
|
+
to[i * 4 + 3] = 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
37
76
|
//# sourceMappingURL=mirror.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mirror.js","sourceRoot":"","sources":["../../src/instanced/mirror.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"mirror.js","sourceRoot":"","sources":["../../src/instanced/mirror.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { Sphere, type Intersection, type Object3D, type Raycaster } from "three/webgpu";
|
|
2
|
-
import type { InstancedLodChunk } from "./chunk.js";
|
|
3
2
|
import type { Part } from "./meshes.js";
|
|
4
|
-
/** A
|
|
5
|
-
export interface InstancedLodIntersection extends Intersection {
|
|
6
|
-
instanceId: number;
|
|
7
|
-
chunk: InstancedLodChunk;
|
|
8
|
-
}
|
|
9
|
-
/** An InstancedLod's source level as a raycast meets it: its parts, and the sphere around every level in an instance's space. */
|
|
3
|
+
/** A Lod's source level as a raycast meets it: its parts, and the sphere around every level in an instance's space. */
|
|
10
4
|
export interface RaycastSource {
|
|
11
5
|
readonly parts: readonly Part[];
|
|
12
6
|
readonly rest: Sphere;
|
|
13
7
|
}
|
|
14
|
-
/**
|
|
15
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Hits on the first `count` instances of `matrices`, `lod`'s, of `source`'s meshes, each raycast where an instance
|
|
10
|
+
* stands, with `instanceId` set as on an InstancedMesh's hits.
|
|
11
|
+
*/
|
|
12
|
+
export declare function raycastInstances(lod: Object3D, source: RaycastSource, matrices: ArrayLike<number>, count: number, raycaster: Raycaster, intersects: Intersection[]): void;
|
|
@@ -6,28 +6,25 @@ const sphere = new Sphere();
|
|
|
6
6
|
const instance = new Matrix4();
|
|
7
7
|
const world = new Matrix4();
|
|
8
8
|
const hits = [];
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Hits on the first `count` instances of `matrices`, `lod`'s, of `source`'s meshes, each raycast where an instance
|
|
11
|
+
* stands, with `instanceId` set as on an InstancedMesh's hits.
|
|
12
|
+
*/
|
|
13
|
+
export function raycastInstances(lod, source, matrices, count, raycaster, intersects) {
|
|
11
14
|
ray.copy(raycaster.ray).applyMatrix4(inverse.copy(lod.matrixWorld).invert());
|
|
12
15
|
// A mesh of several material groups is a part per group: it is hit once. A mesh's parts share its placement.
|
|
13
16
|
const meshes = new Map();
|
|
14
17
|
for (const { template, placement } of source.parts)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
for (const hit of hitsAt(mesh, world.multiplyMatrices(lod.matrixWorld, instance).multiply(placement), raycaster)) {
|
|
26
|
-
const found = Object.assign(hit, { object: lod, instanceId: index, chunk });
|
|
27
|
-
intersects.push(found);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
18
|
+
meshes.set(template, placement);
|
|
19
|
+
for (let index = 0; index < count; index++) {
|
|
20
|
+
instance.fromArray(matrices, index * 16);
|
|
21
|
+
sphere.center.copy(source.rest.center).applyMatrix4(instance);
|
|
22
|
+
sphere.radius = source.rest.radius * stretch(instance);
|
|
23
|
+
if (sphere.radius === 0 || !ray.intersectsSphere(sphere))
|
|
24
|
+
continue;
|
|
25
|
+
for (const [mesh, placement] of meshes)
|
|
26
|
+
for (const hit of hitsAt(mesh, world.multiplyMatrices(lod.matrixWorld, instance).multiply(placement), raycaster))
|
|
27
|
+
intersects.push({ ...hit, object: lod, instanceId: index });
|
|
31
28
|
}
|
|
32
29
|
}
|
|
33
30
|
/** `mesh`'s own raycast, as if it stood at `matrixWorld`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"raycast.js","sourceRoot":"","sources":["../../src/instanced/raycast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAA+D,MAAM,cAAc,CAAC;AACjH,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"raycast.js","sourceRoot":"","sources":["../../src/instanced/raycast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAA+D,MAAM,cAAc,CAAC;AACjH,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAStC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAC9B,MAAM,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;AACtB,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;AAC5B,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAE,CAAC;AAC/B,MAAM,KAAK,GAAG,IAAI,OAAO,EAAE,CAAC;AAC5B,MAAM,IAAI,GAAmB,EAAE,CAAC;AAEhC;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAa,EAAE,MAAqB,EAAE,QAA2B,EAAE,KAAa,EAAE,SAAoB,EAAE,UAA0B;IACjK,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,6GAA6G;IAC7G,MAAM,MAAM,GAAG,IAAI,GAAG,EAAiB,CAAC;IACxC,KAAK,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,MAAM,CAAC,KAAK;QAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACpF,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;QAC3C,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QACvD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC;YAAE,SAAS;QACnE,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,MAAM;YACpC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;gBAAE,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAClL,CAAC;AACH,CAAC;AAED,6DAA6D;AAC7D,SAAS,MAAM,CAAC,IAAU,EAAE,WAAoB,EAAE,SAAoB;IACpE,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC;IAC7B,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAChB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IAC/B,IAAI,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC;IACzB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/instanced/rows.d.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { IndirectStorageBufferAttribute, StorageBufferAttribute } from "three/webgpu";
|
|
2
|
-
/** vec4s
|
|
2
|
+
/** vec4s of the row's u32s and of its f32s. */
|
|
3
3
|
export declare const INT_ROW = 6;
|
|
4
4
|
export declare const FLOAT_ROW = 12;
|
|
5
5
|
/**
|
|
6
|
-
* Where each vec4 of
|
|
7
|
-
* level as `forcedWord` writes it
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* sway, cullDistance's near and far, cullDistance's camera, and the frustum's six planes.
|
|
6
|
+
* Where each vec4 of the row lies. Of its u32s (`INTS_AT`): `levels`, the level count, the coarsest level and the forced
|
|
7
|
+
* level as `forcedWord` writes it; `masks`, the levels that draw nothing, whether they fade (1 or 0), those loaded and
|
|
8
|
+
* those loaded before; `flags`, whether the camera is orthographic, cullDistance is set and its survivors scale (1 or
|
|
9
|
+
* 0), and the draw count; `layout`, slots per list; `starts`, per level the first slot of its list, `UNLISTED` for none.
|
|
10
|
+
* Of its f32s (`FLOATS_AT`): maxPixels of levels 0 to 3 and 4 to 7, the camera in the Lod's space (eye and pixels per
|
|
11
|
+
* unit of subtense, or of size, ortho), one instance's source sphere, the arrival's progress, the reach of every level
|
|
12
|
+
* and its sway, cullDistance's near and far, cullDistance's camera, and the frustum's six planes.
|
|
14
13
|
*/
|
|
15
14
|
export declare const INTS_AT: {
|
|
16
15
|
readonly levels: 0;
|
|
@@ -28,12 +27,10 @@ export declare const FLOATS_AT: {
|
|
|
28
27
|
readonly cullEye: 5;
|
|
29
28
|
readonly planes: 6;
|
|
30
29
|
};
|
|
31
|
-
/** The forced level as
|
|
30
|
+
/** The forced level as the row holds it: one more, so that 0 is none (-1). */
|
|
32
31
|
export declare const forcedWord: (forced: number) => number;
|
|
33
32
|
/** The start of a level without a list. */
|
|
34
33
|
export declare const UNLISTED = 4294967295;
|
|
35
|
-
/** Counts kept per row: one per level. */
|
|
36
|
-
export declare const COUNTS_PER_ROW = 8;
|
|
37
34
|
/** Bytes per indirect draw, including the unused final word of a non-indexed draw. */
|
|
38
35
|
export declare const DRAW_BYTES = 20;
|
|
39
36
|
/** One indirect draw: a level's mesh, drawing `count` indices (or vertices) from `start`. */
|
|
@@ -43,66 +40,18 @@ export interface IndirectDraw {
|
|
|
43
40
|
start: number;
|
|
44
41
|
indexed: boolean;
|
|
45
42
|
}
|
|
46
|
-
/** One camera's buffers, the rows it holds values for, and those due to sort. */
|
|
47
|
-
export interface CameraBuffers {
|
|
48
|
-
/** Its rows' u32s and f32s. */
|
|
49
|
-
words: StorageBufferAttribute;
|
|
50
|
-
floats: StorageBufferAttribute;
|
|
51
|
-
/** Its lists: per slot, the pool index it draws and its signed fade. */
|
|
52
|
-
indices: StorageBufferAttribute;
|
|
53
|
-
fades: StorageBufferAttribute;
|
|
54
|
-
/** Its indirect draws, five words each, in the order of the rows' draws. */
|
|
55
|
-
args: IndirectStorageBufferAttribute;
|
|
56
|
-
/** Whether its words go up whole with the next sort, as after a layout: no range of them is marked then. */
|
|
57
|
-
whole: boolean;
|
|
58
|
-
readonly held: Set<number>;
|
|
59
|
-
readonly due: Set<number>;
|
|
60
|
-
/** The InstancedLods drawing for the camera. */
|
|
61
|
-
users: number;
|
|
62
|
-
}
|
|
63
|
-
/** The rows of every InstancedLod of a LodGpu, where their lists and draws lie, and the buffers every camera shares. */
|
|
64
|
-
export declare class RowLayout {
|
|
65
|
-
private readonly rows;
|
|
66
|
-
private readonly free;
|
|
67
|
-
private slots;
|
|
68
|
-
private drawCount;
|
|
69
|
-
/** Every row's draws, from its first (see `drawWords`). */
|
|
70
|
-
draws: StorageBufferAttribute;
|
|
71
|
-
/** Per row and level, how many instances it holds for the camera sorting: the indirect pass clears them. */
|
|
72
|
-
counts: StorageBufferAttribute;
|
|
73
|
-
/** Whether the rows changed since they were laid out. */
|
|
74
|
-
private moved;
|
|
75
|
-
/** How many rows there are, freed ones included. */
|
|
76
|
-
get length(): number;
|
|
77
|
-
/** A row for an InstancedLod whose levels of `listed`, a mask, list up to `listSize` instances each. */
|
|
78
|
-
register(listed: number, listSize: number): number;
|
|
79
|
-
/** Free `row`: its InstancedLod is disposed. */
|
|
80
|
-
unregister(row: number): void;
|
|
81
|
-
/** `row` draws `draws` too, after those it has; where they start among its draws. */
|
|
82
|
-
appendDraws(row: number, draws: readonly IndirectDraw[]): number;
|
|
83
|
-
/** Byte offset of `row`'s first draw in a camera's args. */
|
|
84
|
-
argsOffset(row: number): number;
|
|
85
|
-
/**
|
|
86
|
-
* Lay every row's lists and draws out anew if they moved, with every camera's buffers fitted to them: each gets
|
|
87
|
-
* fresh args, as a row's old place holds another's words, and every row it holds is due to sort at its new place.
|
|
88
|
-
*/
|
|
89
|
-
layOut(cameras: Iterable<CameraBuffers>): void;
|
|
90
|
-
/** Write `row`'s layout and draw count into `buffers`' words. */
|
|
91
|
-
place(buffers: CameraBuffers, row: number): void;
|
|
92
|
-
/** A camera's buffers, sized to the layout. */
|
|
93
|
-
makeBuffers(): CameraBuffers;
|
|
94
|
-
dispose(): void;
|
|
95
|
-
private rowAt;
|
|
96
|
-
/** Grow `buffers` to the layout, keeping what its rows hold, with fresh args. */
|
|
97
|
-
private fit;
|
|
98
|
-
}
|
|
99
|
-
/** Set `row`'s sorting bit in `buffers` to `sorting`, uploaded with the camera's next sort. */
|
|
100
|
-
export declare function setSorting(buffers: CameraBuffers, row: number, sorting: number): void;
|
|
101
|
-
/** `count` of `buffers`' words from `at` changed: they go up with the camera's next sort. */
|
|
102
|
-
export declare function markWords(buffers: CameraBuffers, at: number, count: number): void;
|
|
103
|
-
export declare function disposeBuffers({ words, floats, indices, fades, args }: CameraBuffers): void;
|
|
104
|
-
/** A camera's rows, as the u32s and the f32s its buffers hold. */
|
|
105
|
-
export declare const wordsOf: ({ words }: CameraBuffers) => Uint32Array<ArrayBufferLike>;
|
|
106
|
-
export declare const floatsOf: ({ floats }: CameraBuffers) => Float32Array<ArrayBufferLike>;
|
|
107
43
|
/** The words of `draws` as the indirect pass reads them: level, count, start and whether indexed, per draw. */
|
|
108
44
|
export declare function drawWords(draws: readonly IndirectDraw[]): StorageBufferAttribute;
|
|
45
|
+
/**
|
|
46
|
+
* Where the blocks start among the u32s: four per block, its first instance, its range's end and start, and its range's
|
|
47
|
+
* item of live counts, NO_LIVE_COUNT for none (see `LodCluster.liveCount`).
|
|
48
|
+
*/
|
|
49
|
+
export declare const BLOCKS_AT: number;
|
|
50
|
+
export declare const NO_LIVE_COUNT = 4294967295;
|
|
51
|
+
/** The row's u32s and room for `blocks` blocks, one at least. */
|
|
52
|
+
export declare const wordsBuffer: (blocks: number) => StorageBufferAttribute;
|
|
53
|
+
export declare const floatsBuffer: () => StorageBufferAttribute;
|
|
54
|
+
/** Per level, how many instances its list holds for the camera sorting: the indirect pass clears them. */
|
|
55
|
+
export declare const countsBuffer: () => StorageBufferAttribute;
|
|
56
|
+
/** Indirect draws only the GPU writes, zero until a sort writes them: nothing draws before a sort. */
|
|
57
|
+
export declare const argsBuffer: (draws: number) => IndirectStorageBufferAttribute;
|
package/dist/instanced/rows.js
CHANGED
|
@@ -1,209 +1,44 @@
|
|
|
1
1
|
import { IndirectStorageBufferAttribute, StorageBufferAttribute } from "three/webgpu";
|
|
2
2
|
import { MAX_LEVELS } from "../levels/draw.js";
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
/** vec4s per row of u32s and of f32s: what one InstancedLod sorts by for a camera, in two buffers (see `INTS_AT`). */
|
|
3
|
+
// What a Lod sorts by for one camera, as the sort passes read it (see update.ts): its row, of u32s and of f32s, and
|
|
4
|
+
// after the row's u32s, in their buffer, the blocks of instances it sorts.
|
|
5
|
+
/** vec4s of the row's u32s and of its f32s. */
|
|
7
6
|
export const INT_ROW = 6;
|
|
8
7
|
export const FLOAT_ROW = 12;
|
|
9
8
|
/**
|
|
10
|
-
* Where each vec4 of
|
|
11
|
-
* level as `forcedWord` writes it
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* sway, cullDistance's near and far, cullDistance's camera, and the frustum's six planes.
|
|
9
|
+
* Where each vec4 of the row lies. Of its u32s (`INTS_AT`): `levels`, the level count, the coarsest level and the forced
|
|
10
|
+
* level as `forcedWord` writes it; `masks`, the levels that draw nothing, whether they fade (1 or 0), those loaded and
|
|
11
|
+
* those loaded before; `flags`, whether the camera is orthographic, cullDistance is set and its survivors scale (1 or
|
|
12
|
+
* 0), and the draw count; `layout`, slots per list; `starts`, per level the first slot of its list, `UNLISTED` for none.
|
|
13
|
+
* Of its f32s (`FLOATS_AT`): maxPixels of levels 0 to 3 and 4 to 7, the camera in the Lod's space (eye and pixels per
|
|
14
|
+
* unit of subtense, or of size, ortho), one instance's source sphere, the arrival's progress, the reach of every level
|
|
15
|
+
* and its sway, cullDistance's near and far, cullDistance's camera, and the frustum's six planes.
|
|
18
16
|
*/
|
|
19
17
|
export const INTS_AT = { levels: 0, masks: 1, flags: 2, layout: 3, starts: 4 };
|
|
20
18
|
export const FLOATS_AT = { low: 0, high: 1, eye: 2, source: 3, values: 4, cullEye: 5, planes: 6 };
|
|
21
|
-
/** The
|
|
22
|
-
const SORTING_AT = INTS_AT.levels * 4 + 3;
|
|
23
|
-
/** The forced level as a row's u32 holds it: one more, so that 0 is none (-1). */
|
|
19
|
+
/** The forced level as the row holds it: one more, so that 0 is none (-1). */
|
|
24
20
|
export const forcedWord = (forced) => forced + 1;
|
|
25
21
|
/** The start of a level without a list. */
|
|
26
22
|
export const UNLISTED = 0xffffffff;
|
|
27
|
-
/** Counts kept per row: one per level. */
|
|
28
|
-
export const COUNTS_PER_ROW = MAX_LEVELS;
|
|
29
23
|
/** Bytes per indirect draw, including the unused final word of a non-indexed draw. */
|
|
30
24
|
export const DRAW_BYTES = 20;
|
|
31
|
-
/** The rows of every InstancedLod of a LodGpu, where their lists and draws lie, and the buffers every camera shares. */
|
|
32
|
-
export class RowLayout {
|
|
33
|
-
rows = [];
|
|
34
|
-
free = [];
|
|
35
|
-
slots = 0;
|
|
36
|
-
drawCount = 0;
|
|
37
|
-
/** Every row's draws, from its first (see `drawWords`). */
|
|
38
|
-
draws = drawWords([]);
|
|
39
|
-
/** Per row and level, how many instances it holds for the camera sorting: the indirect pass clears them. */
|
|
40
|
-
counts = countsBuffer(0);
|
|
41
|
-
/** Whether the rows changed since they were laid out. */
|
|
42
|
-
moved = false;
|
|
43
|
-
/** How many rows there are, freed ones included. */
|
|
44
|
-
get length() {
|
|
45
|
-
return this.rows.length;
|
|
46
|
-
}
|
|
47
|
-
/** A row for an InstancedLod whose levels of `listed`, a mask, list up to `listSize` instances each. */
|
|
48
|
-
register(listed, listSize) {
|
|
49
|
-
const row = this.free.pop() ?? this.rows.length;
|
|
50
|
-
this.rows[row] = { listed, listSize, draws: [], listBase: 0, drawBase: 0 };
|
|
51
|
-
this.moved = true;
|
|
52
|
-
return row;
|
|
53
|
-
}
|
|
54
|
-
/** Free `row`: its InstancedLod is disposed. */
|
|
55
|
-
unregister(row) {
|
|
56
|
-
this.rows[row] = null;
|
|
57
|
-
this.free.push(row);
|
|
58
|
-
this.moved = true;
|
|
59
|
-
}
|
|
60
|
-
/** `row` draws `draws` too, after those it has; where they start among its draws. */
|
|
61
|
-
appendDraws(row, draws) {
|
|
62
|
-
const { draws: own } = this.rowAt(row);
|
|
63
|
-
const first = own.length;
|
|
64
|
-
own.push(...draws);
|
|
65
|
-
this.moved = true;
|
|
66
|
-
return first;
|
|
67
|
-
}
|
|
68
|
-
/** Byte offset of `row`'s first draw in a camera's args. */
|
|
69
|
-
argsOffset(row) {
|
|
70
|
-
return this.rowAt(row).drawBase * DRAW_BYTES;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Lay every row's lists and draws out anew if they moved, with every camera's buffers fitted to them: each gets
|
|
74
|
-
* fresh args, as a row's old place holds another's words, and every row it holds is due to sort at its new place.
|
|
75
|
-
*/
|
|
76
|
-
layOut(cameras) {
|
|
77
|
-
if (!this.moved)
|
|
78
|
-
return;
|
|
79
|
-
this.moved = false;
|
|
80
|
-
let slots = 0;
|
|
81
|
-
const all = [];
|
|
82
|
-
for (const row of this.rows) {
|
|
83
|
-
if (!row)
|
|
84
|
-
continue;
|
|
85
|
-
row.listBase = slots;
|
|
86
|
-
row.drawBase = all.length;
|
|
87
|
-
slots += countBits(row.listed) * row.listSize;
|
|
88
|
-
all.push(...row.draws);
|
|
89
|
-
}
|
|
90
|
-
this.slots = slots;
|
|
91
|
-
this.drawCount = all.length;
|
|
92
|
-
this.draws.dispose();
|
|
93
|
-
this.draws = drawWords(all);
|
|
94
|
-
if (this.counts.count < this.rows.length * COUNTS_PER_ROW) {
|
|
95
|
-
this.counts.dispose();
|
|
96
|
-
this.counts = countsBuffer(this.rows.length);
|
|
97
|
-
}
|
|
98
|
-
for (const buffers of cameras) {
|
|
99
|
-
this.fit(buffers);
|
|
100
|
-
// Every row of it moved: the whole buffer goes up.
|
|
101
|
-
buffers.words.clearUpdateRanges();
|
|
102
|
-
buffers.words.needsUpdate = true;
|
|
103
|
-
buffers.whole = true;
|
|
104
|
-
for (const row of buffers.held) {
|
|
105
|
-
this.place(buffers, row);
|
|
106
|
-
setSorting(buffers, row, 1);
|
|
107
|
-
buffers.due.add(row);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
/** Write `row`'s layout and draw count into `buffers`' words. */
|
|
112
|
-
place(buffers, row) {
|
|
113
|
-
const { listBase, listSize, listed, drawBase, draws } = this.rowAt(row);
|
|
114
|
-
const words = wordsOf(buffers);
|
|
115
|
-
const base = row * INT_ROW * 4;
|
|
116
|
-
words[base + INTS_AT.flags * 4 + 3] = draws.length;
|
|
117
|
-
words.set([listSize, drawBase, 0, 0], base + INTS_AT.layout * 4);
|
|
118
|
-
let next = listBase;
|
|
119
|
-
for (let level = 0; level < COUNTS_PER_ROW; level++) {
|
|
120
|
-
const on = (listed & (1 << level)) !== 0;
|
|
121
|
-
words[base + INTS_AT.starts * 4 + level] = on ? next : UNLISTED;
|
|
122
|
-
if (on)
|
|
123
|
-
next += listSize;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
/** A camera's buffers, sized to the layout. */
|
|
127
|
-
makeBuffers() {
|
|
128
|
-
return {
|
|
129
|
-
words: wordsBuffer(this.rows.length),
|
|
130
|
-
floats: floatsBuffer(this.rows.length),
|
|
131
|
-
indices: new StorageBufferAttribute(new Uint32Array(Math.max(this.slots, 1)), 1),
|
|
132
|
-
fades: new StorageBufferAttribute(new Float32Array(Math.max(this.slots, 1)), 1),
|
|
133
|
-
args: argsBuffer(this.drawCount),
|
|
134
|
-
whole: false,
|
|
135
|
-
held: new Set(),
|
|
136
|
-
due: new Set(),
|
|
137
|
-
users: 0,
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
dispose() {
|
|
141
|
-
this.draws.dispose();
|
|
142
|
-
this.counts.dispose();
|
|
143
|
-
}
|
|
144
|
-
rowAt(row) {
|
|
145
|
-
const found = this.rows[row];
|
|
146
|
-
if (!found)
|
|
147
|
-
throw new Error(`LodGpu: row ${row} holds no InstancedLod`);
|
|
148
|
-
return found;
|
|
149
|
-
}
|
|
150
|
-
/** Grow `buffers` to the layout, keeping what its rows hold, with fresh args. */
|
|
151
|
-
fit(buffers) {
|
|
152
|
-
if (buffers.words.count < this.rows.length * INT_ROW) {
|
|
153
|
-
const words = wordsBuffer(this.rows.length);
|
|
154
|
-
const floats = floatsBuffer(this.rows.length);
|
|
155
|
-
new Uint32Array(words.array.buffer).set(wordsOf(buffers));
|
|
156
|
-
new Float32Array(floats.array.buffer).set(floatsOf(buffers));
|
|
157
|
-
buffers.words.dispose();
|
|
158
|
-
buffers.floats.dispose();
|
|
159
|
-
buffers.words = words;
|
|
160
|
-
buffers.floats = floats;
|
|
161
|
-
}
|
|
162
|
-
if (buffers.indices.count < this.slots) {
|
|
163
|
-
buffers.indices.dispose();
|
|
164
|
-
buffers.fades.dispose();
|
|
165
|
-
buffers.indices = new StorageBufferAttribute(new Uint32Array(this.slots), 1);
|
|
166
|
-
buffers.fades = new StorageBufferAttribute(new Float32Array(this.slots), 1);
|
|
167
|
-
}
|
|
168
|
-
buffers.args.dispose();
|
|
169
|
-
buffers.args = argsBuffer(this.drawCount);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
/** Set `row`'s sorting bit in `buffers` to `sorting`, uploaded with the camera's next sort. */
|
|
173
|
-
export function setSorting(buffers, row, sorting) {
|
|
174
|
-
const at = row * INT_ROW * 4 + SORTING_AT;
|
|
175
|
-
wordsOf(buffers)[at] = sorting;
|
|
176
|
-
markWords(buffers, at, 1);
|
|
177
|
-
}
|
|
178
|
-
/** `count` of `buffers`' words from `at` changed: they go up with the camera's next sort. */
|
|
179
|
-
export function markWords(buffers, at, count) {
|
|
180
|
-
if (!buffers.whole)
|
|
181
|
-
buffers.words.addUpdateRange(at, count);
|
|
182
|
-
buffers.words.needsUpdate = true;
|
|
183
|
-
}
|
|
184
|
-
export function disposeBuffers({ words, floats, indices, fades, args }) {
|
|
185
|
-
for (const attribute of [words, floats, indices, fades, args])
|
|
186
|
-
attribute.dispose();
|
|
187
|
-
}
|
|
188
|
-
/** A camera's rows, as the u32s and the f32s its buffers hold. */
|
|
189
|
-
export const wordsOf = ({ words }) => new Uint32Array(words.array.buffer);
|
|
190
|
-
export const floatsOf = ({ floats }) => new Float32Array(floats.array.buffer);
|
|
191
25
|
/** The words of `draws` as the indirect pass reads them: level, count, start and whether indexed, per draw. */
|
|
192
26
|
export function drawWords(draws) {
|
|
193
27
|
const values = new Uint32Array(Math.max(draws.length, 1) * 4);
|
|
194
28
|
draws.forEach((draw, i) => values.set([draw.level, draw.count, draw.start, Number(draw.indexed)], i * 4));
|
|
195
29
|
return new StorageBufferAttribute(values, 4);
|
|
196
30
|
}
|
|
197
|
-
/**
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const wordsBuffer = (
|
|
205
|
-
const floatsBuffer = (
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Where the blocks start among the u32s: four per block, its first instance, its range's end and start, and its range's
|
|
33
|
+
* item of live counts, NO_LIVE_COUNT for none (see `LodCluster.liveCount`).
|
|
34
|
+
*/
|
|
35
|
+
export const BLOCKS_AT = INT_ROW * 4;
|
|
36
|
+
export const NO_LIVE_COUNT = 0xffffffff;
|
|
37
|
+
/** The row's u32s and room for `blocks` blocks, one at least. */
|
|
38
|
+
export const wordsBuffer = (blocks) => new StorageBufferAttribute(new Uint32Array(BLOCKS_AT + Math.max(blocks, 1) * 4), 4);
|
|
39
|
+
export const floatsBuffer = () => new StorageBufferAttribute(new Float32Array(FLOAT_ROW * 4), 4);
|
|
40
|
+
/** Per level, how many instances its list holds for the camera sorting: the indirect pass clears them. */
|
|
41
|
+
export const countsBuffer = () => new StorageBufferAttribute(new Uint32Array(MAX_LEVELS), 1);
|
|
42
|
+
/** Indirect draws only the GPU writes, zero until a sort writes them: nothing draws before a sort. */
|
|
43
|
+
export const argsBuffer = (draws) => new IndirectStorageBufferAttribute(new Uint32Array(Math.max(draws, 1) * (DRAW_BYTES / 4)), 1);
|
|
209
44
|
//# sourceMappingURL=rows.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rows.js","sourceRoot":"","sources":["../../src/instanced/rows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,
|
|
1
|
+
{"version":3,"file":"rows.js","sourceRoot":"","sources":["../../src/instanced/rows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,oHAAoH;AACpH,2EAA2E;AAE3E,+CAA+C;AAC/C,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC;AACzB,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC;AAE5B;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAW,CAAC;AACxF,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAW,CAAC;AAE3G,8EAA8E;AAC9E,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AAEzD,2CAA2C;AAC3C,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAC;AAEnC,sFAAsF;AACtF,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,CAAC;AAU7B,+GAA+G;AAC/G,MAAM,UAAU,SAAS,CAAC,KAA8B;IACtD,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9D,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC1G,OAAO,IAAI,sBAAsB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,GAAG,CAAC,CAAC;AACrC,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;AAExC,iEAAiE;AACjE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,IAAI,sBAAsB,CAAC,IAAI,WAAW,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACnI,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,IAAI,sBAAsB,CAAC,IAAI,YAAY,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACjG,0GAA0G;AAC1G,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,IAAI,sBAAsB,CAAC,IAAI,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7F,sGAAsG;AACtG,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,8BAA8B,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Sphere } from "three/webgpu";
|
|
2
2
|
import type { LodLevel } from "../levels/index.js";
|
|
3
|
-
/** One instance of
|
|
3
|
+
/** One instance of a Lod as its levels measure it, in its own space: what heights, bounds and fades are measured by. */
|
|
4
4
|
export declare class InstanceShape {
|
|
5
5
|
/** The source's sphere, which heights are measured by. */
|
|
6
6
|
readonly source: Sphere;
|
|
@@ -10,6 +10,8 @@ export declare class InstanceShape {
|
|
|
10
10
|
readonly ownRadius: number;
|
|
11
11
|
/** The source's radius padded for sway, where fades and shadow casters are cut off (see `wind`). */
|
|
12
12
|
fadeRadius: number;
|
|
13
|
+
/** The diagonal of every level's box: how much a cluster's box shows of its instances' scale. */
|
|
14
|
+
readonly extent: number;
|
|
13
15
|
/** Every level's box. */
|
|
14
16
|
private readonly envelope;
|
|
15
17
|
/** How far levels sway beyond `rest`, relative to it. */
|
package/dist/instanced/shape.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Box3, Sphere } from "three/webgpu";
|
|
1
|
+
import { Box3, Sphere, Vector3 } from "three/webgpu";
|
|
2
2
|
import { levelBox, measureLevels } from "../levels/bounds.js";
|
|
3
|
-
/** One instance of
|
|
3
|
+
/** One instance of a Lod as its levels measure it, in its own space: what heights, bounds and fades are measured by. */
|
|
4
4
|
export class InstanceShape {
|
|
5
5
|
/** The source's sphere, which heights are measured by. */
|
|
6
6
|
source = new Sphere();
|
|
@@ -10,6 +10,8 @@ export class InstanceShape {
|
|
|
10
10
|
ownRadius = 0;
|
|
11
11
|
/** The source's radius padded for sway, where fades and shadow casters are cut off (see `wind`). */
|
|
12
12
|
fadeRadius = 0;
|
|
13
|
+
/** The diagonal of every level's box: how much a cluster's box shows of its instances' scale. */
|
|
14
|
+
extent = 0;
|
|
13
15
|
/** Every level's box. */
|
|
14
16
|
envelope = new Box3();
|
|
15
17
|
/** How far levels sway beyond `rest`, relative to it. */
|
|
@@ -18,7 +20,7 @@ export class InstanceShape {
|
|
|
18
20
|
constructor(inputs) {
|
|
19
21
|
if (inputs.length === 0)
|
|
20
22
|
return;
|
|
21
|
-
const { own, placed } = measureLevels(inputs, "
|
|
23
|
+
const { own, placed } = measureLevels(inputs, "Lod");
|
|
22
24
|
this.ownRadius = own.radius;
|
|
23
25
|
this.source.copy(placed);
|
|
24
26
|
this.rest.copy(placed);
|
|
@@ -28,6 +30,7 @@ export class InstanceShape {
|
|
|
28
30
|
// Metadata includes unloaded levels, so later arrivals cannot pass the envelope.
|
|
29
31
|
if (this.envelope.isEmpty())
|
|
30
32
|
return;
|
|
33
|
+
this.extent = this.envelope.getSize(new Vector3()).length();
|
|
31
34
|
const { center } = this.rest;
|
|
32
35
|
const { min, max } = this.envelope;
|
|
33
36
|
this.rest.radius = Math.max(this.rest.radius, Math.hypot(Math.max(Math.abs(min.x - center.x), Math.abs(max.x - center.x)), Math.max(Math.abs(min.y - center.y), Math.abs(max.y - center.y)), Math.max(Math.abs(min.z - center.z), Math.abs(max.z - center.z))));
|