@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,128 @@
1
+ import { Box3, Vector3 } from "three/webgpu";
2
+ import { MeshoptSimplifier } from "meshoptimizer";
3
+ import { at } from "../at.js";
4
+ import { triangleArea } from "../source/surface.js";
5
+ import { isTexture } from "../three.js";
6
+ // Simplifying cards: the alpha-tested quads foliage draws (needles, leaves), which simplify decimates card by card rather
7
+ // than collapsing their edges.
8
+ /** Per material of `mesh`, whether it alpha-tests a texture, so draws cards. */
9
+ export function cardMaterials(mesh) {
10
+ const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
11
+ return materials.map((m) => m.alphaTest > 0 && ["map" in m && m.map, "alphaMap" in m && m.alphaMap].some(isTexture));
12
+ }
13
+ /**
14
+ * About `ratio` of the cards (connected parts, touching where vertices share a position)
15
+ * of the triangles `indices`, spread evenly over them by meshopt's point simplifier on the
16
+ * cards' centres. Each picked card is enlarged about its centre, in `positions`, so the picked
17
+ * cards cover as much area as all did; a card larger than most grows only as far as a
18
+ * card of the median size does, or a long spray would reach far out of the crown, and no
19
+ * card grows past the bounds of all, which a level must stay inside.
20
+ * Edge collapse would instead shrink and warp each card, and so cut most of an
21
+ * alpha-tested texture (needles, leaves) away.
22
+ */
23
+ export function decimateCards(indices, positions, ratio) {
24
+ const { card, count } = cards(indices, positions);
25
+ const corner = (t, k) => indices[t * 3 + k] ?? 0;
26
+ const point = new Vector3();
27
+ const area = new Float64Array(count);
28
+ const centre = Array.from({ length: count }, () => new Vector3());
29
+ const corners = new Uint32Array(count);
30
+ card.forEach((c, t) => {
31
+ area[c] = (area[c] ?? 0) + triangleArea(positions, 3, indices, t * 3);
32
+ for (let k = 0; k < 3; k++)
33
+ at(centre, c).add(point.fromArray(positions, corner(t, k) * 3));
34
+ corners[c] = (corners[c] ?? 0) + 3;
35
+ });
36
+ centre.forEach((p, c) => p.divideScalar(corners[c] ?? 1));
37
+ const radius = new Float64Array(count);
38
+ const box = Array.from({ length: count }, () => new Box3());
39
+ const bounds = new Box3();
40
+ card.forEach((c, t) => {
41
+ for (let k = 0; k < 3; k++) {
42
+ point.fromArray(positions, corner(t, k) * 3);
43
+ radius[c] = Math.max(radius[c] ?? 0, point.distanceTo(at(centre, c)));
44
+ at(box, c).expandByPoint(point);
45
+ bounds.expandByPoint(point);
46
+ }
47
+ });
48
+ const median = Float64Array.from(radius).sort()[count >> 1] ?? 0;
49
+ // The most each card can grow about its centre and stay inside `bounds`.
50
+ const fit = centre.map((p, c) => {
51
+ const { min, max } = at(box, c);
52
+ let most = Infinity;
53
+ for (const axis of ["x", "y", "z"]) {
54
+ if (max[axis] > p[axis])
55
+ most = Math.min(most, (bounds.max[axis] - p[axis]) / (max[axis] - p[axis]));
56
+ if (min[axis] < p[axis])
57
+ most = Math.min(most, (p[axis] - bounds.min[axis]) / (p[axis] - min[axis]));
58
+ }
59
+ return Math.max(1, most);
60
+ });
61
+ const picked = new Uint8Array(count);
62
+ const target = Math.max(1, Math.round(count * ratio));
63
+ const points = Float32Array.from(centre.flatMap((p) => p.toArray()));
64
+ for (const c of target < count ? MeshoptSimplifier.simplifyPoints(points, 3, target) : picked.keys())
65
+ picked[c] = 1;
66
+ // `scale` enlarges a median card; bisect for the one at which the picked cards cover what all did.
67
+ const grow = (c, scale) => Math.min(scale, fit[c] ?? 1, Math.max(1, (scale * median) / Math.max(radius[c] ?? 0, 1e-30)));
68
+ const covered = (scale) => area.reduce((sum, a, c) => sum + (picked[c] ? a * grow(c, scale) ** 2 : 0), 0);
69
+ const total = area.reduce((sum, a) => sum + a, 0);
70
+ let [low, high] = [1, 1];
71
+ while (covered(high) < total && high < 1e6)
72
+ high *= 2;
73
+ for (let i = 0; i < 40; i++) {
74
+ const mid = (low + high) / 2;
75
+ if (covered(mid) < total)
76
+ low = mid;
77
+ else
78
+ high = mid;
79
+ }
80
+ const out = [];
81
+ const moved = new Uint8Array(positions.length / 3);
82
+ card.forEach((c, t) => {
83
+ if (!picked[c])
84
+ return;
85
+ const p = at(centre, c);
86
+ for (let k = 0; k < 3; k++) {
87
+ const v = corner(t, k);
88
+ out.push(v);
89
+ if (moved[v])
90
+ continue;
91
+ moved[v] = 1;
92
+ point
93
+ .fromArray(positions, v * 3)
94
+ .sub(p)
95
+ .multiplyScalar(grow(c, high))
96
+ .add(p)
97
+ .toArray(positions, v * 3);
98
+ }
99
+ });
100
+ return Uint32Array.from(out);
101
+ }
102
+ /** The card of each triangle, numbered 0..count-1. */
103
+ function cards(indices, positions) {
104
+ const remap = MeshoptSimplifier.generatePositionRemap(positions, 3);
105
+ const parent = Uint32Array.from(remap.keys());
106
+ const root = (vertex) => {
107
+ let v = remap[vertex] ?? vertex;
108
+ while (parent[v] !== v)
109
+ v = parent[v] = parent[parent[v] ?? v] ?? v;
110
+ return v;
111
+ };
112
+ for (let i = 0; i < indices.length; i += 3) {
113
+ const a = root(indices[i] ?? 0);
114
+ parent[root(indices[i + 1] ?? 0)] = a;
115
+ parent[root(indices[i + 2] ?? 0)] = a;
116
+ }
117
+ const number = new Map();
118
+ const card = new Uint32Array(indices.length / 3);
119
+ for (let t = 0; t < card.length; t++) {
120
+ const r = root(indices[t * 3] ?? 0);
121
+ let c = number.get(r);
122
+ if (c === undefined)
123
+ number.set(r, (c = number.size));
124
+ card[t] = c;
125
+ }
126
+ return { card, count: number.size };
127
+ }
128
+ //# sourceMappingURL=cards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cards.js","sourceRoot":"","sources":["../../src/simplify/cards.ts"],"names":[],"mappings":"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"}
@@ -1,19 +1,22 @@
1
1
  import { type Object3D } from "three/webgpu";
