@drawcall/lod 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. package/README.md +13 -70
  2. package/dist/at.d.ts +2 -0
  3. package/dist/at.js +8 -0
  4. package/dist/at.js.map +1 -0
  5. package/dist/bake.d.ts +22 -0
  6. package/dist/bake.js +88 -0
  7. package/dist/bake.js.map +1 -0
  8. package/dist/baked/codec.d.ts +5 -5
  9. package/dist/baked/codec.js +58 -158
  10. package/dist/baked/codec.js.map +1 -1
  11. package/dist/baked/coverage.d.ts +6 -3
  12. package/dist/baked/coverage.js +6 -3
  13. package/dist/baked/coverage.js.map +1 -1
  14. package/dist/baked/fields.d.ts +9 -0
  15. package/dist/baked/fields.js +22 -0
  16. package/dist/baked/fields.js.map +1 -0
  17. package/dist/baked/index.d.ts +16 -6
  18. package/dist/baked/index.js +23 -21
  19. package/dist/baked/index.js.map +1 -1
  20. package/dist/baked/interior/faces.d.ts +4 -3
  21. package/dist/baked/interior/faces.js +13 -10
  22. package/dist/baked/interior/faces.js.map +1 -1
  23. package/dist/baked/interior/material.d.ts +7 -10
  24. package/dist/baked/interior/material.js +29 -36
  25. package/dist/baked/interior/material.js.map +1 -1
  26. package/dist/baked/interior/rooms.js +1 -1
  27. package/dist/baked/interior/rooms.js.map +1 -1
  28. package/dist/baked/low.d.ts +2 -2
  29. package/dist/baked/low.js +9 -8
  30. package/dist/baked/low.js.map +1 -1
  31. package/dist/baked/raster.js +6 -6
  32. package/dist/baked/raster.js.map +1 -1
  33. package/dist/baked/textures.d.ts +17 -0
  34. package/dist/baked/textures.js +95 -0
  35. package/dist/baked/textures.js.map +1 -0
  36. package/dist/baked/transfer.js +19 -18
  37. package/dist/baked/transfer.js.map +1 -1
  38. package/dist/baked/unwrap.js +4 -3
  39. package/dist/baked/unwrap.js.map +1 -1
  40. package/dist/baked/xatlas.js.map +1 -1
  41. package/dist/codec/container.d.ts +8 -0
  42. package/dist/codec/container.js +63 -0
  43. package/dist/codec/container.js.map +1 -0
  44. package/dist/codec/mesh.d.ts +8 -0
  45. package/dist/codec/mesh.js +220 -0
  46. package/dist/codec/mesh.js.map +1 -0
  47. package/dist/dispose.d.ts +11 -4
  48. package/dist/dispose.js +39 -12
  49. package/dist/dispose.js.map +1 -1
  50. package/dist/gpu.d.ts +39 -0
  51. package/dist/gpu.js +41 -0
  52. package/dist/gpu.js.map +1 -0
  53. package/dist/impostor/bake/atlas.d.ts +4 -4
  54. package/dist/impostor/bake/atlas.js +12 -12
  55. package/dist/impostor/bake/atlas.js.map +1 -1
  56. package/dist/impostor/bake/fit.d.ts +8 -0
  57. package/dist/impostor/bake/fit.js +28 -0
  58. package/dist/impostor/bake/fit.js.map +1 -0
  59. package/dist/impostor/bake/index.d.ts +23 -14
  60. package/dist/impostor/bake/index.js +42 -134
  61. package/dist/impostor/bake/index.js.map +1 -1
  62. package/dist/impostor/bake/materials.d.ts +3 -3
  63. package/dist/impostor/bake/materials.js +60 -12
  64. package/dist/impostor/bake/materials.js.map +1 -1
  65. package/dist/impostor/bake/sheet.d.ts +8 -0
  66. package/dist/impostor/bake/sheet.js +90 -0
  67. package/dist/impostor/bake/sheet.js.map +1 -0
  68. package/dist/impostor/bake/source.d.ts +2 -2
  69. package/dist/impostor/bake/source.js +8 -19
  70. package/dist/impostor/bake/source.js.map +1 -1
  71. package/dist/impostor/codec.d.ts +5 -11
  72. package/dist/impostor/codec.js +37 -121
  73. package/dist/impostor/codec.js.map +1 -1
  74. package/dist/impostor/impostor.d.ts +31 -7
  75. package/dist/impostor/impostor.js +21 -6
  76. package/dist/impostor/impostor.js.map +1 -1
  77. package/dist/impostor/ktx2/encode.d.ts +26 -0
  78. package/dist/impostor/ktx2/encode.js +117 -0
  79. package/dist/impostor/ktx2/encode.js.map +1 -0
  80. package/dist/impostor/ktx2/transcode.d.ts +3 -0
  81. package/dist/impostor/ktx2/transcode.js +99 -0
  82. package/dist/impostor/ktx2/transcode.js.map +1 -0
  83. package/dist/impostor/ktx2/uastc.d.ts +7 -0
  84. package/dist/impostor/ktx2/uastc.js +64 -0
  85. package/dist/impostor/ktx2/uastc.js.map +1 -0
  86. package/dist/impostor/ktx2/wasm/encoder.d.ts +4 -0
  87. package/dist/impostor/ktx2/wasm/encoder.js +10 -0
  88. package/dist/impostor/ktx2/wasm/encoder.js.map +1 -0
  89. package/dist/impostor/ktx2/wasm/transcoder.d.ts +3 -0
  90. package/dist/impostor/ktx2/wasm/transcoder.js +9 -0
  91. package/dist/impostor/ktx2/wasm/transcoder.js.map +1 -0
  92. package/dist/impostor/ktx2/worker.d.ts +1 -0
  93. package/dist/impostor/ktx2/worker.js +12 -0
  94. package/dist/impostor/ktx2/worker.js.map +1 -0
  95. package/dist/impostor/mesh/card.d.ts +3 -3
  96. package/dist/impostor/mesh/card.js +11 -8
  97. package/dist/impostor/mesh/card.js.map +1 -1
  98. package/dist/impostor/mesh/index.d.ts +10 -7
  99. package/dist/impostor/mesh/index.js +15 -18
  100. package/dist/impostor/mesh/index.js.map +1 -1
  101. package/dist/impostor/mesh/material.d.ts +24 -13
  102. package/dist/impostor/mesh/material.js +67 -51
  103. package/dist/impostor/mesh/material.js.map +1 -1
  104. package/dist/impostor/mesh/surface.d.ts +20 -16
  105. package/dist/impostor/mesh/surface.js +81 -58
  106. package/dist/impostor/mesh/surface.js.map +1 -1
  107. package/dist/impostor/mesh/textures.d.ts +3 -3
  108. package/dist/impostor/mesh/textures.js +24 -34
  109. package/dist/impostor/mesh/textures.js.map +1 -1
  110. package/dist/impostor/octahedral.d.ts +1 -8
  111. package/dist/impostor/octahedral.js +3 -18
  112. package/dist/impostor/octahedral.js.map +1 -1
  113. package/dist/index.d.ts +16 -10
  114. package/dist/index.js +14 -8
  115. package/dist/index.js.map +1 -1
  116. package/dist/instanced/camera.d.ts +46 -0
  117. package/dist/instanced/camera.js +70 -0
  118. package/dist/instanced/camera.js.map +1 -0
  119. package/dist/instanced/chunk.d.ts +97 -0
  120. package/dist/instanced/chunk.js +156 -0
  121. package/dist/instanced/chunk.js.map +1 -0
  122. package/dist/instanced/chunks.d.ts +60 -0
  123. package/dist/instanced/chunks.js +208 -0
  124. package/dist/instanced/chunks.js.map +1 -0
  125. package/dist/instanced/cull.d.ts +28 -0
  126. package/dist/instanced/cull.js +22 -0
  127. package/dist/instanced/cull.js.map +1 -0
  128. package/dist/instanced/index.d.ts +96 -92
  129. package/dist/instanced/index.js +229 -512
  130. package/dist/instanced/index.js.map +1 -1
  131. package/dist/instanced/key.d.ts +19 -0
  132. package/dist/instanced/key.js +45 -0
  133. package/dist/instanced/key.js.map +1 -0
  134. package/dist/instanced/levels.d.ts +60 -0
  135. package/dist/instanced/levels.js +130 -0
  136. package/dist/instanced/levels.js.map +1 -0
  137. package/dist/instanced/lists.d.ts +70 -0
  138. package/dist/instanced/lists.js +133 -0
  139. package/dist/instanced/lists.js.map +1 -0
  140. package/dist/instanced/measure.d.ts +28 -0
  141. package/dist/instanced/measure.js +203 -0
  142. package/dist/instanced/measure.js.map +1 -0
  143. package/dist/instanced/meshes.d.ts +46 -14
  144. package/dist/instanced/meshes.js +137 -22
  145. package/dist/instanced/meshes.js.map +1 -1
  146. package/dist/instanced/mirror.d.ts +20 -0
  147. package/dist/instanced/mirror.js +37 -0
  148. package/dist/instanced/mirror.js.map +1 -0
  149. package/dist/instanced/pages/buffers.d.ts +37 -0
  150. package/dist/instanced/pages/buffers.js +15 -0
  151. package/dist/instanced/pages/buffers.js.map +1 -0
  152. package/dist/instanced/pages/chunk.d.ts +51 -0
  153. package/dist/instanced/pages/chunk.js +81 -0
  154. package/dist/instanced/pages/chunk.js.map +1 -0
  155. package/dist/instanced/pages/index.d.ts +74 -0
  156. package/dist/instanced/pages/index.js +269 -0
  157. package/dist/instanced/pages/index.js.map +1 -0
  158. package/dist/instanced/pages/passes.d.ts +21 -0
  159. package/dist/instanced/pages/passes.js +52 -0
  160. package/dist/instanced/pages/passes.js.map +1 -0
  161. package/dist/instanced/pages/slots.d.ts +11 -0
  162. package/dist/instanced/pages/slots.js +90 -0
  163. package/dist/instanced/pages/slots.js.map +1 -0
  164. package/dist/instanced/pages/workgroup.d.ts +14 -0
  165. package/dist/instanced/pages/workgroup.js +38 -0
  166. package/dist/instanced/pages/workgroup.js.map +1 -0
  167. package/dist/instanced/raycast.d.ts +15 -0
  168. package/dist/instanced/raycast.js +46 -0
  169. package/dist/instanced/raycast.js.map +1 -0
  170. package/dist/instanced/rows.d.ts +108 -0
  171. package/dist/instanced/rows.js +209 -0
  172. package/dist/instanced/rows.js.map +1 -0
  173. package/dist/instanced/shape.d.ts +25 -0
  174. package/dist/instanced/shape.js +51 -0
  175. package/dist/instanced/shape.js.map +1 -0
  176. package/dist/instanced/sort.d.ts +63 -0
  177. package/dist/instanced/sort.js +162 -0
  178. package/dist/instanced/sort.js.map +1 -0
  179. package/dist/instanced/update.d.ts +30 -0
  180. package/dist/instanced/update.js +207 -0
  181. package/dist/instanced/update.js.map +1 -0
  182. package/dist/levels/bounds.d.ts +21 -0
  183. package/dist/levels/bounds.js +42 -0
  184. package/dist/levels/bounds.js.map +1 -0
  185. package/dist/levels/cameras.d.ts +48 -0
  186. package/dist/levels/cameras.js +122 -0
  187. package/dist/levels/cameras.js.map +1 -0
  188. package/dist/levels/compile/contexts.d.ts +30 -0
  189. package/dist/levels/compile/contexts.js +18 -0
  190. package/dist/levels/compile/contexts.js.map +1 -0
  191. package/dist/levels/compile/index.d.ts +39 -0
  192. package/dist/levels/compile/index.js +185 -0
  193. package/dist/levels/compile/index.js.map +1 -0
  194. package/dist/levels/compile/pipelines.d.ts +26 -0
  195. package/dist/levels/compile/pipelines.js +177 -0
  196. package/dist/levels/compile/pipelines.js.map +1 -0
  197. package/dist/levels/compiles.d.ts +29 -0
  198. package/dist/levels/compiles.js +50 -0
  199. package/dist/levels/compiles.js.map +1 -0
  200. package/dist/levels/draw.d.ts +102 -0
  201. package/dist/levels/draw.js +401 -0
  202. package/dist/levels/draw.js.map +1 -0
  203. package/dist/levels/fade.d.ts +69 -0
  204. package/dist/levels/fade.js +150 -0
  205. package/dist/levels/fade.js.map +1 -0
  206. package/dist/levels/index.d.ts +99 -0
  207. package/dist/levels/index.js +155 -0
  208. package/dist/levels/index.js.map +1 -0
  209. package/dist/levels/item.d.ts +38 -0
  210. package/dist/levels/item.js +97 -0
  211. package/dist/levels/item.js.map +1 -0
  212. package/dist/levels/load.d.ts +31 -0
  213. package/dist/levels/load.js +142 -0
  214. package/dist/levels/load.js.map +1 -0
  215. package/dist/levels/manager.d.ts +159 -0
  216. package/dist/levels/manager.js +339 -0
  217. package/dist/levels/manager.js.map +1 -0
  218. package/dist/{material.js → levels/material.js} +13 -7
  219. package/dist/levels/material.js.map +1 -0
  220. package/dist/levels/renderer.d.ts +29 -0
  221. package/dist/levels/renderer.js +41 -0
  222. package/dist/levels/renderer.js.map +1 -0
  223. package/dist/levels/requests.d.ts +49 -0
  224. package/dist/levels/requests.js +95 -0
  225. package/dist/levels/requests.js.map +1 -0
  226. package/dist/levels/screen.d.ts +14 -0
  227. package/dist/levels/screen.js +21 -0
  228. package/dist/levels/screen.js.map +1 -0
  229. package/dist/levels/wait.d.ts +27 -0
  230. package/dist/levels/wait.js +61 -0
  231. package/dist/levels/wait.js.map +1 -0
  232. package/dist/loader/build.d.ts +10 -0
  233. package/dist/loader/build.js +28 -0
  234. package/dist/loader/build.js.map +1 -0
  235. package/dist/loader/cache.d.ts +12 -15
  236. package/dist/loader/cache.js +64 -33
  237. package/dist/loader/cache.js.map +1 -1
  238. package/dist/loader/context.d.ts +46 -0
  239. package/dist/loader/context.js +91 -0
  240. package/dist/loader/context.js.map +1 -0
  241. package/dist/loader/dependencies.d.ts +32 -0
  242. package/dist/loader/dependencies.js +113 -0
  243. package/dist/loader/dependencies.js.map +1 -0
  244. package/dist/loader/index.d.ts +62 -0
  245. package/dist/loader/index.js +284 -0
  246. package/dist/loader/index.js.map +1 -0
  247. package/dist/loader/level.d.ts +41 -0
  248. package/dist/loader/level.js +140 -0
  249. package/dist/loader/level.js.map +1 -0
  250. package/dist/loader/request.d.ts +87 -0
  251. package/dist/loader/request.js +59 -0
  252. package/dist/loader/request.js.map +1 -0
  253. package/dist/loader/url.d.ts +16 -0
  254. package/dist/loader/url.js +35 -0
  255. package/dist/loader/url.js.map +1 -0
  256. package/dist/lod.d.ts +79 -49
  257. package/dist/lod.js +209 -153
  258. package/dist/lod.js.map +1 -1
  259. package/dist/meshopt.d.ts +6 -0
  260. package/dist/meshopt.js +19 -0
  261. package/dist/meshopt.js.map +1 -0
  262. package/dist/simplify/cards.d.ts +14 -0
  263. package/dist/simplify/cards.js +128 -0
  264. package/dist/simplify/cards.js.map +1 -0
  265. package/dist/{simplify.d.ts → simplify/index.d.ts} +7 -4
  266. package/dist/{simplify.js → simplify/index.js} +42 -22
  267. package/dist/simplify/index.js.map +1 -0
  268. package/dist/{bounds.d.ts → source/detail.d.ts} +4 -13
  269. package/dist/{bounds.js → source/detail.js} +62 -32
  270. package/dist/source/detail.js.map +1 -0
  271. package/dist/source/{error.d.ts → deviation.d.ts} +3 -3
  272. package/dist/source/{error.js → deviation.js} +12 -12
  273. package/dist/source/deviation.js.map +1 -0
  274. package/dist/source/{shading.d.ts → evaluator.d.ts} +10 -10
  275. package/dist/source/{shading.js → evaluator.js} +5 -5
  276. package/dist/source/evaluator.js.map +1 -0
  277. package/dist/source/{trace.d.ts → raycaster.d.ts} +6 -6
  278. package/dist/source/{trace.js → raycaster.js} +8 -8
  279. package/dist/source/raycaster.js.map +1 -0
  280. package/dist/source/{texels.d.ts → sampler.d.ts} +1 -1
  281. package/dist/source/{texels.js → sampler.js} +3 -3
  282. package/dist/source/sampler.js.map +1 -0
  283. package/dist/source/source.d.ts +2 -2
  284. package/dist/source/source.js +2 -2
  285. package/dist/source/source.js.map +1 -1
  286. package/dist/source/surface.js +1 -1
  287. package/dist/source/surface.js.map +1 -1
  288. package/dist/task.d.ts +6 -0
  289. package/dist/{pause.js → task.js} +5 -5
  290. package/dist/task.js.map +1 -0
  291. package/dist/three.d.ts +20 -19
  292. package/dist/three.js +29 -35
  293. package/dist/three.js.map +1 -1
  294. package/dist/tsl.d.ts +10 -14
  295. package/dist/tsl.js +12 -47
  296. package/dist/tsl.js.map +1 -1
  297. package/dist/typegpu.d.ts +37 -0
  298. package/dist/typegpu.js +37 -0
  299. package/dist/typegpu.js.map +1 -0
  300. package/dist/wind/bounds.js +2 -2
  301. package/dist/wind/bounds.js.map +1 -1
  302. package/dist/wind/hooks.d.ts +7 -4
  303. package/dist/wind/hooks.js +5 -2
  304. package/dist/wind/hooks.js.map +1 -1
  305. package/dist/wind/index.d.ts +4 -4
  306. package/dist/wind/index.js +43 -40
  307. package/dist/wind/index.js.map +1 -1
  308. package/dist/wind/sway.d.ts +4 -1
  309. package/dist/wind/sway.js +4 -1
  310. package/dist/wind/sway.js.map +1 -1
  311. package/package.json +24 -8
  312. package/skills/lod/SKILL.md +147 -108
  313. package/dist/bounds.js.map +0 -1
  314. package/dist/fade.d.ts +0 -44
  315. package/dist/fade.js +0 -78
  316. package/dist/fade.js.map +0 -1
  317. package/dist/impostor/cache.d.ts +0 -15
  318. package/dist/impostor/cache.js +0 -44
  319. package/dist/impostor/cache.js.map +0 -1
  320. package/dist/instanced/args.d.ts +0 -20
  321. package/dist/instanced/args.js +0 -77
  322. package/dist/instanced/args.js.map +0 -1
  323. package/dist/instanced/bounds.d.ts +0 -50
  324. package/dist/instanced/bounds.js +0 -271
  325. package/dist/instanced/bounds.js.map +0 -1
  326. package/dist/instanced/dirty.d.ts +0 -12
  327. package/dist/instanced/dirty.js +0 -61
  328. package/dist/instanced/dirty.js.map +0 -1
  329. package/dist/instanced/select.d.ts +0 -84
  330. package/dist/instanced/select.js +0 -264
  331. package/dist/instanced/select.js.map +0 -1
  332. package/dist/lazy.d.ts +0 -64
  333. package/dist/lazy.js +0 -187
  334. package/dist/lazy.js.map +0 -1
  335. package/dist/levels.d.ts +0 -72
  336. package/dist/levels.js +0 -146
  337. package/dist/levels.js.map +0 -1
  338. package/dist/loader/dispose.d.ts +0 -3
  339. package/dist/loader/dispose.js +0 -25
  340. package/dist/loader/dispose.js.map +0 -1
  341. package/dist/loader.d.ts +0 -99
  342. package/dist/loader.js +0 -234
  343. package/dist/loader.js.map +0 -1
  344. package/dist/material.js.map +0 -1
  345. package/dist/pause.d.ts +0 -6
  346. package/dist/pause.js.map +0 -1
  347. package/dist/renderer.d.ts +0 -21
  348. package/dist/renderer.js +0 -83
  349. package/dist/renderer.js.map +0 -1
  350. package/dist/simplify.js.map +0 -1
  351. package/dist/source/error.js.map +0 -1
  352. package/dist/source/shading.js.map +0 -1
  353. package/dist/source/texels.js.map +0 -1
  354. package/dist/source/trace.js.map +0 -1
  355. package/dist/view.d.ts +0 -30
  356. package/dist/view.js +0 -75
  357. package/dist/view.js.map +0 -1
  358. /package/dist/{material.d.ts → levels/material.d.ts} +0 -0
