@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
@@ -0,0 +1,151 @@
1
+ import { BufferAttribute, BufferGeometry, DataTexture, DoubleSide, FrontSide, LinearFilter, LinearMipmapLinearFilter, Mesh, MeshStandardNodeMaterial, Matrix4, NoColorSpace, RGFormat, RGBAFormat, SRGBColorSpace, UnsignedByteType, Vector3, } from "three/webgpu";
2
+ import { boundingBox, forEachMesh } from "../bounds.js";
3
+ import { recordError } from "../levels.js";
4
+ import { sharedRenderer } from "../renderer.js";
5
+ import { readSource } from "../source/source.js";
6
+ import { area } from "../source/surface.js";
7
+ import { mipmaps } from "../source/texels.js";
8
+ import { isImpostorMesh, placeLike } from "../three.js";
9
+ import { renderFaces } from "./interior/faces.js";
10
+ import { InteriorMaterial } from "./interior/material.js";
11
+ import { readBoxes } from "./interior/rooms.js";
12
+ import { layOut, simplified } from "./low.js";
13
+ import { transfer } from "./transfer.js";
14
+ import { keepCoverage } from "./coverage.js";
15
+ /**
16
+ * Bake `source` (in its own space, ignoring its own transform) onto one low-poly mesh with
17
+ * its own textures: base colour (alpha: cut out or not), tangent-space normal and
18
+ * occlusion/roughness/metalness, drawn with a MeshStandardNodeMaterial. The mesh is placed
19
+ * like `source`. Materials are read on the CPU as MeshStandardMaterials (color, map,
20
+ * alphaTest, roughness, metalness, normal and ao maps); emissive, clearcoat, transmission
21
+ * and the like are not baked, and blended transparency bakes opaque: glass in its own
22
+ * colour, or as windows into the rooms of `interior`. Textures must be readable on the
23
+ * CPU (no compressed textures).
24
+ *
25
+ * Nested LODs are baked at their level 0; InstancedMeshes, and the source level of an
26
+ * InstancedLod, once per instance: a field of plants bakes as a whole. Skinned meshes
27
+ * and ImpostorMeshes (which have no surface to read) are refused.
28
+ *
29
+ * For each texel of the low mesh, the outermost source surface along the low mesh's
30
+ * normal is shaded. How far the result is off, the larger of a texel's size and the low
31
+ * surface's distance from the source, sets its default maxPixels in a Lod.
32
+ *
33
+ * Experimental, and slow: it runs on the calling thread, yielding to the page now and
34
+ * then.
35
+ */
36
+ export async function bakeMesh(source, options = {}) {
37
+ const { interior } = options;
38
+ if (!interior)
39
+ return bake(source, options, null);
40
+ const placement = placementOf(interior, source);
41
+ const boxes = readBoxes(interior, placement);
42
+ // Hidden for the whole bake, which yields: a scene drawing it meanwhile shows it gone.
43
+ const visible = interior.visible;
44
+ interior.visible = false;
45
+ try {
46
+ return await bake(source, options, { object: interior, placement, boxes });
47
+ }
48
+ finally {
49
+ interior.visible = visible;
50
+ }
51
+ }
52
+ async function bake(source, options, interior) {
53
+ forEachMesh(source, (mesh) => {
54
+ if (isImpostorMesh(mesh))
55
+ throw new Error(`bakeMesh: cannot bake an ImpostorMesh ("${mesh.name}"); bake from its source instead`);
56
+ });
57
+ const input = readSource(source, "bakeMesh", "bake");
58
+ const size = options.textureSize ?? (input.cutout ? 512 : 1024);
59
+ if (!Number.isInteger(size) || size < 16)
60
+ throw new Error(`bakeMesh: textureSize must be an integer >= 16, got ${size}`);
61
+ const ratio = options.ratio ?? 0.05;
62
+ if (!(ratio > 0 && ratio <= 1))
63
+ throw new Error(`bakeMesh: ratio must be in (0, 1], got ${ratio}`);
64
+ const low = await layOut(options.low ?? (await simplified(input, ratio)), input, size);
65
+ if (low.raster.covered === 0)
66
+ throw new Error("bakeMesh: the low mesh covers no texel");
67
+ const texelSize = Math.sqrt(area(low) / low.raster.covered);
68
+ const radius = boundingBox(source).getSize(new Vector3()).length() / 2;
69
+ // How far rays search: far enough for every feature the low mesh cut off, never so far
70
+ // that they reach through to the other side of thin parts.
71
+ const reach = Math.min(Math.max(low.widest * 1.25, radius * 0.005), radius * 0.15);
72
+ const maps = await transfer(input, low, reach, texelSize, interior && interior.boxes);
73
+ const geometry = new BufferGeometry();
74
+ geometry.setAttribute("position", new BufferAttribute(low.positions, 3));
75
+ geometry.setAttribute("normal", new BufferAttribute(low.normals, 3));
76
+ geometry.setAttribute("uv", new BufferAttribute(low.uvs, 2));
77
+ geometry.setIndex(new BufferAttribute(low.index, 1));
78
+ geometry.computeBoundingBox();
79
+ geometry.computeBoundingSphere();
80
+ const orm = bakedTexture({ data: maps.orm, width: size, height: size }, NoColorSpace);
81
+ const color = { data: maps.color, width: size, height: size };
82
+ const material = new (interior ? InteriorMaterial : MeshStandardNodeMaterial)({
83
+ // Cut-outs get mips that keep their coverage; else the GPU's are as good.
84
+ map: bakedTexture(color, SRGBColorSpace, input.cutout ? keepCoverage(mipmaps(color, true)) : undefined),
85
+ normalMap: bakedTexture({ data: maps.normal, width: size, height: size }, NoColorSpace),
86
+ aoMap: orm,
87
+ roughnessMap: orm,
88
+ metalnessMap: orm,
89
+ roughness: 1,
90
+ metalness: 1,
91
+ alphaTest: input.cutout ? 0.5 : 0,
92
+ side: input.inputs.some((inputs) => inputs.doubleSided) ? DoubleSide : FrontSide,
93
+ });
94
+ if (interior && material instanceof InteriorMaterial) {
95
+ const { windows } = maps;
96
+ if (!windows.some((value, i) => i % 2 === 0 && value > 0))
97
+ throw new Error("bakeMesh: no glass of the source looks into a room of the interior");
98
+ const { boxes } = interior;
99
+ const faces = await renderFaces(interior.object, interior.placement, boxes, faceSize(size, boxes.length), await sharedRenderer());
100
+ material.furnish({ ...faces, boxes, windows: windowTexture(windows, size) });
101
+ }
102
+ const mesh = new Mesh(geometry, material);
103
+ mesh.name = `${source.name || "object"} baked`;
104
+ placeLike(mesh, source);
105
+ recordError(mesh, Math.max(texelSize, low.error));
106
+ return mesh;
107
+ }
108
+ /**
109
+ * Pixels per side of each room's cube faces: all of them together about as many as one
110
+ * baked map of `size`², within 32..256.
111
+ */
112
+ const faceSize = (size, rooms) => Math.min(256, Math.max(32, 2 ** Math.floor(Math.log2(size / Math.sqrt(6 * rooms)))));
113
+ /** Where `interior` sits in `source`'s own space: as a child of it, or where it is if inside it. */
114
+ function placementOf(interior, source) {
115
+ let inside = false;
116
+ interior.traverseAncestors((node) => (inside ||= node === source));
117
+ if (!inside) {
118
+ if (interior.matrixAutoUpdate)
119
+ interior.updateMatrix();
120
+ return interior.matrix.clone();
121
+ }
122
+ interior.updateWorldMatrix(true, false);
123
+ return source.matrixWorld.clone().invert().multiply(interior.matrixWorld);
124
+ }
125
+ /** The windows of `transfer`, as a texture: its share is filtered, its rooms read texel by texel. */
126
+ function windowTexture(windows, size) {
127
+ const texture = new DataTexture(windows, size, size, RGFormat, UnsignedByteType);
128
+ texture.minFilter = LinearMipmapLinearFilter;
129
+ texture.magFilter = LinearFilter;
130
+ texture.generateMipmaps = true;
131
+ texture.unpackAlignment = 1;
132
+ texture.needsUpdate = true;
133
+ return texture;
134
+ }
135
+ /** A texture of baked pixels, with `mips` as its mipmaps if given, else the GPU's. */
136
+ function bakedTexture(base, colorSpace, mips) {
137
+ const texture = new DataTexture(new Uint8Array(base.data.buffer), base.width, base.height, RGBAFormat, UnsignedByteType);
138
+ texture.colorSpace = colorSpace;
139
+ texture.minFilter = LinearMipmapLinearFilter;
140
+ texture.magFilter = LinearFilter;
141
+ texture.anisotropy = 4;
142
+ if (mips) {
143
+ texture.mipmaps = mips.map(({ data, width, height }) => ({ data: new Uint8Array(data.buffer), width, height }));
144
+ texture.generateMipmaps = false;
145
+ }
146
+ else
147
+ texture.generateMipmaps = true;
148
+ texture.needsUpdate = true;
149
+ return texture;
150
+ }
151
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/baked/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { Box3, DataArrayTexture, Vector3, type Matrix4, type Object3D, type Renderer } from "three/webgpu";
2
+ /**
3
+ * The six faces of a room's cube, in layer order: the direction each looks and its up.
4
+ * Its right is forward × up. The baked material's shader (material.ts) reads this table.
5
+ */
6
+ export declare const FACES: ReadonlyArray<readonly [forward: Vector3, up: Vector3]>;
7
+ /** What each room shows, per cube face: see `renderFaces`. */
8
+ export interface Faces {
9
+ /** the light each room reflects under white ambient light of irradiance π: its colours */
10
+ response: DataArrayTexture;
11
+ /** the light each room gives off itself (emissive and unlit materials); null when none does */
12
+ glow: DataArrayTexture | null;
13
+ /** how far each face's view reaches past its edges: tan of half its field of view */
14
+ span: number;
15
+ }
16
+ /**
17
+ * Render each room of `interior` (placed in the source's space by `placement`) from its
18
+ * box's centre, six square `size`-pixel views, with the exterior hidden and the other
19
+ * rooms shown, seen through doorways: once in white ambient light and once in none. The difference is how the room
20
+ * responds to light, which the baked material scales by the light reaching its windows;
21
+ * what shows without light is the room's glow. Layer room × 6 + face of each result,
22
+ * sRGB, rows bottom-up: (u, v) = (0.5, 0.5) + 0.5 × (x, y) / (z × span), with x, y and z
23
+ * along the face's right, up and forward. Each view reaches a texel past its edges, so
24
+ * filtering at a face's border reads the neighbouring face's content.
25
+ */
26
+ export declare function renderFaces(interior: Object3D, placement: Matrix4, boxes: readonly Box3[], size: number, renderer: Renderer): Promise<Faces>;
@@ -0,0 +1,105 @@
1
+ import { AmbientLight, Box3, DataArrayTexture, LinearFilter, LinearMipmapLinearFilter, MathUtils, PerspectiveCamera, SRGBColorSpace, Scene, RenderTarget, UnsignedByteType, Vector3, } from "three/webgpu";
2
+ import { showDetail } from "../../bounds.js";
3
+ import { pause } from "../../pause.js";
4
+ import { borrow, readBytes } from "../../renderer.js";
5
+ import { linearToSrgb, srgbToLinear } from "../../source/texels.js";
6
+ /**
7
+ * The six faces of a room's cube, in layer order: the direction each looks and its up.
8
+ * Its right is forward × up. The baked material's shader (material.ts) reads this table.
9
+ */
10
+ export const FACES = [
11
+ [new Vector3(1, 0, 0), new Vector3(0, 1, 0)],
12
+ [new Vector3(-1, 0, 0), new Vector3(0, 1, 0)],
13
+ [new Vector3(0, 1, 0), new Vector3(0, 0, -1)],
14
+ [new Vector3(0, -1, 0), new Vector3(0, 0, 1)],
15
+ [new Vector3(0, 0, 1), new Vector3(0, 1, 0)],
16
+ [new Vector3(0, 0, -1), new Vector3(0, 1, 0)],
17
+ ];
18
+ /**
19
+ * Render each room of `interior` (placed in the source's space by `placement`) from its
20
+ * box's centre, six square `size`-pixel views, with the exterior hidden and the other
21
+ * rooms shown, seen through doorways: once in white ambient light and once in none. The difference is how the room
22
+ * responds to light, which the baked material scales by the light reaching its windows;
23
+ * what shows without light is the room's glow. Layer room × 6 + face of each result,
24
+ * sRGB, rows bottom-up: (u, v) = (0.5, 0.5) + 0.5 × (x, y) / (z × span), with x, y and z
25
+ * along the face's right, up and forward. Each view reaches a texel past its edges, so
26
+ * filtering at a face's border reads the neighbouring face's content.
27
+ */
28
+ export async function renderFaces(interior, placement, boxes, size, renderer) {
29
+ const copy = interior.clone();
30
+ copy.matrixAutoUpdate = false;
31
+ copy.matrix.copy(placement);
32
+ copy.visible = true;
33
+ showDetail(copy);
34
+ // At π, three's Lambert (albedo / π) shows a surface in its own colour.
35
+ const ambient = new AmbientLight(0xffffff, Math.PI);
36
+ const scene = new Scene().add(copy, ambient);
37
+ scene.updateMatrixWorld(true);
38
+ const span = 1 + 2 / size;
39
+ const camera = new PerspectiveCamera(MathUtils.radToDeg(2 * Math.atan(span)), 1);
40
+ camera.matrixAutoUpdate = false;
41
+ camera.layers.enableAll();
42
+ const target = new RenderTarget(size, size, { type: UnsignedByteType, colorSpace: SRGBColorSpace, depthBuffer: true });
43
+ const face = size * size * 4;
44
+ const lit = new Uint8Array(face * 6 * boxes.length);
45
+ const glow = new Uint8Array(face * 6 * boxes.length);
46
+ const right = new Vector3();
47
+ const back = new Vector3();
48
+ const centre = new Vector3();
49
+ const extent = new Vector3();
50
+ const shoot = async (into) => {
51
+ const restore = borrow(renderer, target);
52
+ try {
53
+ renderer.clear(true, true, true);
54
+ renderer.render(scene, camera);
55
+ }
56
+ finally {
57
+ restore();
58
+ }
59
+ into.set(await readBytes(renderer, target, 0));
60
+ };
61
+ // Far enough to see through doorways into any other room.
62
+ const reach = boxes
63
+ .reduce((all, box) => all.union(box), new Box3())
64
+ .getSize(extent)
65
+ .length() * 2;
66
+ try {
67
+ for (const [i, box] of boxes.entries()) {
68
+ camera.near = box.getSize(extent).length() * 1e-3;
69
+ camera.far = reach;
70
+ camera.updateProjectionMatrix();
71
+ box.getCenter(centre);
72
+ for (const [f, [forward, up]] of FACES.entries()) {
73
+ camera.matrix.makeBasis(right.crossVectors(forward, up), up, back.copy(forward).negate()).setPosition(centre);
74
+ camera.updateMatrixWorld(true);
75
+ const at = (i * 6 + f) * face;
76
+ ambient.visible = true;
77
+ await shoot(lit.subarray(at, at + face));
78
+ ambient.visible = false;
79
+ await shoot(glow.subarray(at, at + face));
80
+ }
81
+ await pause();
82
+ }
83
+ }
84
+ finally {
85
+ target.dispose();
86
+ }
87
+ // Light adds up in linear values: response = lit - glow.
88
+ for (let i = 0; i < lit.length; i++) {
89
+ if (i % 4 === 3)
90
+ continue;
91
+ lit[i] = linearToSrgb(Math.max(0, (SRGB_TO_LINEAR[lit[i] ?? 0] ?? 0) - (SRGB_TO_LINEAR[glow[i] ?? 0] ?? 0))) * 255 + 0.5;
92
+ }
93
+ return { response: layers(lit, size, boxes.length), glow: glow.some((v, i) => i % 4 !== 3 && v > 0) ? layers(glow, size, boxes.length) : null, span };
94
+ }
95
+ const SRGB_TO_LINEAR = Float32Array.from({ length: 256 }, (_, i) => srgbToLinear(i / 255));
96
+ function layers(data, size, rooms) {
97
+ const texture = new DataArrayTexture(data, size, size, rooms * 6);
98
+ texture.colorSpace = SRGBColorSpace;
99
+ texture.minFilter = LinearMipmapLinearFilter;
100
+ texture.magFilter = LinearFilter;
101
+ texture.generateMipmaps = true;
102
+ texture.needsUpdate = true;
103
+ return texture;
104
+ }
105
+ //# sourceMappingURL=faces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"faces.js","sourceRoot":"","sources":["../../../src/baked/interior/faces.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { Matrix4, MeshStandardNodeMaterial, PhysicalLightingModel, type Box3, type DataTexture, type Object3D } from "three/webgpu";
2
+ import { type Faces } from "./faces.js";
3
+ /** What a baked material needs to look into its rooms. */
4
+ export interface Rooms extends Faces {
5
+ boxes: readonly Box3[];
6
+ /**
7
+ * per baked texel: R the room of the nearest window + 1, read texel by texel; G the share
8
+ * of the room that shows, filtered
9
+ */
10
+ windows: DataTexture;
11
+ }
12
+ /**
13
+ * Tell `mesh`, if it shows rooms, that its geometry was moved by `placement` out of the
14
+ * source's space: InstancedLod draws copies of its templates' geometry placed in the
15
+ * instance's space.
16
+ */
17
+ export declare function placeInterior(mesh: Object3D, placement: Matrix4): void;
18
+ /**
19
+ * A baked level's material that shows `rooms` through its windows. The rooms' textures
20
+ * go with it.
21
+ */
22
+ export declare class InteriorMaterial extends MeshStandardNodeMaterial {
23
+ readonly isInteriorMaterial = true;
24
+ rooms: Rooms | null;
25
+ /** Each room's box: its min, then its max. */
26
+ private bounds;
27
+ /** Show `rooms` through the windows. */
28
+ furnish(rooms: Rooms): this;
29
+ setupLightingModel(): PhysicalLightingModel;
30
+ copy(source: InteriorMaterial): this;
31
+ }
@@ -0,0 +1,157 @@
1
+ import { InterpolationSamplingType, Matrix4, MeshStandardNodeMaterial, PhysicalLightingModel, StorageBufferAttribute, } from "three/webgpu";
2
+ import { If, cameraPosition, cameraProjectionMatrix, cameraWorldMatrix, clamp, cross, dFdx, dFdy, dot, float, int, ivec2, length, log2, mat4, materialEnvIntensity, max, min, modelWorldMatrix, normalize, pmremTexture, positionGeometry, positionWorld, select, sign, step, texture, textureLoad, uniform, uv, varying, vec2, vec3, vec4, } from "three/tsl";
3
+ import { instanceMatrixOf } from "../../fade.js";
4
+ import { isScene } from "../../three.js";
5
+ import { affine, column, contextNode, isNodeOf, isOrthographic, roomBounds } from "../../tsl.js";
6
+ import { FACES } from "./faces.js";
7
+ /** Per mesh: where its geometry's space sits in the source's, when an InstancedLod moved the geometry (see `placeInterior`). */
8
+ const spaces = new WeakMap();
9
+ const identity = new Matrix4();
10
+ const space = uniform(new Matrix4()).onObjectUpdate(({ object }) => (object && spaces.get(object)) ?? identity);
11
+ /**
12
+ * Tell `mesh`, if it shows rooms, that its geometry was moved by `placement` out of the
13
+ * source's space: InstancedLod draws copies of its templates' geometry placed in the
14
+ * instance's space.
15
+ */
16
+ export function placeInterior(mesh, placement) {
17
+ spaces.set(mesh, placement.clone().invert());
18
+ }
19
+ function flat(node) {
20
+ return varying(node).setInterpolation(InterpolationSamplingType.FLAT);
21
+ }
22
+ /** `vectors[index]`, for an index known only in the shader. */
23
+ function pick(vectors, index) {
24
+ return vectors.reduceRight((rest, v, i) => select(index.equal(i), vec3(v.x, v.y, v.z), rest), vec3(0, 0, 0));
25
+ }
26
+ /**
27
+ * A baked level's material that shows `rooms` through its windows. The rooms' textures
28
+ * go with it.
29
+ */
30
+ export class InteriorMaterial extends MeshStandardNodeMaterial {
31
+ isInteriorMaterial = true;
32
+ rooms = null;
33
+ /** Each room's box: its min, then its max. */
34
+ bounds = null;
35
+ /** Show `rooms` through the windows. */
36
+ furnish(rooms) {
37
+ const bounds = new StorageBufferAttribute(Float32Array.from(rooms.boxes.flatMap((box) => [...box.min.toArray(), 0, ...box.max.toArray(), 0])), 4);
38
+ this.rooms = rooms;
39
+ this.bounds = bounds;
40
+ this.addEventListener("dispose", () => {
41
+ rooms.response.dispose();
42
+ rooms.glow?.dispose();
43
+ rooms.windows.dispose();
44
+ bounds.dispose();
45
+ });
46
+ return this;
47
+ }
48
+ setupLightingModel() {
49
+ return this.rooms && this.bounds ? new InteriorLighting(this.rooms, this.bounds) : super.setupLightingModel();
50
+ }
51
+ copy(source) {
52
+ super.copy(source);
53
+ this.rooms = source.rooms;
54
+ this.bounds = source.bounds;
55
+ return this;
56
+ }
57
+ }
58
+ /**
59
+ * The room is lit by indirect light only: the sun's direct light, which walls and roof
60
+ * would block, is left out. Ambient light, light probes and hemisphere lights are taken at
61
+ * the window; the environment, as three lights the real room's walls, at the wall the
62
+ * view ray meets. Its glow adds on top. Glass shows the room by its share, under its own
63
+ * reflection: three's specular term carries the Fresnel.
64
+ */
65
+ class InteriorLighting extends PhysicalLightingModel {
66
+ rooms;
67
+ bounds;
68
+ constructor(rooms,
69
+ /** see `InteriorMaterial.bounds` */
70
+ bounds) {
71
+ super();
72
+ this.rooms = rooms;
73
+ this.bounds = bounds;
74
+ }
75
+ // After three's lights and before it sums them: by `finish` the sum is made.
76
+ start(builder) {
77
+ super.start(builder);
78
+ const { rooms } = this;
79
+ const irradiance = contextNode(builder, "irradiance");
80
+ const directDiffuse = contextNode(builder, "reflectedLight", "directDiffuse");
81
+ const indirectDiffuse = contextNode(builder, "reflectedLight", "indirectDiffuse");
82
+ if (!isNodeOf(irradiance, "vec3", builder) || !isNodeOf(directDiffuse, "vec3", builder) || !isNodeOf(indirectDiffuse, "vec3", builder))
83
+ throw new Error("bakeMesh: three's lighting is not made of vec3s");
84
+ const count = rooms.boxes.length;
85
+ const boxes = roomBounds(this.bounds);
86
+ const faceSize = rooms.response.image.width;
87
+ const [width, height] = [rooms.windows.image.width, rooms.windows.image.height];
88
+ // The view ray in the source's space, and the source's space to world.
89
+ const instance = instanceMatrixOf(builder.object);
90
+ const toWorld = affine((instance ? modelWorldMatrix.mul(instance) : modelWorldMatrix).mul(affineInverse(space)));
91
+ const back = column(cameraWorldMatrix, 2).xyz;
92
+ const worldRay = select(isOrthographic(cameraProjectionMatrix), back.negate(), positionWorld.sub(cameraPosition));
93
+ const point = varying(space.mul(vec4(positionGeometry, 1)).xyz);
94
+ const ray = varying(toWorld.solve(worldRay));
95
+ const [x, y, z] = toWorld.normalColumns.map(flat);
96
+ if (!x || !y || !z)
97
+ throw new Error("bakeMesh: a normal matrix has three columns");
98
+ const share = texture(rooms.windows, uv()).g;
99
+ const texel = ivec2(clamp(uv().mul(vec2(width, height)), vec2(0, 0), vec2(width - 1, height - 1)));
100
+ // The room's number, 0 for none, as a float: the box's index is clamped to a room.
101
+ const room = float(textureLoad(rooms.windows, texel).r.mul(255).add(0.5).floor()).toVar();
102
+ const box = int(clamp(room.sub(1), 0, count - 1)).toVar();
103
+ const low = boxes.element(box.mul(2)).xyz;
104
+ const high = boxes.element(box.mul(2).add(1)).xyz;
105
+ const unit = normalize(ray);
106
+ // Nudged off zero, so each axis has a crossing.
107
+ const direction = unit
108
+ .add(vec3(1, 1, 1)
109
+ .sub(step(vec3(1e-30, 1e-30, 1e-30), unit.abs()))
110
+ .mul(1e-6))
111
+ .toVar();
112
+ const far = low.sub(point).div(direction).max(high.sub(point).div(direction)).toVar();
113
+ // The box is intersected for every texel, so the derivatives that pick the cube's mip
114
+ // level are defined across window edges.
115
+ const exit = point.add(direction.mul(max(min(far.x, min(far.y, far.z)), 0))).toVar();
116
+ const footprint = max(length(dFdx(exit)), length(dFdy(exit)));
117
+ If(room.greaterThan(0).and(share.greaterThan(0)), () => {
118
+ const wall = exit.sub(low.add(high).mul(0.5));
119
+ const a = wall.abs();
120
+ const face = select(a.x.greaterThanEqual(a.y).and(a.x.greaterThanEqual(a.z)), select(wall.x.greaterThanEqual(0), int(0), int(1)), select(a.y.greaterThanEqual(a.z), select(wall.y.greaterThanEqual(0), int(2), int(3)), select(wall.z.greaterThanEqual(0), int(4), int(5)))).toVar();
121
+ const forward = pick(FACES.map(([f]) => f), face);
122
+ const up = pick(FACES.map(([, u]) => u), face);
123
+ const depth = max(dot(wall, forward), 1e-6).mul(rooms.span);
124
+ const at = vec2(dot(wall, cross(forward, up)), dot(wall, up))
125
+ .div(depth)
126
+ .mul(0.5)
127
+ .add(0.5);
128
+ const layer = box.mul(6).add(face);
129
+ const level = log2(max(footprint.mul(0.5 * faceSize).div(depth), 1e-6));
130
+ const inward = select(far.x.lessThanEqual(min(far.y, far.z)), vec3(sign(direction.x).negate(), 0, 0), select(far.y.lessThanEqual(far.z), vec3(0, sign(direction.y).negate(), 0), vec3(0, 0, sign(direction.z).negate())));
131
+ const wallNormal = normalize(x.mul(inward.x).add(y.mul(inward.y)).add(z.mul(inward.z)));
132
+ const environment = environmentOf(builder.object);
133
+ const ibl = environment ? pmremTexture(environment, wallNormal, float(1)).rgb.mul(Math.PI).mul(materialEnvIntensity) : vec3(0, 0, 0);
134
+ const light = irradiance.add(ibl);
135
+ let shown = texture(rooms.response, at).depth(layer).level(level).rgb.mul(light).div(Math.PI);
136
+ if (rooms.glow)
137
+ shown = shown.add(texture(rooms.glow, at).depth(layer).level(level).rgb);
138
+ const keep = share.oneMinus();
139
+ directDiffuse.assign(directDiffuse.mul(keep));
140
+ indirectDiffuse.assign(indirectDiffuse.mul(keep).add(shown.mul(share)));
141
+ });
142
+ }
143
+ }
144
+ /** The environment of the scene `object` is in, if any. */
145
+ function environmentOf(object) {
146
+ let root = object;
147
+ while (root.parent)
148
+ root = root.parent;
149
+ return isScene(root) ? root.environment : null;
150
+ }
151
+ /** The inverse of an affine `m`, as a matrix: the linear part's inverse and the translation undone. */
152
+ function affineInverse(m) {
153
+ const inverse = affine(m);
154
+ const solve = (v) => vec4(inverse.solve(v), 0);
155
+ return mat4(solve(vec3(1, 0, 0)), solve(vec3(0, 1, 0)), solve(vec3(0, 0, 1)), vec4(inverse.unproject(vec3(0, 0, 0)), 1));
156
+ }
157
+ //# sourceMappingURL=material.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material.js","sourceRoot":"","sources":["../../../src/baked/interior/material.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { Box3, Vector3, type Matrix4, type Object3D } from "three/webgpu";
2
+ /**
3
+ * The boxes of `interior`'s rooms, in the source's own space: one per direct child, the
4
+ * bounds of what it draws. `placement` puts the interior in the source's space.
5
+ *
6
+ * Lights are refused: wherever the source draws they would be scene lights, so every
7
+ * switch to or from it changes the scene's light count (and recompiles every lit
8
+ * material), and an InstancedLod's templates light nothing. Lamps glow with emissive
9
+ * materials instead.
10
+ */
11
+ export declare function readBoxes(interior: Object3D, placement: Matrix4): Box3[];
12
+ /**
13
+ * How far behind glass a room may begin: half the thinnest room's smallest side. A wall
14
+ * between glass and room is thinner than any room; a ray that met no room within half a
15
+ * room's size is not looking into one through this glass.
16
+ */
17
+ export declare function windowDepth(boxes: readonly Box3[]): number;
18
+ /**
19
+ * The room a ray from `origin` along unit `direction` is in or enters first within
20
+ * `far`: the room behind a window. -1 for none.
21
+ */
22
+ export declare function roomAlong(boxes: readonly Box3[], origin: Vector3, direction: Vector3, far: number): number;
@@ -0,0 +1,78 @@
1
+ import { Box3, Ray, Vector3 } from "three/webgpu";
2
+ import { forEachVertex } from "../../bounds.js";
3
+ import { isLight } from "../../three.js";
4
+ /** Most rooms an interior may have: six faces each in texture arrays of at most 256 layers. */
5
+ const MAX_ROOMS = 42;
6
+ /** Share of the smaller box two rooms may overlap by: walls that meet, not rooms inside rooms. */
7
+ const OVERLAP = 0.02;
8
+ /**
9
+ * The boxes of `interior`'s rooms, in the source's own space: one per direct child, the
10
+ * bounds of what it draws. `placement` puts the interior in the source's space.
11
+ *
12
+ * Lights are refused: wherever the source draws they would be scene lights, so every
13
+ * switch to or from it changes the scene's light count (and recompiles every lit
14
+ * material), and an InstancedLod's templates light nothing. Lamps glow with emissive
15
+ * materials instead.
16
+ */
17
+ export function readBoxes(interior, placement) {
18
+ interior.traverse((node) => {
19
+ if (isLight(node))
20
+ throw new Error(`bakeMesh: the interior has a light ("${node.name}"); give lamps emissive materials instead`);
21
+ });
22
+ const rooms = interior.children;
23
+ if (rooms.length === 0)
24
+ throw new Error("bakeMesh: the interior has no rooms: each direct child of it is one room");
25
+ if (rooms.length > MAX_ROOMS)
26
+ throw new Error(`bakeMesh: the interior has ${rooms.length} rooms, at most ${MAX_ROOMS} are supported`);
27
+ const boxes = rooms.map((room, i) => {
28
+ if (room.matrixAutoUpdate)
29
+ room.updateMatrix();
30
+ const matrix = placement.clone().multiply(room.matrix);
31
+ const box = new Box3();
32
+ forEachVertex(room, (p) => box.expandByPoint(p.applyMatrix4(matrix)));
33
+ if (box.isEmpty())
34
+ throw new Error(`bakeMesh: room ${i} ("${room.name}") of the interior draws nothing`);
35
+ return box;
36
+ });
37
+ boxes.forEach((a, i) => boxes.slice(i + 1).forEach((b, k) => {
38
+ const shared = volume(a.clone().intersect(b));
39
+ if (shared > OVERLAP * Math.min(volume(a), volume(b)))
40
+ throw new Error(`bakeMesh: rooms ${i} ("${rooms[i]?.name}") and ${i + k + 1} ("${rooms[i + k + 1]?.name}") of the interior overlap: each room fills a box of its own`);
41
+ }));
42
+ return boxes;
43
+ }
44
+ function volume(box) {
45
+ if (box.isEmpty())
46
+ return 0;
47
+ const { x, y, z } = box.getSize(new Vector3());
48
+ return x * y * z;
49
+ }
50
+ /**
51
+ * How far behind glass a room may begin: half the thinnest room's smallest side. A wall
52
+ * between glass and room is thinner than any room; a ray that met no room within half a
53
+ * room's size is not looking into one through this glass.
54
+ */
55
+ export function windowDepth(boxes) {
56
+ const size = new Vector3();
57
+ return Math.min(...boxes.map((box) => Math.min(...box.getSize(size).toArray()))) / 2;
58
+ }
59
+ const ray = new Ray();
60
+ const enter = new Vector3();
61
+ /**
62
+ * The room a ray from `origin` along unit `direction` is in or enters first within
63
+ * `far`: the room behind a window. -1 for none.
64
+ */
65
+ export function roomAlong(boxes, origin, direction, far) {
66
+ ray.set(origin, direction);
67
+ let nearest = -1;
68
+ let best = far;
69
+ boxes.forEach((box, i) => {
70
+ const distance = box.containsPoint(origin) ? 0 : ray.intersectBox(box, enter)?.distanceTo(origin);
71
+ if (distance === undefined || distance > best)
72
+ return;
73
+ best = distance;
74
+ nearest = i;
75
+ });
76
+ return nearest;
77
+ }
78
+ //# sourceMappingURL=rooms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rooms.js","sourceRoot":"","sources":["../../../src/baked/interior/rooms.ts"],"names":[],"mappings":"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"}