abstract-3d 3.1.2 → 4.0.0-beta.10

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 (236) hide show
  1. package/README.md +53 -1
  2. package/lib/abstract-3d.d.ts +27 -1
  3. package/lib/abstract-3d.d.ts.map +1 -1
  4. package/lib/abstract-3d.js +26 -2
  5. package/lib/abstract-3d.js.map +1 -1
  6. package/lib/renderers/dxf/dxf-encoding/dxf-build.d.ts.map +1 -1
  7. package/lib/renderers/dxf/dxf-encoding/dxf-build.js +1 -2
  8. package/lib/renderers/dxf/dxf-encoding/dxf-build.js.map +1 -1
  9. package/lib/renderers/ifc/ifc.test.d.ts +2 -0
  10. package/lib/renderers/ifc/ifc.test.d.ts.map +1 -0
  11. package/lib/renderers/ifc/ifc.test.js +380 -0
  12. package/lib/renderers/ifc/ifc.test.js.map +1 -0
  13. package/lib/renderers/index.d.ts +1 -0
  14. package/lib/renderers/index.d.ts.map +1 -1
  15. package/lib/renderers/index.js +1 -0
  16. package/lib/renderers/index.js.map +1 -1
  17. package/lib/renderers/react/index.d.ts +2 -5
  18. package/lib/renderers/react/index.d.ts.map +1 -1
  19. package/lib/renderers/react/index.js +1 -2
  20. package/lib/renderers/react/index.js.map +1 -1
  21. package/lib/renderers/react/react.d.ts +16 -42
  22. package/lib/renderers/react/react.d.ts.map +1 -1
  23. package/lib/renderers/react/react.js +56 -32
  24. package/lib/renderers/react/react.js.map +1 -1
  25. package/lib/renderers/three/appearance/appearance.d.ts +46 -0
  26. package/lib/renderers/three/appearance/appearance.d.ts.map +1 -0
  27. package/lib/renderers/three/appearance/appearance.js +102 -0
  28. package/lib/renderers/three/appearance/appearance.js.map +1 -0
  29. package/lib/renderers/three/appearance/appearance.test.d.ts +2 -0
  30. package/lib/renderers/three/appearance/appearance.test.d.ts.map +1 -0
  31. package/lib/renderers/three/appearance/appearance.test.js +97 -0
  32. package/lib/renderers/three/appearance/appearance.test.js.map +1 -0
  33. package/lib/renderers/three/appearance.d.ts +41 -0
  34. package/lib/renderers/three/appearance.d.ts.map +1 -0
  35. package/lib/renderers/three/appearance.js +100 -0
  36. package/lib/renderers/three/appearance.js.map +1 -0
  37. package/lib/renderers/three/build/build.d.ts +53 -0
  38. package/lib/renderers/three/build/build.d.ts.map +1 -0
  39. package/lib/renderers/three/build/build.js +181 -0
  40. package/lib/renderers/three/build/build.js.map +1 -0
  41. package/lib/renderers/three/build/build.test.d.ts +2 -0
  42. package/lib/renderers/three/build/build.test.d.ts.map +1 -0
  43. package/lib/renderers/three/build/build.test.js +120 -0
  44. package/lib/renderers/three/build/build.test.js.map +1 -0
  45. package/lib/renderers/three/build/materials.d.ts +20 -0
  46. package/lib/renderers/three/build/materials.d.ts.map +1 -0
  47. package/lib/renderers/three/build/materials.js +168 -0
  48. package/lib/renderers/three/build/materials.js.map +1 -0
  49. package/lib/renderers/three/build/parts.d.ts +65 -0
  50. package/lib/renderers/three/build/parts.d.ts.map +1 -0
  51. package/lib/renderers/three/build/parts.js +203 -0
  52. package/lib/renderers/three/build/parts.js.map +1 -0
  53. package/lib/renderers/three/build.d.ts +50 -0
  54. package/lib/renderers/three/build.d.ts.map +1 -0
  55. package/lib/renderers/three/build.js +210 -0
  56. package/lib/renderers/three/build.js.map +1 -0
  57. package/lib/renderers/three/camera/camera.d.ts +40 -0
  58. package/lib/renderers/three/camera/camera.d.ts.map +1 -0
  59. package/lib/renderers/three/camera/camera.js +51 -0
  60. package/lib/renderers/three/camera/camera.js.map +1 -0
  61. package/lib/renderers/three/camera/camera.test.d.ts +2 -0
  62. package/lib/renderers/three/camera/camera.test.d.ts.map +1 -0
  63. package/lib/renderers/three/camera/camera.test.js +46 -0
  64. package/lib/renderers/three/camera/camera.test.js.map +1 -0
  65. package/lib/renderers/three/camera/controls.d.ts +24 -0
  66. package/lib/renderers/three/camera/controls.d.ts.map +1 -0
  67. package/lib/renderers/three/camera/controls.js +39 -0
  68. package/lib/renderers/three/camera/controls.js.map +1 -0
  69. package/lib/renderers/three/camera/gizmo.d.ts +44 -0
  70. package/lib/renderers/three/camera/gizmo.d.ts.map +1 -0
  71. package/lib/renderers/three/camera/gizmo.js +43 -0
  72. package/lib/renderers/three/camera/gizmo.js.map +1 -0
  73. package/lib/renderers/three/camera.d.ts +63 -0
  74. package/lib/renderers/three/camera.d.ts.map +1 -0
  75. package/lib/renderers/three/camera.js +85 -0
  76. package/lib/renderers/three/camera.js.map +1 -0
  77. package/lib/renderers/three/compile/compile.d.ts +59 -0
  78. package/lib/renderers/three/compile/compile.d.ts.map +1 -0
  79. package/lib/renderers/three/compile/compile.js +88 -0
  80. package/lib/renderers/three/compile/compile.js.map +1 -0
  81. package/lib/renderers/three/compile/compile.test.d.ts +2 -0
  82. package/lib/renderers/three/compile/compile.test.d.ts.map +1 -0
  83. package/lib/renderers/three/compile/compile.test.js +93 -0
  84. package/lib/renderers/three/compile/compile.test.js.map +1 -0
  85. package/lib/renderers/three/compile.d.ts +58 -0
  86. package/lib/renderers/three/compile.d.ts.map +1 -0
  87. package/lib/renderers/three/compile.js +89 -0
  88. package/lib/renderers/three/compile.js.map +1 -0
  89. package/lib/renderers/three/controls.d.ts +27 -0
  90. package/lib/renderers/three/controls.d.ts.map +1 -0
  91. package/lib/renderers/three/controls.js +115 -0
  92. package/lib/renderers/three/controls.js.map +1 -0
  93. package/lib/renderers/three/environment/studio.d.ts +9 -0
  94. package/lib/renderers/three/environment/studio.d.ts.map +1 -0
  95. package/lib/renderers/three/environment/studio.js +15 -0
  96. package/lib/renderers/three/environment/studio.js.map +1 -0
  97. package/lib/renderers/three/geometry/geometry.d.ts +21 -0
  98. package/lib/renderers/three/geometry/geometry.d.ts.map +1 -0
  99. package/lib/renderers/three/geometry/geometry.js +141 -0
  100. package/lib/renderers/three/geometry/geometry.js.map +1 -0
  101. package/lib/renderers/three/geometry/geometry.test.d.ts +2 -0
  102. package/lib/renderers/three/geometry/geometry.test.d.ts.map +1 -0
  103. package/lib/renderers/three/geometry/geometry.test.js +80 -0
  104. package/lib/renderers/three/geometry/geometry.test.js.map +1 -0
  105. package/lib/renderers/three/geometry.d.ts +20 -0
  106. package/lib/renderers/three/geometry.d.ts.map +1 -0
  107. package/lib/renderers/three/geometry.js +164 -0
  108. package/lib/renderers/three/geometry.js.map +1 -0
  109. package/lib/renderers/three/gizmo.d.ts +49 -0
  110. package/lib/renderers/three/gizmo.d.ts.map +1 -0
  111. package/lib/renderers/three/gizmo.js +172 -0
  112. package/lib/renderers/three/gizmo.js.map +1 -0
  113. package/lib/renderers/three/index.d.ts +16 -0
  114. package/lib/renderers/three/index.d.ts.map +1 -0
  115. package/lib/renderers/three/index.js +6 -0
  116. package/lib/renderers/three/index.js.map +1 -0
  117. package/lib/renderers/three/input.d.ts +25 -0
  118. package/lib/renderers/three/input.d.ts.map +1 -0
  119. package/lib/renderers/three/input.js +71 -0
  120. package/lib/renderers/three/input.js.map +1 -0
  121. package/lib/renderers/three/lines.d.ts +16 -0
  122. package/lib/renderers/three/lines.d.ts.map +1 -0
  123. package/lib/renderers/three/lines.js +63 -0
  124. package/lib/renderers/three/lines.js.map +1 -0
  125. package/lib/renderers/three/materials.d.ts +15 -0
  126. package/lib/renderers/three/materials.d.ts.map +1 -0
  127. package/lib/renderers/three/materials.js +70 -0
  128. package/lib/renderers/three/materials.js.map +1 -0
  129. package/lib/renderers/three/options.d.ts +68 -0
  130. package/lib/renderers/three/options.d.ts.map +1 -0
  131. package/lib/renderers/three/options.js +64 -0
  132. package/lib/renderers/three/options.js.map +1 -0
  133. package/lib/renderers/three/overlays.d.ts +25 -0
  134. package/lib/renderers/three/overlays.d.ts.map +1 -0
  135. package/lib/renderers/three/overlays.js +57 -0
  136. package/lib/renderers/three/overlays.js.map +1 -0
  137. package/lib/renderers/three/quality/quality.d.ts +18 -0
  138. package/lib/renderers/three/quality/quality.d.ts.map +1 -0
  139. package/lib/renderers/three/quality/quality.js +28 -0
  140. package/lib/renderers/three/quality/quality.js.map +1 -0
  141. package/lib/renderers/three/quality/quality.test.d.ts +2 -0
  142. package/lib/renderers/three/quality/quality.test.d.ts.map +1 -0
  143. package/lib/renderers/three/quality/quality.test.js +23 -0
  144. package/lib/renderers/three/quality/quality.test.js.map +1 -0
  145. package/lib/renderers/three/quality.d.ts +24 -0
  146. package/lib/renderers/three/quality.d.ts.map +1 -0
  147. package/lib/renderers/three/quality.js +67 -0
  148. package/lib/renderers/three/quality.js.map +1 -0
  149. package/lib/renderers/three/shadow/key-light.d.ts +6 -0
  150. package/lib/renderers/three/shadow/key-light.d.ts.map +1 -0
  151. package/lib/renderers/three/shadow/key-light.js +39 -0
  152. package/lib/renderers/three/shadow/key-light.js.map +1 -0
  153. package/lib/renderers/three/shadow/shadow.d.ts +21 -0
  154. package/lib/renderers/three/shadow/shadow.d.ts.map +1 -0
  155. package/lib/renderers/three/shadow/shadow.js +120 -0
  156. package/lib/renderers/three/shadow/shadow.js.map +1 -0
  157. package/lib/renderers/three/text/text.d.ts +55 -0
  158. package/lib/renderers/three/text/text.d.ts.map +1 -0
  159. package/lib/renderers/three/text/text.js +90 -0
  160. package/lib/renderers/three/text/text.js.map +1 -0
  161. package/lib/renderers/three/text/text.test.d.ts +2 -0
  162. package/lib/renderers/three/text/text.test.d.ts.map +1 -0
  163. package/lib/renderers/three/text/text.test.js +70 -0
  164. package/lib/renderers/three/text/text.test.js.map +1 -0
  165. package/lib/renderers/three/text.d.ts +53 -0
  166. package/lib/renderers/three/text.d.ts.map +1 -0
  167. package/lib/renderers/three/text.js +151 -0
  168. package/lib/renderers/three/text.js.map +1 -0
  169. package/lib/renderers/three/viewer/options.d.ts +82 -0
  170. package/lib/renderers/three/viewer/options.d.ts.map +1 -0
  171. package/lib/renderers/three/viewer/options.js +34 -0
  172. package/lib/renderers/three/viewer/options.js.map +1 -0
  173. package/lib/renderers/three/viewer/options.test.d.ts +2 -0
  174. package/lib/renderers/three/viewer/options.test.d.ts.map +1 -0
  175. package/lib/renderers/three/viewer/options.test.js +38 -0
  176. package/lib/renderers/three/viewer/options.test.js.map +1 -0
  177. package/lib/renderers/three/viewer/overlays.d.ts +31 -0
  178. package/lib/renderers/three/viewer/overlays.d.ts.map +1 -0
  179. package/lib/renderers/three/viewer/overlays.js +43 -0
  180. package/lib/renderers/three/viewer/overlays.js.map +1 -0
  181. package/lib/renderers/three/viewer/viewer.d.ts +102 -0
  182. package/lib/renderers/three/viewer/viewer.d.ts.map +1 -0
  183. package/lib/renderers/three/viewer/viewer.js +488 -0
  184. package/lib/renderers/three/viewer/viewer.js.map +1 -0
  185. package/lib/renderers/three/viewer.d.ts +38 -0
  186. package/lib/renderers/three/viewer.d.ts.map +1 -0
  187. package/lib/renderers/three/viewer.js +435 -0
  188. package/lib/renderers/three/viewer.js.map +1 -0
  189. package/package.json +34 -16
  190. package/src/abstract-3d.ts +60 -2
  191. package/src/renderers/dxf/dxf-encoding/dxf-build.ts +1 -2
  192. package/src/renderers/ifc/ifc.test.ts +7 -5
  193. package/src/renderers/index.ts +1 -0
  194. package/src/renderers/react/index.ts +2 -5
  195. package/src/renderers/react/react.tsx +107 -181
  196. package/src/renderers/three/appearance/appearance.test.ts +153 -0
  197. package/src/renderers/three/appearance/appearance.ts +150 -0
  198. package/src/renderers/three/build/build.test.ts +149 -0
  199. package/src/renderers/three/build/build.ts +278 -0
  200. package/src/renderers/three/build/materials.ts +222 -0
  201. package/src/renderers/three/build/parts.ts +277 -0
  202. package/src/renderers/three/camera/camera.test.ts +53 -0
  203. package/src/renderers/three/camera/camera.ts +82 -0
  204. package/src/renderers/three/camera/controls.ts +65 -0
  205. package/src/renderers/three/camera/gizmo.ts +94 -0
  206. package/src/renderers/three/compile/compile.test.ts +126 -0
  207. package/src/renderers/three/compile/compile.ts +151 -0
  208. package/src/renderers/three/environment/studio.ts +18 -0
  209. package/src/renderers/three/geometry/geometry.test.ts +121 -0
  210. package/src/renderers/three/geometry/geometry.ts +189 -0
  211. package/src/renderers/three/index.ts +15 -0
  212. package/src/renderers/three/quality/quality.test.ts +37 -0
  213. package/src/renderers/three/quality/quality.ts +36 -0
  214. package/src/renderers/three/shadow/key-light.ts +43 -0
  215. package/src/renderers/three/shadow/shadow.ts +170 -0
  216. package/src/renderers/three/text/text.test.ts +79 -0
  217. package/src/renderers/three/text/text.ts +128 -0
  218. package/src/renderers/three/viewer/options.ts +112 -0
  219. package/src/renderers/three/viewer/overlays.ts +71 -0
  220. package/src/renderers/three/viewer/viewer.ts +596 -0
  221. package/lib/renderers/react/react-hotspot.d.ts +0 -27
  222. package/lib/renderers/react/react-hotspot.d.ts.map +0 -1
  223. package/lib/renderers/react/react-hotspot.js +0 -37
  224. package/lib/renderers/react/react-hotspot.js.map +0 -1
  225. package/src/custom_typings/react-three-fiber.d.ts +0 -9
  226. package/src/custom_typings/react-three-postprocessing.d.ts +0 -1
  227. package/src/renderers/react/react-camera.tsx +0 -391
  228. package/src/renderers/react/react-dimension.tsx +0 -122
  229. package/src/renderers/react/react-group.test.ts +0 -56
  230. package/src/renderers/react/react-group.tsx +0 -202
  231. package/src/renderers/react/react-image-material.tsx +0 -139
  232. package/src/renderers/react/react-material.tsx +0 -91
  233. package/src/renderers/react/react-mesh.tsx +0 -512
  234. package/src/renderers/react/react-relation.tsx +0 -86
  235. package/src/renderers/react/react-scene.tsx +0 -111
  236. package/src/renderers/react/react-types.ts +0 -9