2
2
  export interface SimplifyOptions {
3
- /** share of each mesh's triangles to keep, in (0, 1]; default 0.5 */
3
+ /** share of each mesh's triangles that remains, in (0, 1]; default 0.5 */
4
4
  ratio?: number;
5
5
  }
6
6
  /**
7
7
  * A copy of `object` with the geometry of every mesh drawn at full detail decimated by
8
8
  * meshoptimizer to about `ratio` of its triangles: of a nested LOD only level 0 (its other
9
- * levels are kept), of an InstancedMesh the geometry its instances share. Materials (and
9
+ * levels stay as they are), of an InstancedMesh the geometry its instances share. Materials (and
10
10
  * so textures) are the originals, shared with `object`. Meshes that share a geometry
11
11
  * share the simplified one. Morph targets are dropped. ImpostorMeshes and hidden meshes
12
- * are kept as they are. Skinned meshes and InstancedLods are refused: simplify an
12
+ * stay as they are. Skinned meshes and InstancedLods are refused: simplify an
13
13
  * InstancedLod's source and build a new InstancedLod of it.
14
14
  *
15
- * Per material group it keeps UV and normal seams; if that cannot reach the target it
15
+ * Per material group it preserves UV and normal seams; if that cannot reach the target it
16
16
  * lets seams collapse, and as a last resort ignores topology (meshopt's sloppy mode).
17
+ * A group drawn with an alpha-tested texture (foliage cards) is decimated card by card
18
+ * instead: about `ratio` of its cards remain, whole, spread evenly and enlarged to cover
19
+ * what all covered (see `decimateCards`).
17
20
  *
18
21
  * How far the copy's surface is from `object`'s (the 99.9th percentile of the distance
19
22
  * between the two, by area, over the parts seen from outside; ImpostorMeshes left out)
@@ -1,23 +1,27 @@
1
1
  import { BufferAttribute, BufferGeometry } from "three/webgpu";
2
2
  import { mergeVertices } from "three/addons/utils/BufferGeometryUtils.js";
3
3
  import { MeshoptSimplifier } from "meshoptimizer";
4
- import { detailed } from "./bounds.js";
5
- import { recordError } from "./levels.js";
6
- import { measureError } from "./source/error.js";
7
- import { readSource } from "./source/source.js";
8
- import { merge } from "./source/surface.js";
9
- import { isImpostorMesh, isInstancedLod, isMesh, isSkinnedMesh } from "./three.js";
4
+ import { recordDeviation } from "../levels/index.js";
5
+ import { detailed } from "../source/detail.js";
6
+ import { measureDeviation } from "../source/deviation.js";
7
+ import { readSource } from "../source/source.js";
8
+ import { merge } from "../source/surface.js";
9
+ import { isImpostorMesh, isInstancedLod, isMesh, isSkinnedMesh } from "../three.js";
10
+ import { cardMaterials, decimateCards } from "./cards.js";
10
11
  /**
11
12
  * A copy of `object` with the geometry of every mesh drawn at full detail decimated by
12
13
  * meshoptimizer to about `ratio` of its triangles: of a nested LOD only level 0 (its other
13
- * levels are kept), of an InstancedMesh the geometry its instances share. Materials (and
14
+ * levels stay as they are), of an InstancedMesh the geometry its instances share. Materials (and
14
15
  * so textures) are the originals, shared with `object`. Meshes that share a geometry
15
16
  * share the simplified one. Morph targets are dropped. ImpostorMeshes and hidden meshes
16
- * are kept as they are. Skinned meshes and InstancedLods are refused: simplify an
17
+ * stay as they are. Skinned meshes and InstancedLods are refused: simplify an
17
18
  * InstancedLod's source and build a new InstancedLod of it.
18
19
  *
19
- * Per material group it keeps UV and normal seams; if that cannot reach the target it
20
+ * Per material group it preserves UV and normal seams; if that cannot reach the target it
20
21
  * lets seams collapse, and as a last resort ignores topology (meshopt's sloppy mode).
22
+ * A group drawn with an alpha-tested texture (foliage cards) is decimated card by card
23
+ * instead: about `ratio` of its cards remain, whole, spread evenly and enlarged to cover
24
+ * what all covered (see `decimateCards`).
21
25
  *
22
26
  * How far the copy's surface is from `object`'s (the 99.9th percentile of the distance
23
27
  * between the two, by area, over the parts seen from outside; ImpostorMeshes left out)
@@ -25,7 +29,7 @@ import { isImpostorMesh, isInstancedLod, isMesh, isSkinnedMesh } from "./three.j
25
29
  */