@@ -0,0 +1,208 @@
1
+ import { Box3, InstancedBufferAttribute } from "three/webgpu";
2
+ import { isStorageInstanced } from "../three.js";
3
+ import { InstancedLodChunk, measureChunk } from "./chunk.js";
4
+ import { Mirror } from "./mirror.js";
5
+ import { MAX_SURVIVOR_SCALE } from "./measure.js";
6
+ /** `attribute`, a GPU chunk's, as the storage attribute InstancedLodChunk checked it is. */
7
+ function onGpu(attribute) {
8
+ if (!isStorageInstanced(attribute))
9
+ throw new TypeError("InstancedLod: a GPU chunk's attribute is not a storage attribute");
10
+ return attribute;
11
+ }
12
+ const grown = new Box3();
13
+ /**
14
+ * The chunks of one InstancedLod: their pool slots, the mirrors the pool reads CPU attributes through, and their
15
+ * bounds, which load levels and cull the level meshes.
16
+ */
17
+ export class ChunkSet {
18
+ pool;
19
+ row;
20
+ bounds;
21
+ reach;
22
+ levelAt;
23
+ held = new Map();
24
+ mirrors = new Map();
25
+ /** Bumped whenever a chunk was added, removed or re-measured: what `heights` reads changed. */
26
+ version = 0;
27
+ /**
28
+ * Chunks over `pool`, for the InstancedLod sorting as row `row`, whose instances `bounds` bounds in the InstancedLod's space; `reach` tells how far from an
29
+ * instance's origin, in its space, every level and its sway reach, and `levelAt` is what a chunk's getLevelAt asks.
30
+ */
31
+ constructor(pool, row, bounds, reach, levelAt) {
32
+ this.pool = pool;
33
+ this.row = row;
34
+ this.bounds = bounds;
35
+ this.reach = reach;
36
+ this.levelAt = levelAt;
37
+ }
38
+ get size() {
39
+ return this.held.size;
40
+ }
41
+ /** The chunks, in the order they were added. */
42
+ keys() {
43
+ return this.held.keys();
44
+ }
45
+ /** The pool slots of the chunks. */
46
+ slots() {
47
+ return [...this.held.values()].map(({ slot }) => slot);
48
+ }
49
+ /** The chunks whose instances the CPU holds. */
50
+ cpu() {
51
+ return [...this.held].flatMap(([chunk, { state }]) => (state.gpu ? [] : [chunk]));
52
+ }
53
+ /**
54
+ * What makes chunks of their own with every chunk's instances, their attributes copied (see `InstancedLod.copy`). A
55
+ * GPU chunk cannot be copied: its instances live on the GPU.
56
+ */
57
+ copies() {
58
+ const cpu = this.cpu();
59
+ if (cpu.length !== this.size)
60
+ throw new Error("InstancedLod.copy: a GPU chunk's instances live on the GPU and cannot be copied");
61
+ return cpu.map(({ instanceMatrix, instanceColor, start, count }) => ({
62
+ instanceMatrix: copyOf(instanceMatrix),
63
+ instanceColor: instanceColor ? copyOf(instanceColor) : undefined,
64
+ start,
65
+ count,
66
+ }));
67
+ }
68
+ /** Hold `parameters`' instances as a chunk, copied into the pool at its next run; `bound` bounds it. */
69
+ add(parameters) {
70
+ const gpu = isStorageInstanced(parameters.instanceMatrix);
71
+ const state = { gpu, originBox: new Box3(), minScale: 0, maxScale: 0, boundingBox: new Box3(), levelAt: null };
72
+ const chunk = new InstancedLodChunk(parameters, state);
73
+ const { instanceMatrix, instanceColor, instanceCount } = chunk;
74
+ const attributes = gpu
75
+ ? // A storage attribute's RGB is padded to four floats.
76
+ { matrices: onGpu(instanceMatrix), colors: instanceColor && { attribute: onGpu(instanceColor), stride: 4 }, counts: instanceCount }
77
+ : {
78
+ matrices: this.mirror(instanceMatrix, chunk).attribute,
79
+ colors: instanceColor && { attribute: this.mirror(instanceColor, chunk).attribute, stride: 3 },
80
+ counts: null,
81
+ };
82
+ const slot = this.pool.add({ attributes, start: chunk.start, count: chunk.count, countIndex: chunk.instanceCountIndex, row: this.row });
83
+ state.levelAt = (index, camera) => this.levelAt(chunk, index, camera);
84
+ this.held.set(chunk, { slot, state });
85
+ this.version++;
86
+ return chunk;
87
+ }
88
+ /** Let go of `chunk`; its pages return to the pool at its next run. */
89
+ remove(chunk) {
90
+ const held = this.held.get(chunk);
91
+ if (!held)
92
+ throw new Error("InstancedLod: the chunk is not one of its chunks");
93
+ this.pool.remove(held.slot);
94
+ held.state.levelAt = null;
95
+ this.held.delete(chunk);
96
+ this.version++;
97
+ for (const attribute of [chunk.instanceMatrix, chunk.instanceColor]) {
98
+ const shared = attribute && this.mirrors.get(attribute);
99
+ if (!shared)
100
+ continue;
101
+ shared.users.delete(chunk);
102
+ if (shared.users.size > 0)
103
+ continue;
104
+ shared.mirror.dispose();
105
+ this.mirrors.delete(shared.mirror.source);
106
+ }
107
+ }
108
+ /**
109
+ * Take in the CPU attributes' edits, those whose versions moved, for every chunk reading them: re-measured, and
110
+ * copied into the pool again at its next run. Whether any changed; `bound` bounds them.
111
+ */
112
+ refresh() {
113
+ const changed = new Set();
114
+ for (const { mirror, users } of this.mirrors.values()) {
115
+ if (!mirror.refresh())
116
+ continue;
117
+ for (const chunk of users) {
118
+ if (chunk.instanceMatrix === mirror.source)
119
+ measureChunk(chunk, this.heldOf(chunk).state);
120
+ changed.add(chunk);
121
+ }
122
+ }
123
+ for (const chunk of changed)
124
+ this.pool.change(this.heldOf(chunk).slot);
125
+ if (changed.size > 0)
126
+ this.version++;
127
+ return changed.size > 0;
128
+ }
129
+ /** Bound every chunk, its box (see `InstancedLodChunk.boundingBox`), and all of them, survivors grown by up to `grow`. */
130
+ bound(grow) {
131
+ const { sphere, box } = this.bounds;
132
+ const reach = this.reach();
133
+ box.makeEmpty();
134
+ for (const { state } of this.held.values()) {
135
+ if (state.originBox.isEmpty()) {
136
+ state.boundingBox.makeEmpty();
137
+ continue;
138
+ }
139
+ state.boundingBox.copy(state.originBox).expandByScalar(reach * state.maxScale);
140
+ box.union(grown.copy(state.originBox).expandByScalar(reach * state.maxScale * grow));
141
+ }
142
+ if (box.isEmpty())
143
+ sphere.makeEmpty();
144
+ else
145
+ box.getBoundingSphere(sphere);
146
+ }
147
+ /**
148
+ * The heights on a screen of `scale` from `eye`, both in the InstancedLod's space, that each chunk's instances can
149
+ * have, `source` an instance's source sphere: its shortest instance at its farthest, its tallest at its nearest.
150
+ */
151
+ *heights(source, eye, scale, ortho, cull) {
152
+ const grow = cull?.survivors ? MAX_SURVIVOR_SCALE : 1;
153
+ const diameter = 2 * source.radius * scale;
154
+ for (const { state } of this.held.values()) {
155
+ const { originBox, minScale, maxScale } = state;
156
+ if (originBox.isEmpty() || maxScale === 0)
157
+ continue;
158
+ if (cull && originBox.distanceToPoint(cull.eye) >= cull.far)
159
+ continue;
160
+ const shortest = diameter * minScale;
161
+ const tallest = diameter * maxScale * grow;
162
+ if (ortho) {
163
+ yield [shortest, tallest];
164
+ continue;
165
+ }
166
+ // An instance's centre lies this far from its origin.
167
+ const offset = source.center.length() * maxScale * grow;
168
+ const near = Math.max(originBox.distanceToPoint(eye) - offset, 1e-6);
169
+ const far = farthest(originBox, eye) + offset;
170
+ yield [shortest / far, tallest / near];
171
+ }
172
+ }
173
+ /** Free the chunks' slots and release the mirrors; the chunks no longer find their levels. */
174
+ dispose() {
175
+ for (const { slot, state } of this.held.values()) {
176
+ this.pool.remove(slot);
177
+ state.levelAt = null;
178
+ }
179
+ this.held.clear();
180
+ this.version++;
181
+ for (const { mirror } of this.mirrors.values())
182
+ mirror.dispose();
183
+ this.mirrors.clear();
184
+ }
185
+ /** The mirror of `attribute`, which `chunk` reads too. */
186
+ mirror(attribute, chunk) {
187
+ const shared = this.mirrors.get(attribute) ?? { mirror: new Mirror(attribute), users: new Set() };
188
+ this.mirrors.set(attribute, shared);
189
+ shared.users.add(chunk);
190
+ return shared.mirror;
191
+ }
192
+ heldOf(chunk) {
193
+ const held = this.held.get(chunk);
194
+ if (!held)
195
+ throw new Error("InstancedLod: a mirror's chunk is not one of its chunks");
196
+ return held;
197
+ }
198
+ }
199
+ /** The distance from `point` to the farthest point of `box`. */
200
+ function farthest(box, point) {
201
+ const { min, max } = box;
202
+ return Math.hypot(Math.max(Math.abs(point.x - min.x), Math.abs(point.x - max.x)), Math.max(Math.abs(point.y - min.y), Math.abs(point.y - max.y)), Math.max(Math.abs(point.z - min.z), Math.abs(point.z - max.z)));
203
+ }
204
+ /** A CPU attribute of its own with `attribute`'s instances. */
205
+ function copyOf(attribute) {
206
+ return new InstancedBufferAttribute(attribute.array.slice(), attribute.itemSize);
207
+ }
208
+ //# sourceMappingURL=chunks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunks.js","sourceRoot":"","sources":["../../src/instanced/chunks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { Matrix4, Vector3, type Camera } from "three/webgpu";
2
+ /**
3
+ * How an InstancedLod thins its instances out with distance from `camera`, in every camera, as Fog does: every instance
4
+ * draws up to `near` from it, none from `far` on, and in between a share falling linearly, chosen by a hash of each
5
+ * instance's origin (its matrix's translation), the same on the CPU and the GPU. An instance whose translation changes
6
+ * rolls a new value: it may appear or vanish as it moves. With `scaleSurvivors`, the instances drawn grow by 1/√share,
7
+ * up to `MAX_SURVIVOR_SCALE` (8), so a thinned field stays about as covered.
8
+ */
9
+ export interface CullDistance {
10
+ camera: Camera;
11
+ near: number;
12
+ far: number;
13
+ scaleSurvivors?: boolean;
14
+ }
15
+ /** cullDistance in the InstancedLod's space. */
16
+ export interface Cull {
17
+ eye: Vector3;
18
+ near: number;
19
+ far: number;
20
+ survivors: boolean;
21
+ }
22
+ /**
23
+ * `cullDistance`, checked, in the space of `space`, an InstancedLod's world matrix, written into `target`; null for
24
+ * none. Nothing holds on to what it answers past a sort: the sort and its keys copy its values.
25
+ */
26
+ export declare function cullIn(cullDistance: CullDistance | null, space: Matrix4, target: Cull): Cull | null;
27
+ /** A Cull to write into (see `cullIn`). */
28
+ export declare const emptyCull: () => Cull;
@@ -0,0 +1,22 @@
1
+ import { Matrix4, Vector3 } from "three/webgpu";
2
+ const inverse = new Matrix4();
3
+ /**
4
+ * `cullDistance`, checked, in the space of `space`, an InstancedLod's world matrix, written into `target`; null for
5
+ * none. Nothing holds on to what it answers past a sort: the sort and its keys copy its values.
6
+ */
7
+ export function cullIn(cullDistance, space, target) {
8
+ if (!cullDistance)
9
+ return null;
10
+ const { camera, near, far, scaleSurvivors = false } = cullDistance;
11
+ if (!(Number.isFinite(near) && Number.isFinite(far) && near >= 0 && far > near))
12
+ throw new RangeError(`InstancedLod: cullDistance needs 0 <= near < far, both finite, got ${near} and ${far}`);
13
+ const scale = space.getMaxScaleOnAxis();
14
+ target.eye.setFromMatrixPosition(camera.matrixWorld).applyMatrix4(inverse.copy(space).invert());
15
+ target.near = near / scale;
16
+ target.far = far / scale;
17
+ target.survivors = scaleSurvivors;
18
+ return target;
19
+ }
20
+ /** A Cull to write into (see `cullIn`). */
21
+ export const emptyCull = () => ({ eye: new Vector3(), near: 0, far: 0, survivors: false });
22
+ //# sourceMappingURL=cull.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cull.js","sourceRoot":"","sources":["../../src/instanced/cull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAe,MAAM,cAAc,CAAC;AAwB7D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,YAAiC,EAAE,KAAc,EAAE,MAAY;IACpF,IAAI,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,cAAc,GAAG,KAAK,EAAE,GAAG,YAAY,CAAC;IACnE,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,GAAG,GAAG,IAAI,CAAC;QAC7E,MAAM,IAAI,UAAU,CAAC,sEAAsE,IAAI,QAAQ,GAAG,EAAE,CAAC,CAAC;IAChH,MAAM,KAAK,GAAG,KAAK,CAAC,iBAAiB,EAAE,CAAC;IACxC,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAChG,MAAM,CAAC,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;IAC3B,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,KAAK,CAAC;IACzB,MAAM,CAAC,SAAS,GAAG,cAAc,CAAC;IAClC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,2CAA2C;AAC3C,MAAM,CAAC,MAAM,SAAS,GAAG,GAAS,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC"}
@@ -1,116 +1,120 @@
1
- import { type Color, Matrix4, Object3D, Sphere, type Camera, type Intersection, type Raycaster } from "three/webgpu";
2
- import { type LodLevel } from "../levels.js";
3
- import { type LevelsEventMap } from "../lazy.js";
4
- import { WIND_BOUNDS } from "../wind/hooks.js";
1
+ import { Object3D, type Camera, type Intersection, type LoadingManager, type Raycaster } from "three/webgpu";
2
+ import { type LodLevel, type ThresholdedLevel } from "../levels/index.js";
3
+ import { type LodEventMap } from "../levels/manager.js";
4
+ import type { LodGpu } from "../gpu.js";
5
+ import { type LodOptions } from "../lod.js";
6
+ import { WIND } from "../wind/hooks.js";
7
+ import type { InstancedLodChunk, InstancedLodChunkParameters } from "./chunk.js";
8
+ import { type CullDistance } from "./cull.js";
9
+ /** How an InstancedLod is made. */
10
+ export interface InstancedLodOptions extends LodOptions {
11
+ /**
12
+ * The most instances it draws for a camera, over all its chunks, CPU and GPU chunks alike: 16384 by default. Its
13
+ * lists take 8 bytes per level that draws something per instance (about 400 KB with the defaults and three levels),
14
+ * and every camera that draws any InstancedLod of its LodGpu, each shadow map's included, holds the lists of every
15
+ * InstancedLod of that LodGpu. A camera that draws only a few InstancedLods, such as a minimap's or a reflection's,
16
+ * is bounded by giving those a LodGpu of their own. Chunks that together outgrow it are reported (see `error`),
17
+ * naming it as the limit to raise. Its LodGpu's pool holds the instances themselves (see `LodGpuOptions`).
18
+ */
19
+ maxInstanceCount?: number;
20
+ }
5
21
  /**
6
- * `count` copies of one object with levels of detail, each switched by its own height on
7
- * screen: `Lod` for instances. The GPU sorts the instances into levels once per view
8
- * (see select.ts) and every mesh of a level draws the instances it holds in one indirect
9
- * draw; an instance near a switch is in both neighbours and they split its pixels with
10
- * the dither. Thresholds, `forceLevel`, `Lod.quality`, `Lod.debug` and shadows work as
11
- * for `Lod`; nothing of an instance is drawn into a directional light's shadow map whose
12
- * texels are wider than it. Each level is culled by the crowd's bounds, tightened for
13
- * finer levels to the region near the camera where their instances can draw.
22
+ * Independently drawn copies of one object, sorted into indirect draws per camera on the GPU. Instances arrive and
23
+ * leave in chunks (see `addChunk`), from the CPU or written by the app's GPU passes; `cullDistance` thins them out with
24
+ * distance. Thresholds, fades, loading and global settings follow Lod: each instance draws what levelsToDraw gives for
25
+ * its height. Each camera draws only the instances in its frustum, and each shadow map is a camera of its own: it draws
26
+ * the casters in its frustum, each at the level its texels resolve, as an orthographic camera would (an instance
27
+ * smaller than a texel casts nothing). Instance matrices may scale arbitrarily; the InstancedLod's own transform and its
28
+ * parents should scale uniformly. Scale 0 draws nothing.
14
29
  *
15
- * Instance matrices are model transforms of the object, as for an InstancedMesh; set
16
- * them with `setMatrixAt`, and instance colours with `setColorAt`. An instance at scale 0
17
- * draws nothing. Its own transform (and its parents') should scale uniformly; instances
18
- * may scale any way.
30
+ * Level templates are cloned, then their meshes are instanced; it sets each level mesh's `visible` per camera, so hide
31
+ * the InstancedLod itself, never its level meshes. Skinned meshes, InstancedMeshes (except ImpostorMesh)
32
+ * and nested Lods are unsupported. For external detail, leave level 0 empty and draw the instances that
33
+ * `chunk.getLevelAt` reports there.
19
34
  *
20
- * Levels are templates, read when it is built: their meshes are drawn instanced, not
21
- * added to the scene. They cannot contain skinned meshes, InstancedMeshes (other than an
22
- * ImpostorMesh) or nested Lods. To build a hierarchy on top, leave level 0 empty (see
23
- * `Lod`) and draw the detail of the instances `levelOf` reports at level 0 yourself.
35
+ * Every level mesh's `geometry.boundingBox` and `boundingSphere` bound all its instances, not one, so
36
+ * `new Box3().setFromObject(lod)` bounds them once a level has loaded; with `precise` it walks a level's vertices once,
37
+ * at no instance, as it cannot see them. Measure one instance by a level's `object`, scaled by its matrix.
38
+ *
39
+ * Instances live in its LodGpu's pool, and every InstancedLod of a LodGpu sorts for a camera in one compute call.
40
+ * Requires WebGPU `indirect-first-instance`. Sequential cameras are supported; a nested render with a camera that the
41
+ * outer render also draws with replaces that camera's instance lists, so exclude this InstancedLod from it with camera
42
+ * layers.
24
43
  */