@@ -0,0 +1,64 @@
1
+ /** How each option is compared, and what a change of it redoes; callbacks are read when used, so they need nothing */
2
+ const effects = {
3
+ scene: ["reference", ["compile", "build", "lights", "overlays"]],
4
+ createGroupId: ["reference", ["compile", "build"]],
5
+ activeComponents: ["contents", ["build"]],
6
+ activeRelations: ["value", ["build"]],
7
+ useAlphaTest: ["value", ["build"]],
8
+ materialStateImages: ["contents", ["build"]],
9
+ selectedIds: ["contents", ["paint"]],
10
+ hoveredIds: ["value", ["paint"]],
11
+ showDimensions: ["value", ["dimensions"]],
12
+ camera: ["value", ["camera", "rig", "fit"]],
13
+ view: ["value", ["fit"]],
14
+ bufferZones: ["value", ["fit"]],
15
+ fitPadding: ["value", ["fit"]],
16
+ controls: ["value", ["rig"]],
17
+ gizmo: ["value", ["gizmo"]],
18
+ lights: ["reference", ["lights"]],
19
+ environment: ["reference", ["lights"]],
20
+ environmentIntensity: ["value", ["lights"]],
21
+ lightIntensity: ["value", ["lights"]],
22
+ quality: ["value", ["quality"]],
23
+ backend: ["value", []],
24
+ popovers: ["reference", ["overlays"]],
25
+ getTooltips: ["reference", ["overlays"]],
26
+ fallback: ["reference", ["overlays"]],
27
+ onOverlays: ["reference", []],
28
+ onClickGroup: ["reference", ["paint"]],
29
+ onHoverGroup: ["reference", []],
30
+ onContextMenuGroup: ["reference", []],
31
+ onClickRelation: ["reference", []],
32
+ };
33
+ export function getChanges(previous, next) {
34
+ const changes = new Set();
35
+ Object.keys(effects).forEach((key) => {
36
+ const [comparison, redo] = effects[key];
37
+ if (!isEqual(comparison, previous[key], next[key])) {
38
+ redo.forEach((change) => changes.add(change));
39
+ }
40
+ });
41
+ return changes;
42
+ }
43
+ function isEqual(comparison, a, b) {
44
+ if (a === b) {
45
+ return true;
46
+ }
47
+ switch (comparison) {
48
+ case "reference":
49
+ return false;
50
+ case "contents":
51
+ return isShallowEqual(a, b);
52
+ default:
53
+ return JSON.stringify(a) === JSON.stringify(b);
54
+ }
55
+ }
56
+ function isShallowEqual(a, b) {
57
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
58
+ return false;
59
+ }
60
+ const [ra, rb] = [a, b];
61
+ const keys = Object.keys(ra);
62
+ return keys.length === Object.keys(rb).length && keys.every((key) => Object.is(ra[key], rb[key]));
63
+ }
64
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../../../src/renderers/three/options.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { type Camera, Vector3 } from "three";
2
+ /** HTML elements over the canvas at projected 3D anchors, e.g. popovers and tooltips; their content is mounted by the app, or directly */
3
+ export type Overlay<Content> = {
4
+ readonly key: string;
5
+ /** In world space; without one the overlay is centered on the canvas */
6
+ readonly position?: Vector3;
7
+ readonly content: Content;
8
+ };
9
+ export type MountedOverlay<Content> = {
10
+ readonly key: string;
11
+ readonly element: HTMLElement;
12
+ readonly content: Content;
13
+ };
14
+ /** Mounts the overlays' content into their elements, called when the set of overlays or their content changes */
15
+ export type MountOverlays<Content> = (overlays: ReadonlyArray<MountedOverlay<Content>>) => void;
16
+ export type OverlayLayer<Content> = {
17
+ readonly set: (overlays: ReadonlyArray<Overlay<Content>>) => void;
18
+ /** Moves each element to its anchor's place on screen, hidden while the anchor is behind the camera */
19
+ readonly update: (camera: Camera, width: number, height: number) => void;
20
+ readonly dispose: () => void;
21
+ };
22
+ /** Mounts strings and DOM nodes as they are */
23
+ export declare const mountDirectly: <Content>(overlays: ReadonlyArray<MountedOverlay<Content>>) => void;
24
+ export declare function createOverlayLayer<Content>(container: HTMLElement, mount: MountOverlays<Content>): OverlayLayer<Content>;
25
+ //# sourceMappingURL=overlays.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../../../src/renderers/three/overlays.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAE7C,0IAA0I;AAE1I,MAAM,MAAM,OAAO,CAAC,OAAO,IAAI;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,CAAC,OAAO,IAAI;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,iHAAiH;AACjH,MAAM,MAAM,aAAa,CAAC,OAAO,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC;AAEhG,MAAM,MAAM,YAAY,CAAC,OAAO,IAAI;IAClC,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC;IAClE,uGAAuG;IACvG,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B,CAAC;AAEF,+CAA+C;AAC/C,eAAO,MAAM,aAAa,GAAI,OAAO,YAAY,aAAa,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,KAAG,IACsC,CAAC;AAEjI,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAqDxH"}
@@ -0,0 +1,57 @@
1
+ import { Vector3 } from "three";
2
+ /** Mounts strings and DOM nodes as they are */
3
+ export const mountDirectly = (overlays) => overlays.forEach(({ element, content }) => element.replaceChildren(content instanceof Node ? content : String(content ?? "")));
4
+ export function createOverlayLayer(container, mount) {
5
+ const layer = document.createElement("div");
6
+ Object.assign(layer.style, { position: "absolute", inset: "0", overflow: "hidden", pointerEvents: "none" });
7
+ container.append(layer);
8
+ const mounted = new Map();
9
+ const projected = new Vector3();
10
+ return {
11
+ set: (overlays) => {
12
+ const keys = new Set(overlays.map((o) => o.key));
13
+ const changed = overlays.some((o) => mounted.get(o.key)?.overlay.content !== o.content) || [...mounted.keys()].some((key) => !keys.has(key));
14
+ mounted.forEach(({ element }, key) => {
15
+ if (!keys.has(key)) {
16
+ element.remove();
17
+ mounted.delete(key);
18
+ }
19
+ });
20
+ overlays.forEach((overlay) => {
21
+ const existing = mounted.get(overlay.key);
22
+ if (existing) {
23
+ existing.overlay = overlay;
24
+ return;
25
+ }
26
+ const element = document.createElement("div");
27
+ Object.assign(element.style, { position: "absolute", left: "0", top: "0", pointerEvents: "none", visibility: "hidden" });
28
+ layer.append(element);
29
+ mounted.set(overlay.key, { element, overlay });
30
+ });
31
+ if (changed) {
32
+ mount([...mounted.entries()].map(([key, { element, overlay }]) => ({ key, element, content: overlay.content })));
33
+ }
34
+ },
35
+ update: (camera, width, height) => mounted.forEach(({ element, overlay }) => {
36
+ if (overlay.position) {
37
+ projected.copy(overlay.position).project(camera);
38
+ }
39
+ else {
40
+ projected.set(0, 0, 0);
41
+ }
42
+ const behind = projected.z < -1 || projected.z > 1;
43
+ element.style.visibility = behind ? "hidden" : "visible";
44
+ if (!behind) {
45
+ const x = ((projected.x + 1) / 2) * width;
46
+ const y = ((1 - projected.y) / 2) * height;
47
+ element.style.transform = `translate(${x}px, ${y}px) translate(-50%, -50%)`;
48
+ }
49
+ }),
50
+ dispose: () => {
51
+ layer.remove();
52
+ mounted.clear();
53
+ mount([]);
54
+ },
55
+ };
56
+ }
57
+ //# sourceMappingURL=overlays.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlays.js","sourceRoot":"","sources":["../../../src/renderers/three/overlays.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Quality tiers by resolution, the cheapest lever on a weak GPU: low renders a pixel per CSS pixel, medium up to 1.5, and high, the default, the
3
+ * screen's own pixel ratio as the r3f renderer. `auto` starts high and drops to low for good once moving frames are slow, as model viewers lower
4
+ * their resolution under load
5
+ */
6
+ export type Tier = "low" | "medium" | "high";
7
+ export type Quality = Tier | "auto";
8
+ /** `auto` starts at high, and drops to low for good once moving frames average slower than 40 per second */
9
+ export type TierGovernor = {
10
+ readonly quality: Quality;
11
+ tier: Tier;
12
+ sum: number;
13
+ count: number;
14
+ };
15
+ /** Records the time between two frames while the camera moves; true when that dropped the tier */
16
+ export declare function recordFrame(governor: TierGovernor, intervalMs: number): boolean;
17
+ export declare function getPixelRatio(tier: Tier, devicePixelRatio: number): number;
18
+ //# sourceMappingURL=quality.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.d.ts","sourceRoot":"","sources":["../../../../src/renderers/three/quality/quality.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,IAAI,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAC7C,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC;AAEpC,4GAA4G;AAC5G,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAQjG,kGAAkG;AAClG,wBAAgB,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAY/E;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAE1E"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Quality tiers by resolution, the cheapest lever on a weak GPU: low renders a pixel per CSS pixel, medium up to 1.5, and high, the default, the
3
+ * screen's own pixel ratio as the r3f renderer. `auto` starts high and drops to low for good once moving frames are slow, as model viewers lower
4
+ * their resolution under load
5
+ */
6
+ const pixelRatioCaps = { low: 1, medium: 1.5, high: Infinity };
7
+ const windowSize = 30;
8
+ const slowFrameMs = 25;
9
+ /** Longer intervals are pauses between moves, not slow frames */
10
+ const pauseMs = 250;
11
+ /** Records the time between two frames while the camera moves; true when that dropped the tier */
12
+ export function recordFrame(governor, intervalMs) {
13
+ if (governor.quality !== "auto" || governor.tier === "low" || intervalMs > pauseMs) {
14
+ return false;
15
+ }
16
+ governor.sum += intervalMs;
17
+ governor.count += 1;
18
+ if (governor.count < windowSize) {
19
+ return false;
20
+ }
21
+ const slow = governor.sum / governor.count > slowFrameMs;
22
+ Object.assign(governor, { sum: 0, count: 0 }, slow ? { tier: "low" } : {});
23
+ return slow;
24
+ }
25
+ export function getPixelRatio(tier, devicePixelRatio) {
26
+ return Math.min(devicePixelRatio, pixelRatioCaps[tier]);
27
+ }
28
+ //# sourceMappingURL=quality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.js","sourceRoot":"","sources":["../../../../src/renderers/three/quality/quality.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,MAAM,cAAc,GAAyB,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AACrF,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,WAAW,GAAG,EAAE,CAAC;AACvB,iEAAiE;AACjE,MAAM,OAAO,GAAG,GAAG,CAAC;AAEpB,kGAAkG;AAClG,MAAM,UAAU,WAAW,CAAC,QAAsB,EAAE,UAAkB;IACpE,IAAI,QAAQ,CAAC,OAAO,KAAK,MAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,KAAK,IAAI,UAAU,GAAG,OAAO,EAAE,CAAC;QACnF,OAAO,KAAK,CAAC;IACf,CAAC;IACD,QAAQ,CAAC,GAAG,IAAI,UAAU,CAAC;IAC3B,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;IACpB,IAAI,QAAQ,CAAC,KAAK,GAAG,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,GAAG,QAAQ,CAAC,KAAK,GAAG,WAAW,CAAC;IACzD,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3E,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAU,EAAE,gBAAwB;IAChE,OAAO,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=quality.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.test.d.ts","sourceRoot":"","sources":["../../../../src/renderers/three/quality/quality.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,23 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { recordFrame } from "./quality.js";
3
+ const governor = (quality) => ({ quality, tier: quality === "auto" ? "medium" : quality, sum: 0, count: 0 });
4
+ const record = (g, intervals) => intervals.map((ms) => recordFrame(g, ms));
5
+ describe("recordFrame", () => {
6
+ it("keeps a fixed quality", () => {
7
+ const g = governor("high");
8
+ record(g, Array(100).fill(100));
9
+ expect(g.tier).toBe("high");
10
+ });
11
+ it("drops auto to low for good when moving frames are slow", () => {
12
+ const g = governor("auto");
13
+ expect(record(g, Array(30).fill(40)).filter(Boolean)).toHaveLength(1);
14
+ record(g, Array(100).fill(5));
15
+ expect(g.tier).toBe("low");
16
+ });
17
+ it("keeps auto at medium at 60 frames per second, ignoring the pauses between moves", () => {
18
+ const g = governor("auto");
19
+ record(g, Array.from({ length: 100 }, (_, i) => (i % 10 === 0 ? 2000 : 16.7)));
20
+ expect(g.tier).toBe("medium");
21
+ });
22
+ });
23
+ //# sourceMappingURL=quality.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.test.js","sourceRoot":"","sources":["../../../../src/renderers/three/quality/quality.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,QAAQ,GAAG,CAAC,OAAgB,EAAgB,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AACpI,MAAM,MAAM,GAAG,CAAC,CAAe,EAAE,SAAgC,EAA0B,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAExI,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3B,MAAM,CAAC,CAAC,EAAE,KAAK,CAAS,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAS,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9E,MAAM,CAAC,CAAC,EAAE,KAAK,CAAS,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iFAAiF,EAAE,GAAG,EAAE;QACzF,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3B,MAAM,CACJ,CAAC,EACD,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CACpE,CAAC;QACF,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { OrthographicCamera, PerspectiveCamera, Scene } from "three";
2
+ import { type WebGPURenderer } from "three/webgpu";
3
+ /**
4
+ * Quality tiers that spend the GPU where it shows: the camera is still most of the time, and a still frame can afford ambient occlusion that a moving
5
+ * one can't on a weak GPU
6
+ */
7
+ export type Tier = "low" | "medium" | "high";
8
+ export type Quality = Tier | "auto";
9
+ export declare const getPixelRatio: (tier: Tier, devicePixelRatio: number) => number;
10
+ export type TierGovernor = {
11
+ readonly tier: () => Tier;
12
+ /** Records the time between two frames while the camera moves; returns the new tier when it changes */
13
+ readonly record: (intervalMs: number) => Tier | undefined;
14
+ };
15
+ /** `auto` starts at medium, and drops to low for good once moving frames average slower than 40 per second */
16
+ export declare function createTierGovernor(quality: Quality): TierGovernor;
17
+ export type RenderPath = {
18
+ /** Renders a frame; true while the frame at rest needs more frames to fade its ambient occlusion in */
19
+ readonly render: (moving: boolean) => boolean;
20
+ readonly dispose: () => void;
21
+ };
22
+ /** Low renders directly; medium adds ambient occlusion at rest, faded in; high has it while moving too */
23
+ export declare function createRenderPath(renderer: WebGPURenderer, scene: Scene, camera: PerspectiveCamera | OrthographicCamera, tier: Tier, aoRadius: number): RenderPath;
24
+ //# sourceMappingURL=quality.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.d.ts","sourceRoot":"","sources":["../../../src/renderers/three/quality.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAG1E,OAAO,EAA6B,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9E;;;GAGG;AAEH,MAAM,MAAM,IAAI,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAC7C,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC;AAIpC,eAAO,MAAM,aAAa,SAAU,IAAI,oBAAoB,MAAM,KAAG,MAA0D,CAAC;AAEhI,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;IAC1B,uGAAuG;IACvG,QAAQ,CAAC,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,GAAG,SAAS,CAAC;CAC3D,CAAC;AAOF,8GAA8G;AAC9G,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,CAkBjE;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,uGAAuG;IACvG,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B,CAAC;AAIF,0GAA0G;AAC1G,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,iBAAiB,GAAG,kBAAkB,EAC9C,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,GACf,UAAU,CAkCZ"}
@@ -0,0 +1,67 @@
1
+ import { ao } from "three/addons/tsl/display/GTAONode.js";
2
+ import { float, mix, pass, screenUV, uniform, vec4 } from "three/tsl";
3
+ import { RenderPipeline } from "three/webgpu";
4
+ const pixelRatioCaps = { low: 1, medium: 1.5, high: 2 };
5
+ export const getPixelRatio = (tier, devicePixelRatio) => Math.min(devicePixelRatio, pixelRatioCaps[tier]);
6
+ const windowSize = 30;
7
+ const slowFrameMs = 25;
8
+ /** Longer intervals are pauses between moves, not slow frames */
9
+ const pauseMs = 250;
10
+ /** `auto` starts at medium, and drops to low for good once moving frames average slower than 40 per second */
11
+ export function createTierGovernor(quality) {
12
+ const state = { tier: quality === "auto" ? "medium" : quality, sum: 0, count: 0 };
13
+ return {
14
+ tier: () => state.tier,
15
+ record: (intervalMs) => {
16
+ if (quality !== "auto" || state.tier === "low" || intervalMs > pauseMs) {
17
+ return undefined;
18
+ }
19
+ state.sum += intervalMs;
20
+ state.count += 1;
21
+ if (state.count < windowSize) {
22
+ return undefined;
23
+ }
24
+ const slow = state.sum / state.count > slowFrameMs;
25
+ Object.assign(state, { sum: 0, count: 0 }, slow ? { tier: "low" } : {});
26
+ return slow ? state.tier : undefined;
27
+ },
28
+ };
29
+ }
30
+ const fadeFrames = 6;
31
+ /** Low renders directly; medium adds ambient occlusion at rest, faded in; high has it while moving too */
32
+ export function createRenderPath(renderer, scene, camera, tier, aoRadius) {
33
+ if (tier === "low") {
34
+ return { render: () => (renderer.render(scene, camera), false), dispose: () => undefined };
35
+ }
36
+ const pipeline = new RenderPipeline(renderer);
37
+ // Multisampled, as SMAA would lose the antialiased alpha at edges over the transparent background
38
+ const scenePass = pass(scene, camera, { samples: 4 });
39
+ const color = scenePass.getTextureNode("output");
40
+ // Normals are reconstructed from depth, so there's no extra normal pass; the typings miss that the normal node is optional
41
+ const aoPass = ao(scenePass.getTextureNode("depth"), null, camera);
42
+ aoPass.resolutionScale = 0.5;
43
+ aoPass.radius.value = aoRadius;
44
+ const strength = uniform(0);
45
+ const occlusion = mix(float(1), aoPass.getTextureNode().sample(screenUV).r, strength);
46
+ pipeline.outputNode = vec4(color.rgb.mul(occlusion), color.a);
47
+ const fade = { frame: 0 };
48
+ return {
49
+ render: (moving) => {
50
+ if (moving && tier === "medium") {
51
+ fade.frame = 0;
52
+ renderer.render(scene, camera);
53
+ return false;
54
+ }
55
+ fade.frame = tier === "high" ? fadeFrames : Math.min(fadeFrames, fade.frame + 1);
56
+ strength.value = fade.frame / fadeFrames;
57
+ pipeline.render();
58
+ return fade.frame < fadeFrames;
59
+ },
60
+ dispose: () => {
61
+ aoPass.dispose();
62
+ scenePass.dispose();
63
+ pipeline.dispose();
64
+ },
65
+ };
66
+ }
67
+ //# sourceMappingURL=quality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.js","sourceRoot":"","sources":["../../../src/renderers/three/quality.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { Group } from "three";
2
+ import type { BuiltScene } from "../build/build.js";
3
+ /** The light and its target, to add to the scene, with or without shadows; undefined for a scene without solids */
4
+ export declare function createKeyLight(built: BuiltScene, shadows: boolean): Group | undefined;
5
+ export declare function disposeKeyLight(key: Group): void;
6
+ //# sourceMappingURL=key-light.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-light.d.ts","sourceRoot":"","sources":["../../../../src/renderers/three/shadow/key-light.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,EAAmB,MAAM,OAAO,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAcpD,mHAAmH;AACnH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,KAAK,GAAG,SAAS,CAiBrF;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,CAOhD"}
@@ -0,0 +1,39 @@
1
+ import { DirectionalLight, Group, Sphere, Vector3 } from "three";
2
+ import { getShadowCasters } from "./shadow.js";
3
+ /**
4
+ * A key light from the upper left front, on top of the studio's soft light, that casts the solids' shadows on themselves, e.g. under a roof or behind
5
+ * a profile. Its shadow map is rendered once per build, as the scene doesn't move, so a frame only samples it; the casters are the ground shadow's
6
+ */
7
+ const direction = new Vector3(-1, 2, 1.2).normalize();
8
+ const intensity = 1.6;
9
+ const mapSize = 2048;
10
+ /** Of the key light kept out of its shadows, so faces under an overhang, e.g. a recessed base frame, aren't black */
11
+ const shadowIntensity = 0.6;
12
+ /** The light and its target, to add to the scene, with or without shadows; undefined for a scene without solids */
13
+ export function createKeyLight(built, shadows) {
14
+ const { bounds } = getShadowCasters(built);
15
+ if (bounds.isEmpty()) {
16
+ return undefined;
17
+ }
18
+ const { center, radius } = bounds.getBoundingSphere(new Sphere());
19
+ const light = new DirectionalLight(0xffffff, intensity);
20
+ light.position.copy(center).addScaledVector(direction, radius * 2);
21
+ light.target.position.copy(center);
22
+ light.castShadow = shadows;
23
+ // The shadow camera just encloses the scene, so the map's texels are as small as they can be
24
+ Object.assign(light.shadow.camera, { left: -radius, right: radius, top: radius, bottom: -radius, near: radius, far: radius * 3 });
25
+ light.shadow.camera.updateProjectionMatrix();
26
+ light.shadow.mapSize.set(mapSize, mapSize);
27
+ // Offsets along the normal by three texels, against shadow acne on the lit faces
28
+ Object.assign(light.shadow, { bias: -0.0005, normalBias: (radius * 6) / mapSize, radius: 3, intensity: shadowIntensity });
29
+ return new Group().add(light, light.target);
30
+ }
31
+ export function disposeKeyLight(key) {
32
+ key.removeFromParent();
33
+ key.children.forEach((child) => {
34
+ if (child instanceof DirectionalLight) {
35
+ child.shadow.dispose();
36
+ }
37
+ });
38
+ }
39
+ //# sourceMappingURL=key-light.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-light.js","sourceRoot":"","sources":["../../../../src/renderers/three/shadow/key-light.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C;;;GAGG;AAEH,MAAM,SAAS,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC;AACtD,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,OAAO,GAAG,IAAI,CAAC;AACrB,qHAAqH;AACrH,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,mHAAmH;AACnH,MAAM,UAAU,cAAc,CAAC,KAAiB,EAAE,OAAgB;IAChE,MAAM,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,iBAAiB,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,IAAI,gBAAgB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACxD,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC;IACnE,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,KAAK,CAAC,UAAU,GAAG,OAAO,CAAC;IAC3B,6FAA6F;IAC7F,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC;IAClI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,sBAAsB,EAAE,CAAC;IAC7C,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3C,iFAAiF;IACjF,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAAC;IAC1H,OAAO,IAAI,KAAK,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAU;IACxC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACvB,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC7B,IAAI,KAAK,YAAY,gBAAgB,EAAE,CAAC;YACtC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACzB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { type BatchedMesh, Box3, type Scene, Mesh, MeshBasicMaterial, PlaneGeometry, type WebGLRenderer, WebGLRenderTarget } from "three";
2
+ import type { BuiltScene } from "../build/build.js";
3
+ /**
4
+ * A soft shadow on the ground the scene stands on, rendered once per build: the solids seen from below by their depth, darker the closer to the
5
+ * ground, blurred into a texture on a plane, so a frame costs one textured quad. three.js's webgl_shadow_contact example, rendered once as drei's
6
+ * ContactShadows with `frames={1}`
7
+ */
8
+ export type GroundShadow = {
9
+ readonly mesh: Mesh<PlaneGeometry, MeshBasicMaterial>;
10
+ readonly floor: Mesh<PlaneGeometry, MeshBasicMaterial>;
11
+ readonly target: WebGLRenderTarget;
12
+ };
13
+ /** The batches of solids that cast shadows, with their bounds: opaque ones whose material doesn't turn it off, not text, lines, images or dimensions */
14
+ export declare function getShadowCasters(built: BuiltScene): {
15
+ readonly casters: ReadonlyArray<BatchedMesh>;
16
+ readonly bounds: Box3;
17
+ };
18
+ /** Undefined for a scene without solids; renders with `renderer`, and leaves its render target as it was */
19
+ export declare function createGroundShadow(renderer: WebGLRenderer, scene: Scene, built: BuiltScene): GroundShadow | undefined;
20
+ export declare function disposeGroundShadow(shadow: GroundShadow): void;
21
+ //# sourceMappingURL=shadow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow.d.ts","sourceRoot":"","sources":["../../../../src/renderers/three/shadow/shadow.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,IAAI,EAGJ,KAAK,KAAK,EACV,IAAI,EACJ,iBAAiB,EAGjB,aAAa,EAIb,KAAK,aAAa,EAClB,iBAAiB,EAClB,MAAM,OAAO,CAAC;AAIf,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;;GAIG;AAEH,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC;IACtD,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC;IACvD,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;CACpC,CAAC;AAcF,wJAAwJ;AACxJ,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAA;CAAE,CAU3H;AAED,4GAA4G;AAC5G,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,GAAG,YAAY,GAAG,SAAS,CAwErH;AAeD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAQ9D"}
@@ -0,0 +1,120 @@
1
+ import { Box3, CanvasTexture, HalfFloatType, Mesh, MeshBasicMaterial, MeshDepthMaterial, OrthographicCamera, PlaneGeometry, ShaderMaterial, UniformsUtils, Vector3, WebGLRenderTarget, } from "three";
2
+ import { FullScreenQuad } from "three/addons/postprocessing/Pass.js";
3
+ import { HorizontalBlurShader } from "three/addons/shaders/HorizontalBlurShader.js";
4
+ import { VerticalBlurShader } from "three/addons/shaders/VerticalBlurShader.js";
5
+ /** The layer the solids are drawn on for the shadow, so text, lines, images and dimensions don't cast one */
6
+ const shadowLayer = 1;
7
+ /** Of the texture's longer side */
8
+ const resolution = 512;
9
+ /** The blur's reach, of the solids' height */
10
+ const softness = 0.22;
11
+ const opacity = 1;
12
+ /** A pool of light on the floor the shadow lies in, so it shows on a dark background, which a shadow alone can't darken; on white it's invisible */
13
+ const floorLight = 0.06;
14
+ /** The pool's reach beyond the solids, of their height */
15
+ const floorReach = 1;
16
+ /** The batches of solids that cast shadows, with their bounds: opaque ones whose material doesn't turn it off, not text, lines, images or dimensions */
17
+ export function getShadowCasters(built) {
18
+ const casters = [];
19
+ const bounds = new Box3();
20
+ built.parts.forEach((part) => {
21
+ if (part.kind === "solid" && part.object.castShadow && part.object.parent !== built.dimensions && part.object.boundingBox) {
22
+ casters.push(part.object);
23
+ bounds.union(part.object.boundingBox);
24
+ }
25
+ });
26
+ return { casters, bounds };
27
+ }
28
+ /** Undefined for a scene without solids; renders with `renderer`, and leaves its render target as it was */
29
+ export function createGroundShadow(renderer, scene, built) {
30
+ const { casters, bounds } = getShadowCasters(built);
31
+ if (bounds.isEmpty()) {
32
+ return undefined;
33
+ }
34
+ casters.forEach((caster) => caster.layers.enable(shadowLayer));
35
+ const size = bounds.getSize(new Vector3());
36
+ // The plane reaches past the solids by twice the blur's reach on every side
37
+ const reach = softness * size.y;
38
+ const [width, depth] = [size.x + reach * 4, size.z + reach * 4];
39
+ const center = new Vector3((bounds.min.x + bounds.max.x) / 2, bounds.min.y, (bounds.min.z + bounds.max.z) / 2);
40
+ const [texelsX, texelsZ] = width > depth ? [resolution, Math.ceil((resolution * depth) / width)] : [Math.ceil((resolution * width) / depth), resolution];
41
+ // Half float, so the blur's soft falloff isn't rounded into steps
42
+ const halfFloat = { type: HalfFloatType };
43
+ const [target, blurred] = [new WebGLRenderTarget(texelsX, texelsZ, halfFloat), new WebGLRenderTarget(texelsX, texelsZ, halfFloat)];
44
+ // Looks up from the ground, seeing as far as the solids are high
45
+ const camera = new OrthographicCamera(-width / 2, width / 2, depth / 2, -depth / 2, 0, size.y);
46
+ camera.position.copy(center);
47
+ camera.rotation.x = Math.PI / 2;
48
+ camera.layers.set(shadowLayer);
49
+ camera.updateMatrixWorld();
50
+ // Depth tested, so at each point the surface closest to the ground darkens it, not the last one drawn
51
+ const darkness = new MeshDepthMaterial();
52
+ darkness.onBeforeCompile = (shader) => {
53
+ shader.fragmentShader = shader.fragmentShader.replace("gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );", "gl_FragColor = vec4( vec3( 0.0 ), sqrt( 1.0 - fragCoordZ ) );");
54
+ };
55
+ const previous = renderer.getRenderTarget();
56
+ Object.assign(scene, { overrideMaterial: darkness });
57
+ renderer.setRenderTarget(target);
58
+ renderer.render(scene, camera);
59
+ Object.assign(scene, { overrideMaterial: null });
60
+ const horizontal = new ShaderMaterial({ ...HorizontalBlurShader, uniforms: UniformsUtils.clone(HorizontalBlurShader.uniforms) });
61
+ const vertical = new ShaderMaterial({ ...VerticalBlurShader, uniforms: UniformsUtils.clone(VerticalBlurShader.uniforms) });
62
+ const quad = new FullScreenQuad(horizontal);
63
+ // The blur shaders reach 4 steps; three passes of shrinking steps blend into one smooth falloff
64
+ const step = (reach * texelsX) / width / 4;
65
+ [step, step / 2, step / 4].forEach((amount) => {
66
+ Object.assign(horizontal.uniforms, { tDiffuse: { value: target.texture }, h: { value: amount / texelsX } });
67
+ quad.material = horizontal;
68
+ renderer.setRenderTarget(blurred);
69
+ quad.render(renderer);
70
+ Object.assign(vertical.uniforms, { tDiffuse: { value: blurred.texture }, v: { value: amount / texelsZ } });
71
+ quad.material = vertical;
72
+ renderer.setRenderTarget(target);
73
+ quad.render(renderer);
74
+ });
75
+ renderer.setRenderTarget(previous);
76
+ [blurred, darkness, horizontal, vertical, quad].forEach((d) => d.dispose());
77
+ // The plane faces down as the camera looked up, so its texture lines up, and is mirrored to face up
78
+ const mesh = new Mesh(new PlaneGeometry(width, depth).rotateX(Math.PI / 2), ditherAlpha(new MeshBasicMaterial({ map: target.texture, transparent: true, depthWrite: false, opacity }), 2));
79
+ mesh.position.copy(center);
80
+ mesh.scale.y = -1;
81
+ // The floor's pool of light first, then the shadow in it, both before other transparent objects
82
+ const floor = new Mesh(new PlaneGeometry(size.x + size.y * floorReach * 2, size.z + size.y * floorReach * 2).rotateX(-Math.PI / 2), ditherAlpha(new MeshBasicMaterial({ alphaMap: createPool(), transparent: true, depthWrite: false, opacity: floorLight }), 1));
83
+ floor.position.copy(center);
84
+ Object.assign(floor, { renderOrder: -2 });
85
+ Object.assign(mesh, { renderOrder: -1 });
86
+ scene.add(floor, mesh);
87
+ return { mesh, floor, target };
88
+ }
89
+ /** A radial falloff from the center to the edges, as a spotlight's pool on the floor */
90
+ function createPool() {
91
+ const canvas = Object.assign(document.createElement("canvas"), { width: 128, height: 128 });
92
+ const ctx = canvas.getContext("2d");
93
+ const gradient = ctx.createRadialGradient(64, 64, 0, 64, 64, 64);
94
+ gradient.addColorStop(0, "#fff");
95
+ gradient.addColorStop(0.3, "#999");
96
+ gradient.addColorStop(0.7, "#222");
97
+ gradient.addColorStop(1, "#000");
98
+ Object.assign(ctx, { fillStyle: gradient }).fillRect(0, 0, 128, 128);
99
+ return new CanvasTexture(canvas);
100
+ }
101
+ export function disposeGroundShadow(shadow) {
102
+ [shadow.mesh, shadow.floor].forEach((mesh) => {
103
+ mesh.removeFromParent();
104
+ mesh.geometry.dispose();
105
+ mesh.material.alphaMap?.dispose();
106
+ mesh.material.dispose();
107
+ });
108
+ shadow.target.dispose();
109
+ }
110
+ /**
111
+ * Jitters the alpha by about `levels` of the screen's 256 per pixel, so a faint gradient blended over the background doesn't show the 8-bit steps of
112
+ * the blend; three's `dithering` jitters the color, which these blends' steps don't come from
113
+ */
114
+ function ditherAlpha(material, levels) {
115
+ material.onBeforeCompile = (shader) => {
116
+ shader.fragmentShader = shader.fragmentShader.replace("#include <dithering_fragment>", `gl_FragColor.a = clamp( gl_FragColor.a + ( rand( gl_FragCoord.xy ) - 0.5 ) * ${(levels / 255).toFixed(5)}, 0.0, 1.0 );`);
117
+ };
118
+ return material;
119
+ }
120
+ //# sourceMappingURL=shadow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow.js","sourceRoot":"","sources":["../../../../src/renderers/three/shadow/shadow.ts"],"names":[],"mappings":"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"}