26
30
  export async function simplify(object, options = {}) {
27
31
  const copy = await decimate(object, options.ratio ?? 0.5);
28
- recordError(copy, measureError(readSource(object, "simplify", "measure"), merge(copy, "simplify")).error);
32
+ recordDeviation(copy, measureDeviation(readSource(object, "simplify", "measure"), merge(copy, "simplify")).deviation);
29
33
  return copy;
30
34
  }
31
35
  /** A copy of `object` decimated to `ratio`, as `simplify` makes it, without measuring it. */
@@ -33,7 +37,7 @@ export async function decimate(object, ratio) {
33
37
  if (!(ratio > 0 && ratio <= 1))
34
38
  throw new Error(`simplify: ratio must be in (0, 1], got ${ratio}`);
35
39
  await MeshoptSimplifier.ready;
36
- // clone() also visits hidden children, whose crowd allocations must never be
40
+ // clone() also visits hidden children, whose InstancedLod allocations must never be
37
41
  // created just to reject them (or skipped by the visible-detail walk below).
38
42
  object.traverse((node) => {
39
43
  if (isInstancedLod(node))
@@ -45,18 +49,23 @@ export async function decimate(object, ratio) {
45
49
  decimateTree(copy, ratio, new Map());
46
50
  return copy;
47
51
  }
48
- /** Decimate the meshes of `node` drawn at full detail; `done` maps each geometry to its simplified one. */
52
+ /**
53
+ * Decimate the meshes of `node` drawn at full detail; `done` maps each geometry, with
54
+ * which of its material indices are cards, to its simplified one.
55
+ */
49
56
  function decimateTree(node, ratio, done) {
50
57
  if (isMesh(node) && !isImpostorMesh(node)) {
51
- let geometry = done.get(node.geometry);
58
+ const cards = cardMaterials(node);
59
+ const key = `${node.geometry.uuid} ${cards.join()}`;
60
+ let geometry = done.get(key);
52
61
  if (!geometry)
53
- done.set(node.geometry, (geometry = simplifyGeometry(node.geometry, ratio)));
62
+ done.set(key, (geometry = simplifyGeometry(node.geometry, ratio, cards)));
54
63
  node.geometry = geometry;
55
64
  }
56
65
  for (const child of detailed(node))
57
66
  decimateTree(child, ratio, done);
58
67
  }
59
- function simplifyGeometry(source, ratio) {
68
+ function simplifyGeometry(source, ratio, cards) {
60
69
  const geometry = source.index ? source : mergeVertices(source);
61
70
  const index = geometry.index;
62
71
  if (!index)
@@ -65,12 +74,20 @@ function simplifyGeometry(source, ratio) {
65
74
  const { attributes, stride, weights } = simplifierAttributes(geometry);
66
75
  const groups = geometry.groups.length > 0 ? geometry.groups : [{ start: 0, count: index.count, materialIndex: 0 }];
67
76
  const parts = [];
77
+ let decimatedCards = false;
68
78
  for (const group of groups) {
69
79
  const indices = new Uint32Array(Math.min(group.count, index.count - group.start));
70
80
  for (let i = 0; i < indices.length; i++)
71
81
  indices[i] = index.getX(group.start + i);
72
- const [simplified] = simplifyIndices(indices, positions, attributes, stride, weights, Math.floor((indices.length / 3) * ratio) * 3);
73
- parts.push({ indices: simplified, materialIndex: group.materialIndex ?? 0 });
82
+ const materialIndex = group.materialIndex ?? 0;
83
+ // A single material draws every group.
84
+ const card = (cards.length === 1 ? cards[0] : cards[materialIndex]) ?? false;
85
+ if (card)
86
+ decimatedCards = true;
87
+ const simplified = card
88
+ ? decimateCards(indices, positions, ratio)
89
+ : simplifyIndices(indices, positions, attributes, stride, weights, Math.floor((indices.length / 3) * ratio) * 3)[0];
90
+ parts.push({ indices: simplified, materialIndex });
74
91
  }
75
92
  const all = new Uint32Array(parts.reduce((n, p) => n + p.indices.length, 0));
76
93
  const out = new BufferGeometry();
@@ -82,8 +99,11 @@ function simplifyGeometry(source, ratio) {
82
99
  offset += part.indices.length;
83
100
  }
84
101
  const [remap, unique] = MeshoptSimplifier.compactMesh(all); // rewrites `all` in place
85
- for (const [name, attribute] of Object.entries(geometry.attributes))
86
- out.setAttribute(name, compactAttribute(attribute, remap, unique));
102
+ for (const [name, attribute] of Object.entries(geometry.attributes)) {
103
+ // decimateCards moved the remaining cards' vertices, past the range a quantized position may hold.
104
+ const from = name === "position" && decimatedCards ? new BufferAttribute(positions, 3) : attribute;
105
+ out.setAttribute(name, compactAttribute(from, remap, unique));
106
+ }
87
107
  out.setIndex(new BufferAttribute(all, 1));
88
108
  out.computeBoundingBox();
89
109
  out.computeBoundingSphere();
@@ -98,7 +118,7 @@ function simplifyIndices(indices, positions, attributes, stride, weights, target
98
118
  if (reached(permissive[0]))
99
119
  return permissive;
100
120
  const sloppy = MeshoptSimplifier.simplifySloppy(indices, positions, 3, null, target, 1);
101
- // Sloppy can collapse a tiny target to nothing; then keep the permissive result.
121
+ // Sloppy can collapse a tiny target to nothing; then use the permissive result.
102
122
  return sloppy[0].length > 0 ? sloppy : permissive;
103
123
  }
104
124
  /** Normal (weight 0.5) and UV (weight 1) packed per vertex for simplifyWithAttributes. */
@@ -124,7 +144,7 @@ function simplifierAttributes(geometry) {
124
144
  }
125
145
  function compactAttribute(attribute, remap, unique) {
126
146
  const size = attribute.itemSize;
127
- // A slice keeps the array type, so normalized and integer attributes keep their encoding;
147
+ // A slice has the array's type, so normalized and integer attributes hold their encoding;
128
148
  // every element is written below (unique <= count, so it is long enough).
129
149
  const out = new BufferAttribute(attribute.array.slice(0, unique * size), size, attribute.normalized);
130
150
  for (let i = 0; i < remap.length; i++) {
@@ -145,4 +165,4 @@ function toFloat32(attribute) {
145
165
  }
146
166
  return out;
147
167
  }
148
- //# sourceMappingURL=simplify.js.map
168
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/simplify/index.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Box3, Matrix4, Sphere, Vector3, type Mesh, type Object3D } from "three/webgpu";
1
+ import { Box3, Matrix4, Vector3, type Mesh, type Object3D } from "three/webgpu";
2
2
  /**
3
3
  * Call `visit` with every mesh of `root` drawn at full detail, and the matrix that places
4
4
  * it in `root`'s own space (`root`'s own transform not applied): `root` itself and its
@@ -10,6 +10,8 @@ import { Box3, Matrix4, Sphere, Vector3, type Mesh, type Object3D } from "three/
10
10
  export declare function forEachMesh(root: Object3D, visit: (mesh: Mesh, placement: Matrix4) => void): void;
11
11
  /** The children of `node` drawn at full detail: of a LOD its level 0, whatever it shows, else the visible ones. */
12
12
  export declare function detailed(node: Object3D): Object3D[];
13
+ /** `node`'s matrix in its parent's space, up to date. */
14
+ export declare function local(node: Object3D): Matrix4;
13
15
  /** Show level 0 of every LOD under `root` and stop them switching: a bake sees full detail. */
14
16
  export declare function showDetail(root: Object3D): void;
15
17
  /**
@@ -18,16 +20,5 @@ export declare function showDetail(root: Object3D): void;
18
20
  * an ImpostorMesh. `visit` gets one reused vector.
19
21
  */
20
22
  export declare function forEachVertex(root: Object3D, visit: (p: Vector3) => void): void;
21
- /** Bounds of every vertex that draws at full detail, in `root`'s own space. */
23
+ /** Conservative full-detail bounds from cached geometry boxes and deferred metadata, in the root's space: what a bake measures. */
22
24
  export declare function boundingBox(root: Object3D): Box3;
23
- /** The centre and half diagonal of `boundingBox(root)`: an impostor baked from `root` has the same box. */
24
- export declare function boundingSphere(root: Object3D): Sphere;
25
- /**
26
- * The sphere fades measure for a Lod's levels (see `boundingSphere`): level 0's, or the
27
- * first level's that draws anything when level 0 draws nothing; `own` in that level's
28
- * own space, `placed` in its parent's (the Lod's). `who` names the caller in the error.
29
- */
30
- export declare function measureLevels(levels: readonly Object3D[], who: string): {
31
- own: Sphere;
32
- placed: Sphere;
33
- };
@@ -1,5 +1,5 @@
1
- import { Box3, Matrix4, Sphere, Vector3 } from "three/webgpu";
2
- import { isBatchedMesh, isImpostorMesh, isInstancedLod, isInstancedMesh, isLOD, isMesh } from "./three.js";
1
+ import { Box3, Matrix4, Vector3 } from "three/webgpu";
2
+ import { isBatchedMesh, isImpostorMesh, isInstancedLod, isInstancedMesh, isLOD, isMesh, isStorageInstanced } from "../three.js";
3
3
  // What an object is at full detail: its meshes, where they sit and the vertices they draw.
4
4
  /**
5
5
  * Call `visit` with every mesh of `root` drawn at full detail, and the matrix that places
@@ -20,8 +20,8 @@ function walk(node, placement, visit) {
20
20
  if (!source)
21
21
  return;
22
22
  const instance = new Matrix4();
23
- for (let i = 0; i < node.count; i++)
24
- walk(source, local(source).premultiply(node.getMatrixAt(i, instance)).premultiply(placement), visit);
23
+ for (const { chunk, index } of instancesOf(node))
24
+ walk(source, local(source).premultiply(chunk.getMatrixAt(index, instance)).premultiply(placement), visit);
25
25
  return;
26
26
  }
27
27
  if (isInstancedMesh(node) || isImpostorMesh(node)) {
@@ -38,11 +38,11 @@ function walk(node, placement, visit) {
38
38
  export function detailed(node) {
39
39
  if (!isLOD(node))
40
40
  return node.children.filter((child) => child.visible);
41
- const source = node.levels[0];
42
- return source ? [source.object] : [];
41
+ const source = node.levels[0]?.object;
42
+ return source ? [source] : [];
43
43
  }
44
44
  /** `node`'s matrix in its parent's space, up to date. */
45
- function local(node) {
45
+ export function local(node) {
46
46
  if (node.matrixAutoUpdate)
47
47
  node.updateMatrix();
48
48
  return node.matrix.clone();
@@ -55,7 +55,10 @@ export function showDetail(root) {
55
55
  }
56
56
  if (isLOD(root)) {
57
57
  root.autoUpdate = false;
58
- root.levels.forEach((level, i) => (level.object.visible = i === 0));
58
+ root.levels.forEach((level, i) => {
59
+ if (level.object)
60
+ level.object.visible = i === 0;
61
+ });
59
62
  }
60
63
  for (const child of detailed(root))
61
64
  showDetail(child);
@@ -94,34 +97,61 @@ export function forEachVertex(root, visit) {
94
97
  visit(mesh.getVertexPosition(i, point).applyMatrix4(placement));
95
98
  });
96
99
  }
97
- /** Bounds of every vertex that draws at full detail, in `root`'s own space. */
100
+ /** Conservative full-detail bounds from cached geometry boxes and deferred metadata, in the root's space: what a bake measures. */
98
101
  export function boundingBox(root) {
99
102
  const box = new Box3();
100
- forEachVertex(root, (p) => box.expandByPoint(p));
103
+ boxes(root, new Matrix4(), box);
101
104
  return box;
102
105
  }
103
- /** The centre and half diagonal of `boundingBox(root)`: an impostor baked from `root` has the same box. */
104
- export function boundingSphere(root) {
105
- const sphere = sphereOf(boundingBox(root));
106
- if (!sphere)
107
- throw new Error("@drawcall/lod: object has no visible geometry to measure");
108
- return sphere;
106
+ function boxes(node, placement, box) {
107
+ if (isInstancedLod(node)) {
108
+ const source = node.levels[0];
109
+ if (!source)
110
+ return;
111
+ // Its level 0 at every instance, as forEachMesh visits them: tighter than its level meshes' box (see InstancedLod).
112
+ // The box it declares, else the one it draws.
113
+ const own = source.box?.clone() ?? (source.object ? boundingBox(source.object).applyMatrix4(local(source.object)) : new Box3());
114
+ const instance = new Matrix4();
115
+ for (const { chunk, index } of instancesOf(node))
116
+ box.union(own.clone().applyMatrix4(chunk.getMatrixAt(index, instance).premultiply(placement)));
117
+ return;
118
+ }
119
+ if (isLOD(node) && !node.levels[0]?.object) {
120
+ const metadata = node.levels[0]?.box;
121
+ if (metadata)
122
+ box.union(metadata.clone().applyMatrix4(placement));
123
+ return;
124
+ }
125
+ if (isMesh(node) && [node.material].flat().some((material) => material.visible && material.colorWrite)) {
126
+ if (isBatchedMesh(node)) {
127
+ if (!node.boundingBox)
128
+ node.computeBoundingBox();
129
+ if (node.boundingBox)
130
+ box.union(node.boundingBox.clone().applyMatrix4(placement));
131
+ }
132
+ else {
133
+ if (!node.geometry.boundingBox)
134
+ node.geometry.computeBoundingBox();
135
+ const own = node.geometry.boundingBox;
136
+ if (own && (isInstancedMesh(node) || isImpostorMesh(node))) {
137
+ const instance = new Matrix4();
138
+ for (let i = 0; i < node.count; i++)
139
+ box.union(own.clone().applyMatrix4(node.getMatrixAt(i, instance).premultiply(placement)));
140
+ }
141
+ else if (own)
142
+ box.union(own.clone().applyMatrix4(placement));
143
+ }
144
+ }
145
+ for (const child of detailed(node))
146
+ boxes(child, local(child).premultiply(placement), box);
109
147
  }
110
- const sphereOf = (box) => (box.isEmpty() ? null : new Sphere(box.getCenter(new Vector3()), box.getSize(new Vector3()).length() / 2));
111
- /**
112
- * The sphere fades measure for a Lod's levels (see `boundingSphere`): level 0's, or the
113
- * first level's that draws anything when level 0 draws nothing; `own` in that level's
114
- * own space, `placed` in its parent's (the Lod's). `who` names the caller in the error.
115
- */
116
- export function measureLevels(levels, who) {
117
- for (const level of levels) {
118
- const own = sphereOf(boundingBox(level));
119
- if (!own)
120
- continue;
121
- if (level.matrixAutoUpdate)
122
- level.updateMatrix();
123
- return { own, placed: own.clone().applyMatrix4(level.matrix) };
148
+ /** Every instance of `lod`'s chunks; a GPU chunk's live on the GPU, where the CPU cannot visit them. */
149
+ function* instancesOf(lod) {
150
+ for (const chunk of lod.chunks) {
151
+ if (isStorageInstanced(chunk.instanceMatrix))
152
+ throw new Error("@drawcall/lod: a GPU chunk's instances live on the GPU: the CPU cannot visit its meshes");
153
+ for (let index = 0; index < chunk.count; index++)
154
+ yield { chunk, index };
124
155
  }
125
- throw new Error(`${who}: no level has visible geometry to measure`);
126
156
  }
127
- //# sourceMappingURL=bounds.js.map
157
+ //# sourceMappingURL=detail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detail.js","sourceRoot":"","sources":["../../src/source/detail.ts"],"names":[],"mappings":"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"}
@@ -4,11 +4,11 @@ import { type Surface } from "./surface.js";
4
4
  * How far a level's surface `low` is from `source`'s: the distances from points spread
5
5
  * evenly by area over each surface to the other, measured with a BVH. Source points
6
6
  * nobody sees from outside (a floor inside, the inner side of a partition) are left out:
7
- * they need no counterpart on the level. `error` is the 99.9th percentile of the
7
+ * they need no counterpart on the level. `deviation` is the 99.9th percentile of the
8
8
  * distances, `widest` the largest. A high percentile, as what a level moves (a part
9
9
  * collapsed or cut off) is often a sliver of the area.
10
10
  */
11
- export declare function measureError(source: Source, low: Surface): {
12
- error: number;
11
+ export declare function measureDeviation(source: Source, low: Surface): {
12
+ deviation: number;
13
13
  widest: number;
14
14
  };
@@ -1,19 +1,19 @@
1
1
  import { BufferAttribute, BufferGeometry, Vector3 } from "three/webgpu";
2
2
  import { MeshBVH } from "three-mesh-bvh";
3
- import { Shading } from "./shading.js";
3
+ import { MaterialEvaluator } from "./evaluator.js";
4
4
  import { triangleArea } from "./surface.js";
5
- import { Tracer } from "./trace.js";
6
- /** Points sampled per surface to measure the error. */
5
+ import { SourceRaycaster } from "./raycaster.js";
6
+ /** Points sampled per surface to measure the deviation. */
7
7
  const SAMPLES = 20000;
8
8
  /**
9
9
  * How far a level's surface `low` is from `source`'s: the distances from points spread
10
10
  * evenly by area over each surface to the other, measured with a BVH. Source points
11
11
  * nobody sees from outside (a floor inside, the inner side of a partition) are left out:
12
- * they need no counterpart on the level. `error` is the 99.9th percentile of the
12
+ * they need no counterpart on the level. `deviation` is the 99.9th percentile of the
13
13
  * distances, `widest` the largest. A high percentile, as what a level moves (a part
14
14
  * collapsed or cut off) is often a sliver of the area.
15
15
  */
16
- export function measureError(source, low) {
16
+ export function measureDeviation(source, low) {
17
17
  const geometry = new BufferGeometry();
18
18
  geometry.setAttribute("position", new BufferAttribute(low.positions, 3));
19
19
  // The BVH reorders the index it is built on.
@@ -27,12 +27,12 @@ export function measureError(source, low) {
27
27
  distances.push(closest(toLow, point));
28
28
  });
29
29
  const sorted = Float64Array.from(distances).sort();
30
- return { error: sorted[Math.floor(0.999 * (sorted.length - 1))] ?? 0, widest: sorted[sorted.length - 1] ?? 0 };
30
+ return { deviation: sorted[Math.floor(0.999 * (sorted.length - 1))] ?? 0, widest: sorted[sorted.length - 1] ?? 0 };
31
31
  }
32
32
  const hit = { point: new Vector3(), distance: 0, faceIndex: 0 };
33
33
  function closest(bvh, point) {
34
34
  if (!bvh.closestPointToPoint(point, hit))
35
- throw new Error("@drawcall/lod: no closest point to measure the error by");
35
+ throw new Error("@drawcall/lod: no closest point to measure the deviation by");
36
36
  return hit.distance;
37
37
  }
38
38
  /**
@@ -46,14 +46,14 @@ function visibility(source) {
46
46
  const bounds = geometry.boundingSphere;
47
47
  if (!bounds)
48
48
  throw new Error("@drawcall/lod: the source has no bounds");
49
- const shading = new Shading(source, 0);
50
- const tracer = new Tracer(source, shading);
49
+ const evaluator = new MaterialEvaluator(source, 0);
50
+ const raycaster = new SourceRaycaster(source, evaluator);
51
51
  const normal = new Vector3();
52
52
  const corner = new Vector3();
53
53
  const origin = new Vector3();
54
54
  const epsilon = bounds.radius * 1e-4;
55
55
  const far = bounds.radius * 4;
56
- const escapes = (point, direction) => tracer.cast(origin.copy(point).addScaledVector(direction, epsilon), direction, far, null) !== "opaque";
56
+ const escapes = (point, direction) => raycaster.cast(origin.copy(point).addScaledVector(direction, epsilon), direction, far, null) !== "opaque";
57
57
  return (point, triangle) => {
58
58
  const { positions, index } = source;
59
59
  const a = (index[triangle * 3] ?? 0) * 3;
@@ -62,7 +62,7 @@ function visibility(source) {
62
62
  normal.cross(corner).normalize();
63
63
  if (escapes(point, normal))
64
64
  return true;
65
- return shading.material(triangle).doubleSided && escapes(point, normal.negate());
65
+ return evaluator.material(triangle).doubleSided && escapes(point, normal.negate());
66
66
  };
67
67
  }
68
68
  /** Call `visit` with points spread evenly by area over `from`, and the triangle of each. */
@@ -91,4 +91,4 @@ function measure(from, visit) {
91
91
  visit(point, t);
92
92
  }
93
93
  }
94
- //# sourceMappingURL=error.js.map
94
+ //# sourceMappingURL=deviation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deviation.js","sourceRoot":"","sources":["../../src/source/deviation.ts"],"names":[],"mappings":"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"}