25
- export declare class InstancedLod extends Object3D<LevelsEventMap> {
44
+ export declare class InstancedLod extends Object3D<LodEventMap> {
45
+ private readonly gpu;
26
46
  readonly isLOD = true;
27
47
  readonly isInstancedLod = true;
28
48
  /** Let the renderer call `update` with its camera every frame. */
29
49
  autoUpdate: boolean;
30
- /** Draw only this level for every instance, without fades. */
50
+ /** Draw only this level, without fades, once the coarsest level that draws something has loaded. */
31
51
  forceLevel: number | null;
32
- readonly levels: readonly LodLevel[];
33
- readonly count: number;
34
- private readonly entries;
35
- /** Per level, the meshes drawing it. */
36
- private readonly meshes;
37
- private readonly probes;
38
- private selection;
39
- private fallback;
40
- private readonly installed;
52
+ /** The levels, each `object` the template its level meshes are made from, once there is one (never in the scene). */
53
+ readonly levels: ThresholdedLevel[];
54
+ /** Thins the instances out with distance from a camera, in every camera; null draws them at any distance. */
55
+ cullDistance: CullDistance | null;
56
+ /** The levels as they were given, which a copy is made from. */
57
+ private inputs;
58
+ /** What it is made of for its levels and sizes, which a copy makes anew. */
59
+ private built;
41
60
  private disposed;
42
- /** Instance matrices, 16 floats each: the selection uploads them from here. */
43
- private readonly matrices;
44
- /** Instance colours, 4 floats each, once `setColorAt` was called. */
45
- private colors;
46
- /** Each instance's bounding sphere, centre and radius, in the InstancedLod's space. */
47
- private readonly spheres;
48
- /** Bounding sphere of the source in an instance's space. */
49
- private readonly sphere;
50
- /** Every placed level, kept separate from the source sphere used for LOD selection. */
51
- private readonly envelope;
52
- private readonly rest;
53
- /** Around every instance; each level may use tighter bounds. */
54
- readonly bounds: Sphere;
55
- /** Per level, what its meshes are culled by: `bounds`, or less where its instances must be near the camera. */
56
- private readonly reaches;
57
- /** Logical demand at the initial default viewport, separate from first-draw visibility. */
58
- private readonly demand;
59
- /** Source-radius padding for the shadow caster cutoff; culling pads every level separately. */
60
- private padding;
61
- private readonly matrixChanges;
62
- private readonly colorChanges;
63
- private blocks;
64
- private readonly last;
65
- /** `levels[0]` is the source. Empty only as the target of `copy`. */
66
- constructor(levels?: Object3D[], count?: number);
67
- private build;
68
- /** Install ready atlas templates atomically before selecting this view. */
69
- private refresh;
70
- /** Bound what the level meshes draw, including template placement and impostor boxes. */
71
- private boundLevels;
72
- /** Material group `group` of `template` drawn for every instance in `level`'s slots, from indirect draw arguments at byte `offset`. */
73
- private instance;
74
- private bind;
75
- setMatrixAt(index: number, matrix: Matrix4): void;
76
- getMatrixAt(index: number, matrix: Matrix4): Matrix4;
77
- /** Tint instance `index` by `color`, as InstancedMesh.setColorAt does, in every level. */
78
- setColorAt(index: number, color: Color): void;
79
- /** Instance `index`'s colour: white unless set. */
80
- getColorAt(index: number, color: Color): Color;
81
- /** Carry `colors` with the instances from now on: every level's meshes draw them. */
82
- private useColors;
61
+ /** Around every instance, survivors grown: what every level mesh is culled and boxed by. */
62
+ private readonly bounds;
63
+ /** What `cullIn` writes cullDistance into, in this InstancedLod's space. */
64
+ private readonly cull;
65
+ /**
66
+ * `levels[0]` is the source. Empty only as the target of `copy`. It holds no instances until chunks are added. `gpu`
67
+ * is what it shares with every Lod drawing with its renderer.
68
+ */
69
+ constructor(levels: readonly LodLevel[], gpu: LodGpu, options?: InstancedLodOptions);
70
+ get pending(): boolean;
71
+ get error(): Error | undefined;
72
+ /** Where the item of levels a camera misses goes (see `LodOptions.manager`). */
73
+ get manager(): LoadingManager;
74
+ set manager(manager: LoadingManager | undefined);
75
+ /** Its chunks, in the order they were added. */
76
+ get chunks(): Iterable<InstancedLodChunk>;
77
+ /** What this InstancedLod is made of for `inputs` and `maxInstanceCount`: its levels, their meshes and their loading. */
78
+ private init;
83
79
  /**
84
- * The finest level instance `index` drew in the last update, or null before the first
85
- * (or at scale 0). Inside a fade the next coarser level draws too.
80
+ * Add `parameters`' instances as one chunk, from the CPU or the GPU (see `InstancedLodChunkParameters`). The next
81
+ * render that updates this InstancedLod copies them into its pages. Its item (see `LodOptions.manager`) stays held
82
+ * until the GPU shows every chunk copied; a chunk the pool lacks pages for draws the instances it got until it is
83
+ * removed, and is this InstancedLod's error (see `error`).
86
84
  */
87
- levelOf(index: number): number | null;
88
- private check;
89
- /** Source radius padded for the level shaders' shadow caster cutoff. */
90
- private get drawRadius();
91
- [WIND_BOUNDS](padding: number, slope: number, baseY: number): void;
92
- /** Measure only changed matrices; matrix and colour uploads have separate ranges. */
93
- private measure;
94
- private measureChanges;
95
- /** Sort the instances into levels for `camera`; three's renderer calls this itself while `autoUpdate`. */
85
+ addChunk(parameters: InstancedLodChunkParameters): InstancedLodChunk;
86
+ /** Remove `chunk`'s instances; its pages return to the pool in the next render. */
87
+ removeChunk(chunk: InstancedLodChunk): void;
88
+ /** Bound every chunk's instances, survivors grown. */
89
+ private measureBounds;
90
+ [WIND](padding: number, slope: number, baseY: number): void;
91
+ /** Sort the instances into level lists for `camera`, a camera's or a shadow map's, and load the levels they need. What fails is reported (see `error`). */
96
92
  update(camera: Camera): void;
97
- /** Only levels whose conservative bounds contain a possible selected instance. */
98
- private showLevels;
93
+ /** Sort for `camera`, a shadow map's when `shadow`. */
94
+ private sort;
95
+ /** `camera` in this InstancedLod's space (see `localCamera`). */
96
+ private localCamera;
97
+ /** Draw survivors' scaled matrices, or the pool's again. */
98
+ private scaleSurvivors;
99
+ /** The level instance `index` of `chunk` draws most of its pixels with for `camera` (see `InstancedLodChunk.getLevelAt`). */
100
+ private levelAt;
99
101
  /**
100
- * Hits every instance's source level, with `instanceId` set; `object` is this
101
- * InstancedLod. Meshes of the source on layers the raycaster does not test are skipped.
102
+ * Hits every instance of its CPU chunks on the source level, with `instanceId` and `chunk` set (see
103
+ * `InstancedLodIntersection`); `object` is this InstancedLod. A GPU chunk's instances the CPU cannot see, and meshes
104
+ * of the source on layers the raycaster does not test, are not hit.
102
105
  */
103
106
  raycast(raycaster: Raycaster, intersects: Intersection[]): boolean;
104
107
  /**
105
- * Copies `source`'s levels, instances and settings into this empty InstancedLod of the
106
- * same count (it throws otherwise); the copy shares geometry and textures with `source`.
108
+ * Copies `source`'s levels, CPU chunks and settings into this empty InstancedLod, one without levels or chunks (it
109
+ * throws otherwise); the copy shares geometry and textures with `source`, and its chunks hold copies of the source's
110
+ * attributes. A GPU chunk cannot be copied: its instances live on the GPU.
107
111
  */
108
112
  copy(source: InstancedLod): this;
109
113
  clone(): this;
110
114
  /**
111
- * Frees every level, the source included, and the instanced meshes. Clones share
112
- * geometry and textures, so dispose only once no clone draws any more.
115
+ * Release its buffers and what it made of its levels, once nothing it prepares or compiles still uses them. Objects
116
+ * you give or load, chunk attributes among them, are yours to dispose; LodLoader's are freed when the last Lod
117
+ * holding them is disposed (see `LodLevel.hold`).
113
118
  */
114
119
  dispose(): void;
115
- private clearDraws;
116
120
  }