@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/tsl.js ADDED
@@ -0,0 +1,99 @@
1
+ import { context, cross, dFdx, dFdy, dot, length, log2, max, storage, uniform, uv, vec2, vec3, vec4 } from "three/tsl";
2
+ // Matrix access for the shaders, in operations three's typings know: they type no
3
+ // columns, inverses or transposes of matrix nodes. A product with a unit vector picks a
4
+ // column out and compiles to the same read; an affine inverse is cofactors and a dot.
5
+ /** Column `i` (0..3) of `m`. */
6
+ export const column = (m, i) => m.mul(vec4(i === 0 ? 1 : 0, i === 1 ? 1 : 0, i === 2 ? 1 : 0, i === 3 ? 1 : 0));
7
+ /** The largest scale `m` applies along an axis. */
8
+ export const maxScale = (m) => max(column(m, 0).xyz.length(), max(column(m, 1).xyz.length(), column(m, 2).xyz.length()));
9
+ /** Whether projection `m` is orthographic: its bottom-right element is 1. */
10
+ export const isOrthographic = (m) => column(m, 3).w.equal(1);
11
+ export function affine(m) {
12
+ const a0 = column(m, 0).xyz.toVar();
13
+ const a1 = column(m, 1).xyz.toVar();
14
+ const a2 = column(m, 2).xyz.toVar();
15
+ const det = dot(a0, cross(a1, a2)).toVar();
16
+ const c0 = cross(a1, a2).div(det).toVar();
17
+ const c1 = cross(a2, a0).div(det).toVar();
18
+ const c2 = cross(a0, a1).div(det).toVar();
19
+ const solve = (v) => vec3(dot(c0, v), dot(c1, v), dot(c2, v));
20
+ return {
21
+ apply: (v) => a0.mul(v.x).add(a1.mul(v.y)).add(a2.mul(v.z)),
22
+ solve,
23
+ unproject: (p) => solve(p.sub(column(m, 3).xyz)),
24
+ normal: (v) => c0.mul(v.x).add(c1.mul(v.y)).add(c2.mul(v.z)),
25
+ normalColumns: [c0, c1, c2],
26
+ };
27
+ }
28
+ const isNode = (value) => typeof value === "object" && value !== null && Reflect.get(value, "isNode") === true;
29
+ /** The node at `path` in the context `builder` builds with, which three's typings leave open. */
30
+ export function contextNode(builder, ...path) {
31
+ const value = path.reduce((at, key) => (typeof at === "object" && at !== null ? Reflect.get(at, key) : undefined), builder.context);
32
+ if (!isNode(value))
33
+ throw new Error(`@drawcall/lod: the shader's context has no ${path.join(".")}`);
34
+ return value;
35
+ }
36
+ /**
37
+ * An object that stays the same throughout one build of a shader, to cache per build
38
+ * what several of a material's slots read. Each slot is handed its own proxy of the
39
+ * builder, and three's typings expose no handle of the build itself: this is what the
40
+ * build keeps for `anchor`.
41
+ */
42
+ export function buildKey(builder, anchor) {
43
+ const properties = Reflect.apply(Reflect.get(builder, "getNodeProperties"), builder, [anchor]);
44
+ if (typeof properties !== "object" || properties === null)
45
+ throw new Error("@drawcall/lod: three's node builder keeps no properties");
46
+ return properties;
47
+ }
48
+ /**
49
+ * Whether `node` builds to a `type` value, which three's typings leave open for a
50
+ * material's slots. Checked while a shader builds, so a slot of another type fails there.
51
+ */
52
+ export function isNodeOf(node, type, builder) {
53
+ return node.getNodeType(builder) === type;
54
+ }
55
+ /**
56
+ * One node per buffer and role: a stage has few storage bindings. Each library material
57
+ * reads one buffer per role. Stable, distinct names let equal shaders share programs;
58
+ * Three's default storage names contain global node IDs, even for otherwise equal code.
59
+ */
60
+ function storageCache(type, name) {
61
+ const nodes = new WeakMap();
62
+ return (attribute) => {
63
+ let node = nodes.get(attribute);
64
+ if (!node)
65
+ nodes.set(attribute, (node = storage(attribute, type, attribute.count).setName(name)));
66
+ return node;
67
+ };
68
+ }
69
+ export const instanceFades = storageCache("float", "lodInstanceFades");
70
+ export const instanceColors = storageCache("vec4", "lodInstanceColors");
71
+ export const instanceMatrices = storageCache("mat4", "lodInstanceMatrices");
72
+ export const roomBounds = storageCache("vec4", "lodRoomBounds");
73
+ /** The size in texels of a texture's image, or null when it has none to read. */
74
+ function texelsOf(image) {
75
+ if (typeof image !== "object" || image === null || !("width" in image) || !("height" in image))
76
+ return null;
77
+ const { width, height } = image;
78
+ return typeof width === "number" && typeof height === "number" ? [width, height] : null;
79
+ }
80
+ /**
81
+ * A context in which every texture read is `bias` mip levels above the level the
82
+ * hardware would pick: the level from the read's own texel footprint, plus `bias`. Reads
83
+ * with uv of their own making, or with an explicit level or gradients, keep theirs.
84
+ */
85
+ export function biasedTextures(bias) {
86
+ return context({
87
+ getTextureLevel: (node) => {
88
+ const texture = node.value;
89
+ const size = texelsOf(texture.image);
90
+ if (node.uvNode || !size)
91
+ return null;
92
+ // The texture's offset, repeat and rotation, as three applies them.
93
+ const at = uniform(texture.matrix).mul(vec3(uv(texture.channel), 1)).xy;
94
+ const texels = at.mul(vec2(size[0], size[1]));
95
+ return log2(max(max(length(dFdx(texels)), length(dFdy(texels))), 1e-6)).add(bias);
96
+ },
97
+ });
98
+ }
99
+ //# sourceMappingURL=tsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tsl.js","sourceRoot":"","sources":["../src/tsl.ts"],"names":[],"mappings":"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"}
package/dist/view.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ import { Vector3, type Camera, type Matrix4, type Mesh, type Sphere } from "three/webgpu";
2
+ /**
3
+ * The angle `sphere` (in the space `root` maps to world) subtends from `eye`, small-angle:
4
+ * its diameter, scaled by the largest axis scale of `root`, over its distance.
5
+ */
6
+ export declare function subtense(root: Matrix4, sphere: Sphere, eye: Vector3): number;
7
+ /** How a camera measures objects on screen: from where, and pixels per unit of subtense (or of size, orthographic). */
8
+ export declare class View {
9
+ readonly eye: Vector3;
10
+ ortho: boolean;
11
+ scale: number;
12
+ /** Whether levels fade (not with an orthographic camera or a forced level). */
13
+ fades: boolean;
14
+ /** Read `camera`, drawing into a viewport `height` pixels tall. */
15
+ begin(camera: Camera, height: number, forceLevel: number | null): this;
16
+ /** On-screen height of `sphere`, given in the space `root` maps to world. */
17
+ pixels(root: Matrix4, sphere: Sphere): number;
18
+ }
19
+ /**
20
+ * Set the view height before the first LOD update, or after a resize while no level
21
+ * meshes draw. Use CSS pixels for the canvas or a full-size postprocessing target;
22
+ * use target pixels for other render targets. Subsequent draws measure it automatically.
23
+ */
24
+ export declare function setViewportHeight(camera: Camera, height: number): void;
25
+ /** The explicit or last drawn height, or null before either is known. */
26
+ export declare const viewportHeight: (camera: Camera) => number | null;
27
+ /** Learn the height whenever `mesh` draws. */
28
+ export declare function watchViewport(mesh: Mesh): void;
29
+ /** A typical screen's height, for a camera no level mesh drew with yet. */
30
+ export declare const TYPICAL_HEIGHT = 1080;
package/dist/view.js ADDED
@@ -0,0 +1,75 @@
1
+ import { Vector2, Vector3, Vector4 } from "three/webgpu";
2
+ import { gpuRenderer, inShadowPass } from "./three.js";
3
+ const scratch = new Vector3();
4
+ /**
5
+ * The angle `sphere` (in the space `root` maps to world) subtends from `eye`, small-angle:
6
+ * its diameter, scaled by the largest axis scale of `root`, over its distance.
7
+ */
8
+ export function subtense(root, sphere, eye) {
9
+ const centre = scratch.copy(sphere.center).applyMatrix4(root);
10
+ return (2 * sphere.radius * root.getMaxScaleOnAxis()) / Math.max(eye.distanceTo(centre), 1e-6);
11
+ }
12
+ /** How a camera measures objects on screen: from where, and pixels per unit of subtense (or of size, orthographic). */
13
+ export class View {
14
+ eye = new Vector3();
15
+ ortho = false;
16
+ scale = 0;
17
+ /** Whether levels fade (not with an orthographic camera or a forced level). */
18
+ fades = false;
19
+ /** Read `camera`, drawing into a viewport `height` pixels tall. */
20
+ begin(camera, height, forceLevel) {
21
+ const projection = camera.projectionMatrix.elements;
22
+ this.ortho = projection[15] === 1;
23
+ this.scale = ((projection[5] ?? 0) * height) / 2;
24
+ this.eye.setFromMatrixPosition(camera.matrixWorld);
25
+ this.fades = forceLevel === null && !this.ortho;
26
+ return this;
27
+ }
28
+ /** On-screen height of `sphere`, given in the space `root` maps to world. */
29
+ pixels(root, sphere) {
30
+ const size = this.ortho ? 2 * sphere.radius * root.getMaxScaleOnAxis() : subtense(root, sphere, this.eye);
31
+ return size * this.scale;
32
+ }
33
+ }
34
+ const viewport = new Vector4();
35
+ const canvas = new Vector2();
36
+ /**
37
+ * The viewport height each camera draws at, as the level meshes drawn with it see it: CSS
38
+ * pixels on the canvas, so that a high-density screen picks the levels a standard one
39
+ * does and pays for its extra pixels only in fill; pixels in a render target, except one
40
+ * the canvas's size, which stands in for it (a post-processing pass). Every level
41
+ * mesh that draws tells it for all: a Lod or InstancedLod with nothing drawn learns it
42
+ * from the others.
43
+ */
44
+ const heights = new WeakMap();
45
+ /**
46
+ * Set the view height before the first LOD update, or after a resize while no level
47
+ * meshes draw. Use CSS pixels for the canvas or a full-size postprocessing target;
48
+ * use target pixels for other render targets. Subsequent draws measure it automatically.
49
+ */
50
+ export function setViewportHeight(camera, height) {
51
+ if (!Number.isFinite(height) || height <= 0)
52
+ throw new RangeError("LOD viewport height must be finite and positive");
53
+ heights.set(camera, height);
54
+ }
55
+ /** The explicit or last drawn height, or null before either is known. */
56
+ export const viewportHeight = (camera) => heights.get(camera) ?? null;
57
+ /** Learn the height whenever `mesh` draws. */
58
+ export function watchViewport(mesh) {
59
+ const previous = mesh.onBeforeRender;
60
+ mesh.onBeforeRender = (renderer, scene, camera, geometry, material, group) => {
61
+ previous.call(mesh, renderer, scene, camera, geometry, material, group);
62
+ // Shadow maps are drawn for the viewing camera's choice, not measured.
63
+ if (inShadowPass(scene))
64
+ return;
65
+ const gpu = gpuRenderer(renderer);
66
+ const target = gpu.getRenderTarget();
67
+ if (!target)
68
+ return void heights.set(camera, gpu.getViewport(viewport).w);
69
+ const ratio = target.height === gpu.getDrawingBufferSize(canvas).y ? gpu.getPixelRatio() : 1;
70
+ heights.set(camera, target.viewport.w / ratio);
71
+ };
72
+ }
73
+ /** A typical screen's height, for a camera no level mesh drew with yet. */
74
+ export const TYPICAL_HEIGHT = 1080;
75
+ //# sourceMappingURL=view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Matrix4, type Mesh } from "three/webgpu";
2
+ /** Bound maximum sway on the mesh itself, leaving shared geometry in its rest pose. */
3
+ export declare function windBounds(mesh: Mesh, placement: Matrix4, amplitude: number, baseY: number, height: number): void;
@@ -0,0 +1,47 @@
1
+ import { Matrix4, Sphere, Vector3 } from "three/webgpu";
2
+ import { drawOf } from "../fade.js";
3
+ import { isImpostorMesh, isInstancedMesh } from "../three.js";
4
+ /** Bound maximum sway on the mesh itself, leaving shared geometry in its rest pose. */
5
+ export function windBounds(mesh, placement, amplitude, baseY, height) {
6
+ const { geometry } = mesh;
7
+ if (!geometry.boundingBox)
8
+ geometry.computeBoundingBox();
9
+ const box = geometry.boundingBox;
10
+ if (!box || box.isEmpty())
11
+ return;
12
+ if (placement.determinant() === 0)
13
+ throw new Error("Wind: a mesh's placement must be invertible");
14
+ const rest = box.getBoundingSphere(new Sphere());
15
+ const root = box.clone().applyMatrix4(placement);
16
+ const reach = Math.max(Math.abs(root.min.y - baseY), Math.abs(root.max.y - baseY)) / height;
17
+ rest.radius += amplitude * reach * horizontalScale(placement.clone().invert());
18
+ // An ImpostorMesh of its own measures its shadow casters by this radius too.
19
+ const draw = drawOf(mesh);
20
+ if (draw?.kind === "instances")
21
+ draw.radius = rest.radius;
22
+ const instances = isInstancedMesh(mesh) || isImpostorMesh(mesh) ? mesh : null;
23
+ if (!instances) {
24
+ // Frustum.intersectsObject prefers an object's sphere over its geometry's.
25
+ Object.assign(mesh, { boundingSphere: rest });
26
+ return;
27
+ }
28
+ // As for InstancedMesh normally, callers recompute after changing instance transforms.
29
+ // Start from the geometry's rest box every time wind is attached, including on clones.
30
+ instances.computeBoundingSphere = () => {
31
+ const bounds = (instances.boundingSphere ??= new Sphere()).makeEmpty();
32
+ const matrix = new Matrix4();
33
+ const sphere = new Sphere();
34
+ for (let i = 0; i < instances.count; i++)
35
+ bounds.union(sphere.copy(rest).applyMatrix4(instances.getMatrixAt(i, matrix)));
36
+ };
37
+ instances.computeBoundingSphere();
38
+ }
39
+ /** Largest stretch of a horizontal unit vector, including sheared placements. */
40
+ function horizontalScale(matrix) {
41
+ const x = new Vector3().setFromMatrixColumn(matrix, 0);
42
+ const z = new Vector3().setFromMatrixColumn(matrix, 2);
43
+ const xx = x.lengthSq();
44
+ const zz = z.lengthSq();
45
+ return Math.sqrt((xx + zz + Math.hypot(xx - zz, 2 * x.dot(z))) / 2);
46
+ }
47
+ //# sourceMappingURL=bounds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bounds.js","sourceRoot":"","sources":["../../src/wind/bounds.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** Setup-only culling and caster padding; selection and fades keep their rest bounds. */
2
+ export declare const WIND_BOUNDS: unique symbol;
3
+ export interface WindBounds {
4
+ [WIND_BOUNDS](padding: number, slope: number, baseY: number): void;
5
+ }
@@ -0,0 +1,3 @@
1
+ /** Setup-only culling and caster padding; selection and fades keep their rest bounds. */
2
+ export const WIND_BOUNDS = Symbol("wind bounds");
3
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/wind/hooks.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { type Object3D } from "three/webgpu";
2
+ export interface WindOptions {
3
+ /** Horizontal world-space X/Z direction; normalized on assignment. Default [1, 0]. */
4
+ direction?: readonly [number, number];
5
+ /** Oscillations per second; default 0.25. */
6
+ speed?: number;
7
+ }
8
+ export interface SwayOptions {
9
+ /** Maximum sideways displacement at baseY + height, in the root's units. */
10
+ amplitude: number;
11
+ /** Fixed base in the root's space; defaults to the source's lowest point. */
12
+ baseY?: number;
13
+ /** Height above the fixed base; defaults to the source's top minus baseY. */
14
+ height?: number;
15
+ }
16
+ /**
17
+ * A shared GPU breeze: an affine sway, fixed at the base and linear with height.
18
+ * Bake/build levels first, apply once to the completed Lod, InstancedLod, mesh or
19
+ * mesh group, then set time once before rendering each frame. All levels and shadow
20
+ * passes share the motion. Simplified and baked meshes need no special preparation.
21
+ *
22
+ * Instances derive their phase from the undeformed root's world position, so slot
23
+ * sorting never changes it. The breeze follows the root's horizontal plane; upright
24
+ * trees with different rotations still follow the same world direction.
25
+ *
26
+ * Bounds cover strength 0..1. Geometry, instance matrices and LOD lists are not updated
27
+ * by the clock. CPU raycasts still hit the rest pose. Mesh placements within a root
28
+ * must stay fixed after applying; move/rotate/scale the root or its instances instead.
29
+ * Nested LODs and nested instance batches must be applied individually; an
30
+ * InstancedMesh sways only with its matrices in a storage buffer (an ImpostorMesh's are).
31
+ * Lod, InstancedLod and ImpostorMesh clones retain the shared breeze. For ordinary
32
+ * Mesh/Group clones, apply to each clone too: the material is shared but the sway is
33
+ * the mesh's. Tangent-space normal maps are supported (tangents do not sway);
34
+ * object-space normal maps are not.
35
+ */
36
+ export declare class Wind {
37
+ private readonly breeze;
38
+ constructor({ direction, speed }?: WindOptions);
39
+ /** Shared animation time in seconds; update once per frame, before any render pass. */
40
+ get time(): number;
41
+ set time(value: number);
42
+ /** Oscillations per second; zero freezes the time-dependent part of the phase. */
43
+ get speed(): number;
44
+ set speed(value: number);
45
+ /** Global amplitude multiplier in [0, 1]. Zero keeps the wind shader but draws the rest pose. */
46
+ get strength(): number;
47
+ set strength(value: number);
48
+ get direction(): readonly [number, number];
49
+ set direction([x, z]: readonly [number, number]);
50
+ /** Attach once, after constructing all levels. Objects without this call keep their original shaders. */
51
+ apply(root: Object3D, { amplitude, baseY, height }: SwayOptions): void;
52
+ /** Attach meshes installed by a lazy level; existing meshes retain their bounds. */
53
+ private attach;
54
+ }
55
+ /** Rebuilt LODs and impostors share the clock, with their own placements and bounds. */
56
+ export declare function copyWind(source: Object3D, target: Object3D): void;
57
+ export declare function refreshWind(root: Object3D): void;
@@ -0,0 +1,196 @@
1
+ import { Box3, Matrix4, ObjectSpaceNormalMap, Vector2 } from "three/webgpu";
2
+ import { boundingBox } from "../bounds.js";
3
+ import { levelMaterial } from "../material.js";
4
+ import { isBatchedMesh, isImpostorMesh, isInstancedLod, isInstancedMesh, isLOD, isMesh, isSkinnedMesh, isStorageInstanced } from "../three.js";
5
+ import { WIND_BOUNDS } from "./hooks.js";
6
+ import { windBounds } from "./bounds.js";
7
+ import { setSway, swayMatrix } from "./sway.js";
8
+ const bindings = new WeakMap();
9
+ const attached = new WeakSet();
10
+ const identity = new Matrix4();
11
+ /**
12
+ * A shared GPU breeze: an affine sway, fixed at the base and linear with height.
13
+ * Bake/build levels first, apply once to the completed Lod, InstancedLod, mesh or
14
+ * mesh group, then set time once before rendering each frame. All levels and shadow
15
+ * passes share the motion. Simplified and baked meshes need no special preparation.
16
+ *
17
+ * Instances derive their phase from the undeformed root's world position, so slot
18
+ * sorting never changes it. The breeze follows the root's horizontal plane; upright
19
+ * trees with different rotations still follow the same world direction.
20
+ *
21
+ * Bounds cover strength 0..1. Geometry, instance matrices and LOD lists are not updated
22
+ * by the clock. CPU raycasts still hit the rest pose. Mesh placements within a root
23
+ * must stay fixed after applying; move/rotate/scale the root or its instances instead.
24
+ * Nested LODs and nested instance batches must be applied individually; an
25
+ * InstancedMesh sways only with its matrices in a storage buffer (an ImpostorMesh's are).
26
+ * Lod, InstancedLod and ImpostorMesh clones retain the shared breeze. For ordinary
27
+ * Mesh/Group clones, apply to each clone too: the material is shared but the sway is
28
+ * the mesh's. Tangent-space normal maps are supported (tangents do not sway);
29
+ * object-space normal maps are not.
30
+ */
31
+ export class Wind {
32
+ breeze = { time: 0, speed: 0.25, strength: 1, direction: new Vector2(1, 0) };
33
+ constructor({ direction = [1, 0], speed = 0.25 } = {}) {
34
+ this.direction = direction;
35
+ this.speed = speed;
36
+ }
37
+ /** Shared animation time in seconds; update once per frame, before any render pass. */
38
+ get time() {
39
+ return this.breeze.time;
40
+ }
41
+ set time(value) {
42
+ finite(value, "time");
43
+ this.breeze.time = value;
44
+ }
45
+ /** Oscillations per second; zero freezes the time-dependent part of the phase. */
46
+ get speed() {
47
+ return this.breeze.speed;
48
+ }
49
+ set speed(value) {
50
+ nonnegative(value, "speed");
51
+ this.breeze.speed = value;
52
+ }
53
+ /** Global amplitude multiplier in [0, 1]. Zero keeps the wind shader but draws the rest pose. */
54
+ get strength() {
55
+ return this.breeze.strength;
56
+ }
57
+ set strength(value) {
58
+ nonnegative(value, "strength");
59
+ if (value > 1)
60
+ throw new Error("Wind: strength must be in [0, 1]");
61
+ this.breeze.strength = value;
62
+ }
63
+ get direction() {
64
+ const { x, y } = this.breeze.direction;
65
+ return [x, y];
66
+ }
67
+ set direction([x, z]) {
68
+ finite(x, "direction.x");
69
+ finite(z, "direction.z");
70
+ if (Math.hypot(x, z) === 0)
71
+ throw new Error("Wind: direction must be nonzero");
72
+ this.breeze.direction.set(x, z).normalize();
73
+ }
74
+ /** Attach once, after constructing all levels. Objects without this call keep their original shaders. */
75
+ apply(root, { amplitude, baseY, height }) {
76
+ if (bindings.has(root))
77
+ throw new Error("Wind: already applied to this object");
78
+ this.attach(root, { amplitude, baseY, height }, false);
79
+ }
80
+ /** Attach meshes installed by a lazy level; existing meshes retain their bounds. */
81
+ attach(root, { amplitude, baseY, height }, refreshing) {
82
+ nonnegative(amplitude, "amplitude");
83
+ const box = sourceBox(root);
84
+ if (box.isEmpty())
85
+ throw new Error("Wind: object has no geometry");
86
+ const base = baseY ?? box.min.y;
87
+ const size = height ?? box.max.y - base;
88
+ finite(base, "baseY");
89
+ finite(size, "height");
90
+ if (size <= 0)
91
+ throw new Error("Wind: height must be positive");
92
+ const meshes = [];
93
+ root.traverse((node) => {
94
+ if (node !== root && isLOD(node))
95
+ throw new Error("Wind: apply to nested LODs individually");
96
+ if (!isMesh(node))
97
+ return;
98
+ if (refreshing && attached.has(node))
99
+ return;
100
+ if (attached.has(node))
101
+ throw new Error("Wind: a mesh already belongs to a wind root");
102
+ if (isSkinnedMesh(node) || isBatchedMesh(node))
103
+ throw new Error("Wind: skinned and batched meshes are not supported");
104
+ if (node !== root && !isInstancedLod(root) && (isInstancedMesh(node) || (isImpostorMesh(node) && node.count > 1)))
105
+ throw new Error("Wind: apply to nested instance batches individually");
106
+ if (isInstancedMesh(node) && !isStorageInstanced(node.instanceMatrix))
107
+ throw new Error(`Wind: InstancedMesh "${node.name}" needs its instance matrices in a StorageInstancedBufferAttribute`);
108
+ if ([node.material]
109
+ .flat()
110
+ .some((material) => "normalMapType" in material && material.normalMapType === ObjectSpaceNormalMap && "normalMap" in material && material.normalMap))
111
+ throw new Error("Wind: use tangent-space normal maps");
112
+ meshes.push(node);
113
+ });
114
+ if (meshes.length === 0) {
115
+ if (refreshing)
116
+ return;
117
+ throw new Error("Wind: object has no meshes");
118
+ }
119
+ root.updateWorldMatrix(true, true);
120
+ invertible(root.matrixWorld);
121
+ const inverse = root.matrixWorld.clone().invert();
122
+ const placed = meshes.map((mesh) => {
123
+ // InstancedLod has already placed ordinary geometry in instance space; its
124
+ // impostors carry placement separately. Avoid roundoff defeating the fast path.
125
+ const placement = mesh === root || isInstancedLod(root) ? identity.clone() : inverse.clone().multiply(mesh.matrixWorld);
126
+ invertible(placement);
127
+ return { mesh, placement };
128
+ });
129
+ const shape = new Vector2(amplitude / size, base);
130
+ const padding = (amplitude * Math.max(Math.abs(box.min.y - base), Math.abs(box.max.y - base))) / size;
131
+ if (hasBounds(root) && (!refreshing || isInstancedLod(root)))
132
+ root[WIND_BOUNDS](padding, amplitude / size, base);
133
+ for (const { mesh, placement } of placed) {
134
+ if (!isInstancedLod(root))
135
+ windBounds(mesh, placement, amplitude, base, size);
136
+ setSway(mesh, { breeze: this.breeze, shape, placement, fromRoot: placement.clone().invert() });
137
+ if (isImpostorMesh(mesh)) {
138
+ mesh.material.deformNode = swayMatrix();
139
+ mesh.material.needsUpdate = true;
140
+ }
141
+ else
142
+ mesh.material = Array.isArray(mesh.material) ? mesh.material.map((m) => levelMaterial(m, true)) : levelMaterial(mesh.material, true);
143
+ attached.add(mesh);
144
+ }
145
+ const options = { amplitude, baseY: base, height: size };
146
+ bindings.set(root, { wind: this, options, refresh: () => this.attach(root, options, true) });
147
+ }
148
+ }
149
+ function hasBounds(root) {
150
+ return WIND_BOUNDS in root;
151
+ }
152
+ function sourceBox(root) {
153
+ if (isLOD(root)) {
154
+ for (const { object } of root.levels) {
155
+ const box = boundingBox(object);
156
+ if (box.isEmpty())
157
+ continue;
158
+ if (object.matrixAutoUpdate)
159
+ object.updateMatrix();
160
+ return box.applyMatrix4(object.matrix);
161
+ }
162
+ return new Box3();
163
+ }
164
+ if (isImpostorMesh(root))
165
+ return new Box3().setFromArray(root.impostor.box);
166
+ if (isInstancedMesh(root)) {
167
+ root.geometry.computeBoundingBox();
168
+ return root.geometry.boundingBox?.clone() ?? new Box3();
169
+ }
170
+ return boundingBox(root);
171
+ }
172
+ function invertible(matrix) {
173
+ const determinant = matrix.determinant();
174
+ if (!Number.isFinite(determinant) || determinant === 0)
175
+ throw new Error("Wind: root and mesh placements must be finite and invertible");
176
+ }
177
+ function finite(value, name) {
178
+ if (!Number.isFinite(value))
179
+ throw new Error(`Wind: ${name} must be finite`);
180
+ }
181
+ function nonnegative(value, name) {
182
+ finite(value, name);
183
+ if (value < 0)
184
+ throw new Error(`Wind: ${name} must be nonnegative`);
185
+ }
186
+ /** Rebuilt LODs and impostors share the clock, with their own placements and bounds. */
187
+ export function copyWind(source, target) {
188
+ const binding = bindings.get(source);
189
+ if (binding)
190
+ binding.wind.apply(target, binding.options);
191
+ }
192
+ export function refreshWind(root) {
193
+ const binding = bindings.get(root);
194
+ binding?.refresh();
195
+ }
196
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/wind/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { Matrix4, Vector2, type Node, type Object3D } from "three/webgpu";
2
+ /** A Wind's state, which every object it sways reads. */
3
+ export interface Breeze {
4
+ time: number;
5
+ /** oscillations per second */
6
+ speed: number;
7
+ /** amplitude multiplier in [0, 1] */
8
+ strength: number;
9
+ /** horizontal world direction, unit */
10
+ direction: Vector2;
11
+ }
12
+ /** How one mesh sways. */
13
+ export interface Sway {
14
+ breeze: Breeze;
15
+ /** sideways displacement per unit of height at full swing, and the base's height, in the root's space */
16
+ shape: Vector2;
17
+ /** the mesh's space (before any instance matrix) in the root's, and back */
18
+ placement: Matrix4;
19
+ fromRoot: Matrix4;
20
+ }
21
+ /** Sway `mesh` as `sway` says. */
22
+ export declare const setSway: (mesh: Object3D, sway: Sway) => void;
23
+ /**
24
+ * `position` (a mesh's, after its instance matrix) swayed, and its normal with it. three
25
+ * applies instance matrices first: the sway is carried into the instanced space.
26
+ */
27
+ export declare const sway: (position: Node<"vec3">) => Node<"vec3">;
28
+ /** The sway as a matrix in the mesh's own space, for an ImpostorMesh's card (which inverts it). */
29
+ export declare const swayMatrix: import("three/src/nodes/TSL.js").FnNode<[], import("three/webgpu").VarNode<"mat4", import("three/webgpu").JoinNode<"mat4">>>;