@drawcall/lod 0.2.0 → 0.4.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 (355) hide show
  1. package/README.md +6 -7
  2. package/dist/bake.d.ts +36 -0
  3. package/dist/bake.js +176 -0
  4. package/dist/bake.js.map +1 -0
  5. package/dist/baked/codec.d.ts +3 -6
  6. package/dist/baked/codec.js +48 -154
  7. package/dist/baked/codec.js.map +1 -1
  8. package/dist/baked/coverage.d.ts +6 -3
  9. package/dist/baked/coverage.js +6 -3
  10. package/dist/baked/coverage.js.map +1 -1
  11. package/dist/baked/fields.d.ts +9 -0
  12. package/dist/baked/fields.js +22 -0
  13. package/dist/baked/fields.js.map +1 -0
  14. package/dist/baked/index.d.ts +14 -8
  15. package/dist/baked/index.js +24 -22
  16. package/dist/baked/index.js.map +1 -1
  17. package/dist/baked/interior/faces.d.ts +4 -3
  18. package/dist/baked/interior/faces.js +16 -11
  19. package/dist/baked/interior/faces.js.map +1 -1
  20. package/dist/baked/interior/material.d.ts +7 -10
  21. package/dist/baked/interior/material.js +29 -36
  22. package/dist/baked/interior/material.js.map +1 -1
  23. package/dist/baked/interior/rooms.d.ts +1 -1
  24. package/dist/baked/interior/rooms.js +2 -2
  25. package/dist/baked/interior/rooms.js.map +1 -1
  26. package/dist/baked/low.js +5 -4
  27. package/dist/baked/low.js.map +1 -1
  28. package/dist/baked/raster.js +6 -6
  29. package/dist/baked/raster.js.map +1 -1
  30. package/dist/baked/textures.d.ts +17 -0
  31. package/dist/baked/textures.js +95 -0
  32. package/dist/baked/textures.js.map +1 -0
  33. package/dist/baked/transfer.js +19 -18
  34. package/dist/baked/transfer.js.map +1 -1
  35. package/dist/baked/unwrap.js +4 -3
  36. package/dist/baked/unwrap.js.map +1 -1
  37. package/dist/baked/xatlas.js.map +1 -1
  38. package/dist/codec/container.d.ts +8 -0
  39. package/dist/codec/container.js +63 -0
  40. package/dist/codec/container.js.map +1 -0
  41. package/dist/codec/mesh.d.ts +8 -0
  42. package/dist/{mesh/codec.js → codec/mesh.js} +80 -52
  43. package/dist/codec/mesh.js.map +1 -0
  44. package/dist/dispose.d.ts +8 -5
  45. package/dist/dispose.js +22 -24
  46. package/dist/dispose.js.map +1 -1
  47. package/dist/foliage.d.ts +32 -0
  48. package/dist/foliage.js +137 -0
  49. package/dist/foliage.js.map +1 -0
  50. package/dist/impostor/bake/atlas.d.ts +4 -4
  51. package/dist/impostor/bake/atlas.js +12 -12
  52. package/dist/impostor/bake/atlas.js.map +1 -1
  53. package/dist/impostor/bake/fit.d.ts +8 -0
  54. package/dist/impostor/bake/fit.js +28 -0
  55. package/dist/impostor/bake/fit.js.map +1 -0
  56. package/dist/impostor/bake/index.d.ts +22 -14
  57. package/dist/impostor/bake/index.js +50 -134
  58. package/dist/impostor/bake/index.js.map +1 -1
  59. package/dist/impostor/bake/materials.d.ts +3 -3
  60. package/dist/impostor/bake/materials.js +51 -13
  61. package/dist/impostor/bake/materials.js.map +1 -1
  62. package/dist/impostor/bake/sheet.d.ts +8 -0
  63. package/dist/impostor/bake/sheet.js +90 -0
  64. package/dist/impostor/bake/sheet.js.map +1 -0
  65. package/dist/impostor/bake/source.d.ts +3 -2
  66. package/dist/impostor/bake/source.js +9 -20
  67. package/dist/impostor/bake/source.js.map +1 -1
  68. package/dist/impostor/codec.d.ts +4 -5
  69. package/dist/impostor/codec.js +36 -109
  70. package/dist/impostor/codec.js.map +1 -1
  71. package/dist/impostor/impostor.d.ts +31 -7
  72. package/dist/impostor/impostor.js +21 -6
  73. package/dist/impostor/impostor.js.map +1 -1
  74. package/dist/impostor/ktx2/encode.d.ts +26 -0
  75. package/dist/impostor/ktx2/encode.js +120 -0
  76. package/dist/impostor/ktx2/encode.js.map +1 -0
  77. package/dist/impostor/ktx2/transcode.d.ts +3 -0
  78. package/dist/impostor/ktx2/transcode.js +99 -0
  79. package/dist/impostor/ktx2/transcode.js.map +1 -0
  80. package/dist/impostor/ktx2/uastc.d.ts +7 -0
  81. package/dist/impostor/ktx2/uastc.js +65 -0
  82. package/dist/impostor/ktx2/uastc.js.map +1 -0
  83. package/dist/impostor/ktx2/wasm/encoder.d.ts +4 -0
  84. package/dist/impostor/ktx2/wasm/encoder.js +10 -0
  85. package/dist/impostor/ktx2/wasm/encoder.js.map +1 -0
  86. package/dist/impostor/ktx2/wasm/transcoder.d.ts +3 -0
  87. package/dist/impostor/ktx2/wasm/transcoder.js +9 -0
  88. package/dist/impostor/ktx2/wasm/transcoder.js.map +1 -0
  89. package/dist/impostor/ktx2/worker.d.ts +1 -0
  90. package/dist/impostor/ktx2/worker.js +10 -0
  91. package/dist/impostor/ktx2/worker.js.map +1 -0
  92. package/dist/impostor/mesh/card.d.ts +4 -4
  93. package/dist/impostor/mesh/card.js +7 -7
  94. package/dist/impostor/mesh/card.js.map +1 -1
  95. package/dist/impostor/mesh/index.d.ts +7 -6
  96. package/dist/impostor/mesh/index.js +10 -11
  97. package/dist/impostor/mesh/index.js.map +1 -1
  98. package/dist/impostor/mesh/material.d.ts +18 -9
  99. package/dist/impostor/mesh/material.js +40 -27
  100. package/dist/impostor/mesh/material.js.map +1 -1
  101. package/dist/impostor/mesh/surface.d.ts +1 -1
  102. package/dist/impostor/mesh/surface.js +13 -9
  103. package/dist/impostor/mesh/surface.js.map +1 -1
  104. package/dist/impostor/mesh/textures.d.ts +3 -3
  105. package/dist/impostor/mesh/textures.js +24 -34
  106. package/dist/impostor/mesh/textures.js.map +1 -1
  107. package/dist/index.d.ts +13 -11
  108. package/dist/index.js +12 -10
  109. package/dist/index.js.map +1 -1
  110. package/dist/instanced/camera.d.ts +34 -0
  111. package/dist/instanced/camera.js +45 -0
  112. package/dist/instanced/camera.js.map +1 -0
  113. package/dist/instanced/clusters.d.ts +54 -0
  114. package/dist/instanced/clusters.js +151 -0
  115. package/dist/instanced/clusters.js.map +1 -0
  116. package/dist/instanced/cull.d.ts +28 -0
  117. package/dist/instanced/cull.js +22 -0
  118. package/dist/instanced/cull.js.map +1 -0
  119. package/dist/instanced/instances.d.ts +39 -0
  120. package/dist/instanced/instances.js +104 -0
  121. package/dist/instanced/instances.js.map +1 -0
  122. package/dist/instanced/key.d.ts +19 -0
  123. package/dist/instanced/key.js +45 -0
  124. package/dist/instanced/key.js.map +1 -0
  125. package/dist/instanced/levels.d.ts +60 -0
  126. package/dist/instanced/levels.js +131 -0
  127. package/dist/instanced/levels.js.map +1 -0
  128. package/dist/instanced/lists.d.ts +57 -0
  129. package/dist/instanced/lists.js +114 -0
  130. package/dist/instanced/lists.js.map +1 -0
  131. package/dist/instanced/measure.d.ts +28 -0
  132. package/dist/instanced/measure.js +203 -0
  133. package/dist/instanced/measure.js.map +1 -0
  134. package/dist/instanced/meshes.d.ts +44 -51
  135. package/dist/instanced/meshes.js +167 -179
  136. package/dist/instanced/meshes.js.map +1 -1
  137. package/dist/instanced/mirror.d.ts +24 -0
  138. package/dist/instanced/mirror.js +76 -0
  139. package/dist/instanced/mirror.js.map +1 -0
  140. package/dist/instanced/raycast.d.ts +10 -11
  141. package/dist/instanced/raycast.js +31 -41
  142. package/dist/instanced/raycast.js.map +1 -1
  143. package/dist/instanced/rows.d.ts +50 -0
  144. package/dist/instanced/rows.js +36 -0
  145. package/dist/instanced/rows.js.map +1 -0
  146. package/dist/instanced/shape.d.ts +27 -0
  147. package/dist/instanced/shape.js +54 -0
  148. package/dist/instanced/shape.js.map +1 -0
  149. package/dist/instanced/sort.d.ts +61 -0
  150. package/dist/instanced/sort.js +192 -0
  151. package/dist/instanced/sort.js.map +1 -0
  152. package/dist/instanced/update.d.ts +34 -0
  153. package/dist/instanced/update.js +180 -0
  154. package/dist/instanced/update.js.map +1 -0
  155. package/dist/levels/bounds.d.ts +21 -0
  156. package/dist/levels/bounds.js +42 -0
  157. package/dist/levels/bounds.js.map +1 -0
  158. package/dist/levels/cameras.d.ts +48 -0
  159. package/dist/levels/cameras.js +122 -0
  160. package/dist/levels/cameras.js.map +1 -0
  161. package/dist/levels/compile/contexts.d.ts +30 -0
  162. package/dist/levels/compile/contexts.js +18 -0
  163. package/dist/levels/compile/contexts.js.map +1 -0
  164. package/dist/levels/compile/index.d.ts +41 -0
  165. package/dist/levels/compile/index.js +193 -0
  166. package/dist/levels/compile/index.js.map +1 -0
  167. package/dist/levels/compile/pipelines.d.ts +26 -0
  168. package/dist/levels/compile/pipelines.js +172 -0
  169. package/dist/levels/compile/pipelines.js.map +1 -0
  170. package/dist/levels/compiles.d.ts +29 -0
  171. package/dist/levels/compiles.js +50 -0
  172. package/dist/levels/compiles.js.map +1 -0
  173. package/dist/levels/draw.d.ts +102 -0
  174. package/dist/levels/draw.js +401 -0
  175. package/dist/levels/draw.js.map +1 -0
  176. package/dist/levels/fade.d.ts +60 -0
  177. package/dist/levels/fade.js +129 -0
  178. package/dist/levels/fade.js.map +1 -0
  179. package/dist/levels/index.d.ts +99 -0
  180. package/dist/levels/index.js +155 -0
  181. package/dist/levels/index.js.map +1 -0
  182. package/dist/levels/item.d.ts +38 -0
  183. package/dist/levels/item.js +89 -0
  184. package/dist/levels/item.js.map +1 -0
  185. package/dist/levels/load.d.ts +31 -0
  186. package/dist/levels/load.js +144 -0
  187. package/dist/levels/load.js.map +1 -0
  188. package/dist/levels/manager.d.ts +158 -0
  189. package/dist/levels/manager.js +352 -0
  190. package/dist/levels/manager.js.map +1 -0
  191. package/dist/{material.d.ts → levels/material.d.ts} +2 -2
  192. package/dist/{material.js → levels/material.js} +6 -5
  193. package/dist/levels/material.js.map +1 -0
  194. package/dist/levels/renderer.d.ts +32 -0
  195. package/dist/levels/renderer.js +57 -0
  196. package/dist/levels/renderer.js.map +1 -0
  197. package/dist/levels/requests.d.ts +52 -0
  198. package/dist/levels/requests.js +97 -0
  199. package/dist/levels/requests.js.map +1 -0
  200. package/dist/levels/screen.d.ts +14 -0
  201. package/dist/levels/screen.js +21 -0
  202. package/dist/levels/screen.js.map +1 -0
  203. package/dist/loader/build.d.ts +10 -0
  204. package/dist/loader/build.js +28 -0
  205. package/dist/loader/build.js.map +1 -0
  206. package/dist/loader/context.d.ts +44 -0
  207. package/dist/loader/context.js +96 -0
  208. package/dist/loader/context.js.map +1 -0
  209. package/dist/loader/entry.d.ts +4 -0
  210. package/dist/loader/entry.js +43 -0
  211. package/dist/loader/entry.js.map +1 -0
  212. package/dist/loader/index.d.ts +76 -0
  213. package/dist/loader/index.js +272 -0
  214. package/dist/loader/index.js.map +1 -0
  215. package/dist/loader/level.d.ts +41 -0
  216. package/dist/loader/level.js +140 -0
  217. package/dist/loader/level.js.map +1 -0
  218. package/dist/loader/node.d.ts +26 -0
  219. package/dist/loader/node.js +199 -0
  220. package/dist/loader/node.js.map +1 -0
  221. package/dist/loader/request.d.ts +54 -0
  222. package/dist/loader/request.js +19 -0
  223. package/dist/loader/request.js.map +1 -0
  224. package/dist/loader/url.d.ts +10 -6
  225. package/dist/loader/url.js +22 -14
  226. package/dist/loader/url.js.map +1 -1
  227. package/dist/lod.d.ts +144 -43
  228. package/dist/lod.js +354 -163
  229. package/dist/lod.js.map +1 -1
  230. package/dist/meshopt.d.ts +6 -0
  231. package/dist/meshopt.js +20 -0
  232. package/dist/meshopt.js.map +1 -0
  233. package/dist/node-process.d.ts +5 -0
  234. package/dist/node-process.js +6 -0
  235. package/dist/node-process.js.map +1 -0
  236. package/dist/node.d.ts +2 -0
  237. package/dist/node.js +5 -0
  238. package/dist/node.js.map +1 -0
  239. package/dist/simplify/cards.d.ts +14 -0
  240. package/dist/simplify/cards.js +128 -0
  241. package/dist/simplify/cards.js.map +1 -0
  242. package/dist/{simplify.d.ts → simplify/index.d.ts} +8 -5
  243. package/dist/{simplify.js → simplify/index.js} +45 -27
  244. package/dist/simplify/index.js.map +1 -0
  245. package/dist/{bounds.d.ts → source/detail.d.ts} +9 -23
  246. package/dist/{bounds.js → source/detail.js} +28 -58
  247. package/dist/source/detail.js.map +1 -0
  248. package/dist/source/deviation.js +6 -6
  249. package/dist/source/deviation.js.map +1 -1
  250. package/dist/source/{shading.d.ts → evaluator.d.ts} +10 -10
  251. package/dist/source/{shading.js → evaluator.js} +5 -5
  252. package/dist/source/evaluator.js.map +1 -0
  253. package/dist/source/{trace.d.ts → raycaster.d.ts} +6 -6
  254. package/dist/source/{trace.js → raycaster.js} +8 -8
  255. package/dist/source/raycaster.js.map +1 -0
  256. package/dist/source/{texels.d.ts → sampler.d.ts} +1 -1
  257. package/dist/source/{texels.js → sampler.js} +8 -5
  258. package/dist/source/sampler.js.map +1 -0
  259. package/dist/source/source.d.ts +1 -1
  260. package/dist/source/source.js +1 -1
  261. package/dist/source/source.js.map +1 -1
  262. package/dist/source/surface.js +1 -1
  263. package/dist/source/surface.js.map +1 -1
  264. package/dist/task.d.ts +6 -0
  265. package/dist/{pause.js → task.js} +5 -5
  266. package/dist/task.js.map +1 -0
  267. package/dist/three.d.ts +19 -30
  268. package/dist/three.js +30 -57
  269. package/dist/three.js.map +1 -1
  270. package/dist/tsl.d.ts +8 -12
  271. package/dist/tsl.js +11 -39
  272. package/dist/tsl.js.map +1 -1
  273. package/dist/typegpu.d.ts +37 -0
  274. package/dist/typegpu.js +37 -0
  275. package/dist/typegpu.js.map +1 -0
  276. package/dist/wind/bounds.js +3 -3
  277. package/dist/wind/bounds.js.map +1 -1
  278. package/dist/wind/hooks.d.ts +7 -4
  279. package/dist/wind/hooks.js +5 -2
  280. package/dist/wind/hooks.js.map +1 -1
  281. package/dist/wind/index.d.ts +4 -4
  282. package/dist/wind/index.js +25 -23
  283. package/dist/wind/index.js.map +1 -1
  284. package/dist/wind/sway.d.ts +2 -0
  285. package/dist/wind/sway.js +4 -1
  286. package/dist/wind/sway.js.map +1 -1
  287. package/package.json +24 -10
  288. package/skills/lod/SKILL.md +120 -32
  289. package/dist/bounds.js.map +0 -1
  290. package/dist/compile.d.ts +0 -4
  291. package/dist/compile.js +0 -100
  292. package/dist/compile.js.map +0 -1
  293. package/dist/deferred.d.ts +0 -12
  294. package/dist/deferred.js +0 -27
  295. package/dist/deferred.js.map +0 -1
  296. package/dist/fade.d.ts +0 -36
  297. package/dist/fade.js +0 -112
  298. package/dist/fade.js.map +0 -1
  299. package/dist/instanced/args.d.ts +0 -20
  300. package/dist/instanced/args.js +0 -77
  301. package/dist/instanced/args.js.map +0 -1
  302. package/dist/instanced/blocks.d.ts +0 -66
  303. package/dist/instanced/blocks.js +0 -294
  304. package/dist/instanced/blocks.js.map +0 -1
  305. package/dist/instanced/dirty.d.ts +0 -15
  306. package/dist/instanced/dirty.js +0 -96
  307. package/dist/instanced/dirty.js.map +0 -1
  308. package/dist/instanced/index.d.ts +0 -90
  309. package/dist/instanced/index.js +0 -349
  310. package/dist/instanced/index.js.map +0 -1
  311. package/dist/instanced/parts.d.ts +0 -14
  312. package/dist/instanced/parts.js +0 -79
  313. package/dist/instanced/parts.js.map +0 -1
  314. package/dist/instanced/select.d.ts +0 -92
  315. package/dist/instanced/select.js +0 -315
  316. package/dist/instanced/select.js.map +0 -1
  317. package/dist/instanced/store.d.ts +0 -31
  318. package/dist/instanced/store.js +0 -96
  319. package/dist/instanced/store.js.map +0 -1
  320. package/dist/levels.d.ts +0 -95
  321. package/dist/levels.js +0 -171
  322. package/dist/levels.js.map +0 -1
  323. package/dist/loader/bundle.d.ts +0 -25
  324. package/dist/loader/bundle.js +0 -241
  325. package/dist/loader/bundle.js.map +0 -1
  326. package/dist/loader/cache.d.ts +0 -15
  327. package/dist/loader/cache.js +0 -75
  328. package/dist/loader/cache.js.map +0 -1
  329. package/dist/loader/provenance.d.ts +0 -30
  330. package/dist/loader/provenance.js +0 -105
  331. package/dist/loader/provenance.js.map +0 -1
  332. package/dist/loader.d.ts +0 -55
  333. package/dist/loader.js +0 -239
  334. package/dist/loader.js.map +0 -1
  335. package/dist/material.js.map +0 -1
  336. package/dist/mesh/codec.d.ts +0 -4
  337. package/dist/mesh/codec.js.map +0 -1
  338. package/dist/pause.d.ts +0 -6
  339. package/dist/pause.js.map +0 -1
  340. package/dist/queue.d.ts +0 -2
  341. package/dist/queue.js +0 -33
  342. package/dist/queue.js.map +0 -1
  343. package/dist/renderer.d.ts +0 -21
  344. package/dist/renderer.js +0 -83
  345. package/dist/renderer.js.map +0 -1
  346. package/dist/residency.d.ts +0 -44
  347. package/dist/residency.js +0 -205
  348. package/dist/residency.js.map +0 -1
  349. package/dist/simplify.js.map +0 -1
  350. package/dist/source/shading.js.map +0 -1
  351. package/dist/source/texels.js.map +0 -1
  352. package/dist/source/trace.js.map +0 -1
  353. package/dist/view.d.ts +0 -45
  354. package/dist/view.js +0 -131
  355. package/dist/view.js.map +0 -1
@@ -1,7 +1,10 @@
1
- import { gzipSync, strFromU8, strToU8 } from "fflate";
2
- import { BufferAttribute, BufferGeometry, Float16BufferAttribute, FloatType, Group, IntType, Mesh, Object3D, Scene, } from "three/webgpu";
3
- import { borrowMaterials } from "../dispose.js";
1
+ import { MeshoptEncoder } from "meshoptimizer";
2
+ import { Box3, BufferAttribute, BufferGeometry, Float16BufferAttribute, FloatType, Group, IntType, Mesh, Object3D, Scene, Sphere, Vector3, } from "three/webgpu";
3
+ import { pack, unpack } from "./container.js";
4
+ import { meshoptDecoder } from "../meshopt.js";
4
5
  import { isInstancedMesh, isLOD, isMesh, isSkinnedMesh } from "../three.js";
6
+ // The file format of a simplified level: a static hierarchy's geometry and material slots, drawn with its source's
7
+ // materials.
5
8
  const arrays = {
6
9
  Int8Array,
7
10
  Uint8Array,
@@ -14,12 +17,17 @@ const arrays = {
14
17
  Float64Array,
15
18
  };
16
19
  const containers = { Scene, Group, Object3D };
17
- /** Store a static hierarchy's geometry and material slots. Decode with the same ordered material list; materials and textures are never serialized. */
18
- export function encodeMesh(object, materials) {
19
- const chunks = [];
20
+ /** The significant bits a float attribute holds, of its 24: each value moves by at most 2^-17 of its magnitude. */
21
+ const BITS = 18;
22
+ /**
23
+ * Store a static hierarchy's geometry and material slots. Decode with the same ordered material list; materials and textures are never serialized.
24
+ * Attributes and indices are meshopt-encoded, and float attributes hold `BITS` significant bits, as meshopt's exponential filter stores them.
25
+ */
26
+ export async function encodeMeshAsync(object, materials) {
27
+ await MeshoptEncoder.ready;
28
+ const files = [];
20
29
  const geometries = [];
21
- let length = 0;
22
- function attribute(value) {
30
+ function attribute(value, index) {
23
31
  if (value instanceof Float16BufferAttribute)
24
32
  fail("unsupported float16 attribute");
25
33
  const packed = value instanceof BufferAttribute ? value.array : value.array.slice(0, value.count * value.itemSize);
@@ -28,14 +36,20 @@ export function encodeMesh(object, materials) {
28
36
  const offset = i * value.data.stride + value.offset;
29
37
  packed.set(value.array.subarray(offset, offset + value.itemSize), i * value.itemSize);
30
38
  }
31
- const offset = length;
32
- chunks.push(new Uint8Array(packed.buffer, packed.byteOffset, packed.byteLength));
33
- length += packed.byteLength;
39
+ const stride = packed.BYTES_PER_ELEMENT * value.itemSize;
40
+ const mode = index ? (stride === 2 || stride === 4 ? (value.count % 3 ? "INDICES" : "TRIANGLES") : null) : stride % 4 || stride > 256 ? null : "ATTRIBUTES";
41
+ const floats = mode === "ATTRIBUTES" && packed instanceof Float32Array ? packed : undefined;
42
+ const bytes = floats
43
+ ? MeshoptEncoder.encodeFilterExp(floats, value.count, stride, BITS, "Separate")
44
+ : new Uint8Array(packed.buffer, packed.byteOffset, packed.byteLength);
45
+ files.push(mode ? MeshoptEncoder.encodeGltfBuffer(bytes, value.count, stride, mode, 1) : bytes);
34
46
  return {
35
- offset,
36
- length: packed.byteLength,
47
+ file: files.length - 1,
37
48
  type: packed.constructor.name,
49
+ count: value.count,
38
50
  size: value.itemSize,
51
+ mode,
52
+ filter: floats ? "EXPONENTIAL" : null,
39
53
  normalized: value.normalized,
40
54
  gpuType: value instanceof BufferAttribute ? value.gpuType : FloatType,
41
55
  };
@@ -77,68 +91,70 @@ export function encodeMesh(object, materials) {
77
91
  if (Object.keys(value.morphAttributes).length)
78
92
  fail("cannot persist morph targets");
79
93
  return {
94
+ bounds: bounds(value),
80
95
  name: value.name,
81
96
  data: value.userData,
82
97
  groups: value.groups.map((group) => [group.start, group.count, group.materialIndex ?? 0]),
83
98
  range: [value.drawRange.start, value.drawRange.count === Infinity ? null : value.drawRange.count],
84
- attributes: Object.fromEntries(Object.entries(value.attributes).map(([name, value]) => [name, attribute(value)])),
85
- index: value.index && attribute(value.index),
99
+ attributes: Object.fromEntries(Object.entries(value.attributes).map(([name, value]) => [name, attribute(value, false)])),
100
+ index: value.index && attribute(value.index, true),
86
101
  };
87
102
  });
88
- const header = strToU8(JSON.stringify({ version: 1, root, geometry }));
89
- const bytes = new Uint8Array(4 + header.length + length);
90
- new DataView(bytes.buffer).setUint32(0, header.length, true);
91
- bytes.set(header, 4);
92
- let offset = 4 + header.length;
93
- for (const chunk of chunks) {
94
- bytes.set(chunk, offset);
95
- offset += chunk.length;
96
- }
97
- return gzipSync(bytes, { level: 1 });
103
+ return pack({ version: 3, root, geometry }, files);
98
104
  }
105
+ /** The hierarchy `encodeMeshAsync` stored, drawn with `materials`, which stay the caller's to free. */
99
106
  export async function decodeMeshAsync(input, materials) {
100
- const bytes = new Uint8Array(await new Response(new Blob([input.slice().buffer]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer());
101
- if (bytes.length < 4)
102
- fail("missing metadata");
103
- const start = 4 + new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0, true);
104
- if (start > bytes.length)
105
- fail("invalid metadata length");
106
- const meta = record(JSON.parse(strFromU8(bytes.subarray(4, start))));
107
- if (meta.version !== 1)
108
- fail("unsupported version");
109
- function attribute(value) {
107
+ const { header, files } = await unpack(input, fail);
108
+ const meta = record(header);
109
+ if (meta.version !== 3)
110
+ fail("unsupported version; encode it again");
111
+ const decoder = meshoptDecoder();
112
+ async function attribute(value) {
110
113
  const meta = record(value);
111
114
  const Type = arrays[string(meta.type)] ?? fail("unsupported attribute type");
112
- const offset = start + integer(meta.offset);
113
- const length = integer(meta.length);
115
+ const file = files[integer(meta.file)] ?? fail("missing attribute file");
116
+ const count = integer(meta.count);
114
117
  const size = integer(meta.size);
115
- if (!size || length % (Type.BYTES_PER_ELEMENT * size) || offset + length > bytes.length)
118
+ const stride = Type.BYTES_PER_ELEMENT * size;
119
+ const mode = meta.mode === null ? null : string(meta.mode);
120
+ const filter = meta.filter === null ? undefined : string(meta.filter);
121
+ if (!size || (mode === null && file.length !== count * stride))
116
122
  fail("invalid attribute length");
117
- const result = new BufferAttribute(new Type(bytes.slice(offset, offset + length).buffer), size, boolean(meta.normalized));
123
+ const { buffer, byteOffset } = mode === null ? file : await decoder.decodeGltfBufferAsync(count, stride, file, mode, filter);
124
+ if (!(buffer instanceof ArrayBuffer))
125
+ fail("shared attribute data");
126
+ const array = new Type(buffer, byteOffset, count * size);
127
+ const result = new BufferAttribute(array, size, boolean(meta.normalized));
118
128
  if (meta.gpuType !== FloatType && meta.gpuType !== IntType)
119
129
  fail("invalid attribute gpuType");
120
130
  result.gpuType = meta.gpuType;
121
131
  return result;
122
132
  }
123
- const geometries = list(meta.geometry).map((value) => {
133
+ const geometries = await Promise.all(list(meta.geometry).map(async (value) => {
124
134
  const meta = record(value);
125
135
  const geometry = new BufferGeometry();
126
136
  geometry.name = string(meta.name);
127
137
  geometry.userData = record(meta.data);
128
- for (const [name, value] of Object.entries(record(meta.attributes)))
129
- geometry.setAttribute(name, attribute(value));
138
+ const attributes = Object.entries(record(meta.attributes));
139
+ const decoded = await Promise.all(attributes.map(([, value]) => attribute(value)));
140
+ attributes.forEach(([name], i) => geometry.setAttribute(name, decoded[i] ?? fail("missing attribute")));
130
141
  if (meta.index !== null)
131
- geometry.setIndex(attribute(meta.index));
142
+ geometry.setIndex(await attribute(meta.index));
132
143
  for (const value of list(meta.groups)) {
133
144
  const group = list(value);
134
145
  geometry.addGroup(integer(group[0]), integer(group[1]), integer(group[2]));
135
146
  }
136
147
  const range = list(meta.range);
137
148
  geometry.setDrawRange(integer(range[0]), range[1] === null ? Infinity : integer(range[1]));
138
- geometry.computeBoundingBox();
139
- geometry.computeBoundingSphere();
149
+ if (meta.bounds !== null) {
150
+ const values = list(meta.bounds).map(number);
151
+ if (values.length !== 10)
152
+ fail("invalid bounds");
153
+ geometry.boundingBox = new Box3().setFromArray(values.slice(0, 6));
154
+ geometry.boundingSphere = new Sphere(new Vector3().fromArray(values, 6), values[9]);
155
+ }
140
156
  return geometry;
141
- });
157
+ }));
142
158
  const material = (value) => materials[integer(value)] ?? fail("missing source material");
143
159
  function node(value) {
144
160
  const meta = record(value);
@@ -161,12 +177,24 @@ export async function decodeMeshAsync(input, materials) {
161
177
  result.add(node(child));
162
178
  return result;
163
179
  }
164
- const root = node(meta.root);
165
- borrowMaterials(root);
166
- return root;
180
+ return node(meta.root);
181
+ }
182
+ /**
183
+ * The box and sphere three computes from the positions, stored so decode does not walk them; null without positions. They
184
+ * bound the positions before the filter, which may move a vertex out of them by 2^-17 of its coordinates.
185
+ */
186
+ function bounds(geometry) {
187
+ if (!geometry.getAttribute("position"))
188
+ return null;
189
+ geometry.computeBoundingBox();
190
+ geometry.computeBoundingSphere();
191
+ const { boundingBox: box, boundingSphere: sphere } = geometry;
192
+ if (!box || !sphere)
193
+ fail("missing bounds");
194
+ return [...box.min.toArray(), ...box.max.toArray(), ...sphere.center.toArray(), sphere.radius];
167
195
  }
168
- function fail(reason) {
169
- throw new Error(`Invalid mesh cache (${reason})`);
196
+ function fail(reason, cause) {
197
+ throw new Error(`Invalid mesh cache (${reason})`, { cause });
170
198
  }
171
199
  function record(value) {
172
200
  if (typeof value !== "object" || value === null || Array.isArray(value))
@@ -189,4 +217,4 @@ function integer(value) {
189
217
  const result = number(value);
190
218
  return Number.isSafeInteger(result) && result >= 0 ? result : fail("expected nonnegative integer");
191
219
  }
192
- //# sourceMappingURL=codec.js.map
220
+ //# sourceMappingURL=mesh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh.js","sourceRoot":"","sources":["../../src/codec/mesh.ts"],"names":[],"mappings":"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"}
package/dist/dispose.d.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  import type { Object3D } from "three/webgpu";
2
- /** Derived geometry keeps its source materials; their owner releases them. */
3
- export declare function borrowMaterials(root: Object3D): void;
4
2
  /** Clones share source geometry, materials and textures; only their own draw state is released here. */
5
3
  export declare function disposeCopies(node: Object3D): void;
6
- /** Free what `node` and its descendants hold; a nested LOD or an ImpostorMesh frees itself. */
7
- export declare function disposeTree(node: Object3D): void;
4
+ /** What `disposeRecursive` frees beside geometry and draw state. */
5
+ export interface DisposeOptions {
6
+ /** whether the tree's materials and their textures are its own; false for a tree drawn with its source's, as a simplified level is */
7
+ materials: boolean;
8
+ }
9
+ /** Free what `node` and its descendants hold; a LOD or an ImpostorMesh frees itself. */
10
+ export declare function disposeRecursive(node: Object3D, { materials }?: DisposeOptions): void;
8
11
  /** Cleanup must not replace the failure that rejected a load or prevent the other levels from being released. */
9
- export declare function disposeRejected(node: Object3D): void;
12
+ export declare function disposeRejected(node: Object3D, options?: DisposeOptions): void;
package/dist/dispose.js CHANGED
@@ -1,41 +1,39 @@
1
- import { originalOf } from "./material.js";
1
+ import { originalOf } from "./levels/material.js";
2
2
  import { isGLTSScene, isImpostorMesh, isInstancedMesh, isLOD, isMesh, isTexture } from "./three.js";
3
- const borrowed = new WeakSet();
4
- /** Derived geometry keeps its source materials; their owner releases them. */
5
- export function borrowMaterials(root) {
6
- root.traverse((node) => {
7
- if (isMesh(node))
8
- borrowed.add(node);
9
- });
10
- }
3
+ // Freeing what a tree of objects holds: whoever made a tree frees it, and only what it made.
11
4
  /** Clones share source geometry, materials and textures; only their own draw state is released here. */
12
5
  export function disposeCopies(node) {
13
- if ((isImpostorMesh(node) || isLOD(node)) && "dispose" in node && typeof node.dispose === "function") {
6
+ if (isImpostorMesh(node) || isLOD(node)) {
14
7
  node.dispose();
15
8
  return;
16
9
  }
10
+ // An InstancedMesh's clone has instance buffers of its own. Any other node fires what Object3D.dispose fires, which frees
11
+ // its draw state: a subclass's own dispose may free what the clone shares.
17
12
  if (isInstancedMesh(node))
18
13
  node.dispose();
14
+ else
15
+ node.dispatchEvent({ type: "dispose" });
19
16
  for (const child of node.children)
20
17
  disposeCopies(child);
21
18
  }
22
- /** Free what `node` and its descendants hold; a nested LOD or an ImpostorMesh frees itself. */
23
- export function disposeTree(node) {
24
- // ImpostorMesh, InstancedMesh, a nested Lod, a GLTS scene.
25
- if ("dispose" in node && typeof node.dispose === "function") {
26
- node.dispose();
27
- if (isImpostorMesh(node) || isLOD(node) || isGLTSScene(node))
28
- return;
29
- }
19
+ /** Free what `node` and its descendants hold; a LOD or an ImpostorMesh frees itself. */
20
+ export function disposeRecursive(node, { materials } = { materials: true }) {
21
+ // Every object frees its draw state; an ImpostorMesh, a Lod and a GLTS scene free the rest too.
22
+ node.dispose();
23
+ if (isImpostorMesh(node) || isLOD(node) || isGLTSScene(node))
24
+ return;
30
25
  if (isMesh(node)) {
31
26
  node.geometry.dispose();
32
- if (!borrowed.has(node))
27
+ if (materials)
33
28
  disposeMaterials(node);
34
29
  }
35
30
  for (const child of node.children)
36
- disposeTree(child);
31
+ disposeRecursive(child, { materials });
37
32
  }
38
- /** Free `mesh`'s materials and their textures: the originals of level copies, which free their copies (see `levelMaterial`). */
33
+ /**
34
+ * Free `mesh`'s materials and their textures: the originals of level copies, which free their copies (see
35
+ * `levelMaterial`). Images stay open: another object, or three's Cache, may share them and upload them again.
36
+ */
39
37
  function disposeMaterials(mesh) {
40
38
  for (const material of new Set([mesh.material].flat().map(originalOf))) {
41
39
  const values = Object.values(material);
@@ -46,12 +44,12 @@ function disposeMaterials(mesh) {
46
44
  }
47
45
  }
48
46
  /** Cleanup must not replace the failure that rejected a load or prevent the other levels from being released. */
49
- export function disposeRejected(node) {
47
+ export function disposeRejected(node, options) {
50
48
  try {
51
- disposeTree(node);
49
+ disposeRecursive(node, options);
52
50
  }
53
51
  catch (error) {
54
- console.error("LodLoader: failed to dispose a rejected load", error);
52
+ console.error("CachedLodLoader: failed to dispose a rejected load", error);
55
53
  }
56
54
  }
57
55
  //# sourceMappingURL=dispose.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dispose.js","sourceRoot":"","sources":["../src/dispose.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEpG,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAQ,CAAC;AAErC,8EAA8E;AAC9E,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE;QACrB,IAAI,MAAM,CAAC,IAAI,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,aAAa,CAAC,IAAc;IAC1C,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,SAAS,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QACrG,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,OAAO;IACT,CAAC;IACD,IAAI,eAAe,CAAC,IAAI,CAAC;QAAE,IAAI,CAAC,OAAO,EAAE,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;QAAE,aAAa,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,WAAW,CAAC,IAAc;IACxC,2DAA2D;IAC3D,IAAI,SAAS,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QAC5D,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC;YAAE,OAAO;IACvE,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QACjB,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;QAAE,WAAW,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAED,gIAAgI;AAChI,SAAS,gBAAgB,CAAC,IAAU;IAClC,KAAK,MAAM,QAAQ,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;QACvE,MAAM,MAAM,GAAc,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClD,KAAK,MAAM,KAAK,IAAI,MAAM;YAAE,IAAI,SAAS,CAAC,KAAK,CAAC;gBAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QAClE,QAAQ,CAAC,OAAO,EAAE,CAAC;IACrB,CAAC;AACH,CAAC;AAED,iHAAiH;AACjH,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,IAAI,CAAC;QACH,WAAW,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,8CAA8C,EAAE,KAAK,CAAC,CAAC;IACvE,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"dispose.js","sourceRoot":"","sources":["../src/dispose.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEpG,6FAA6F;AAE7F,wGAAwG;AACxG,MAAM,UAAU,aAAa,CAAC,IAAc;IAC1C,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,OAAO;IACT,CAAC;IACD,0HAA0H;IAC1H,2EAA2E;IAC3E,IAAI,eAAe,CAAC,IAAI,CAAC;QAAE,IAAI,CAAC,OAAO,EAAE,CAAC;;QACrC,IAAI,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IAC7C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;QAAE,aAAa,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAQD,wFAAwF;AACxF,MAAM,UAAU,gBAAgB,CAAC,IAAc,EAAE,EAAE,SAAS,KAAqB,EAAE,SAAS,EAAE,IAAI,EAAE;IAClG,gGAAgG;IAChG,IAAI,CAAC,OAAO,EAAE,CAAC;IACf,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC;QAAE,OAAO;IACrE,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QACjB,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;QACxB,IAAI,SAAS;YAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;QAAE,gBAAgB,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,IAAU;IAClC,KAAK,MAAM,QAAQ,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;QACvE,MAAM,MAAM,GAAc,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClD,KAAK,MAAM,KAAK,IAAI,MAAM;YAAE,IAAI,SAAS,CAAC,KAAK,CAAC;gBAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QAClE,QAAQ,CAAC,OAAO,EAAE,CAAC;IACrB,CAAC;AACH,CAAC;AAED,iHAAiH;AACjH,MAAM,UAAU,eAAe,CAAC,IAAc,EAAE,OAAwB;IACtE,IAAI,CAAC;QACH,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,oDAAoD,EAAE,KAAK,CAAC,CAAC;IAC7E,CAAC;AACH,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { Color, MeshStandardNodeMaterial, PhysicalLightingModel, type ColorRepresentation, type Material, type Object3D } from "three/webgpu";
2
+ export interface FoliageOptions {
3
+ /** Share of sunlight a leaf passes on to its shaded side (0–1). */
4
+ translucency: number;
5
+ /** Colour of the transmitted light relative to the leaf's own: thin leaves glow yellow-green. Default #e4ff8a. */
6
+ tint?: ColorRepresentation;
7
+ }
8
+ /**
9
+ * A leaf material, lit with translucency: sunlight hitting the far side of a thin leaf shows on the near side, so
10
+ * back-lit leaves glow instead of turning black. It rides on the direct-light term, so it is shadowed exactly like front
11
+ * light. Set up by `foliage`. Its own class so that the copies levels draw with (clones) keep it.
12
+ */
13
+ export declare class Foliage extends MeshStandardNodeMaterial {
14
+ translucency: number;
15
+ readonly tint: Color;
16
+ copy(source: Material): this;
17
+ setupLightingModel(): PhysicalLightingModel;
18
+ customProgramCacheKey(): string;
19
+ }
20
+ /**
21
+ * Makes `material` foliage with `options`. Cut-out leaves also get alpha to coverage and a mip-dependent alpha boost, in
22
+ * the view and in shadow maps alike: plain alpha testing loses coverage in smaller mips, which makes distant needles and
23
+ * leaves vanish.
24
+ */
25
+ export declare function foliage(material: Foliage, { translucency, tint }: FoliageOptions): Foliage;
26
+ /** Turns every alpha-tested standard material under `root`, such as a loaded plant model's leaves, into foliage. */
27
+ export declare function foliageModel(root: Object3D, options: FoliageOptions): void;
28
+ /**
29
+ * Adds leaf translucency to the lighting of the impostors under `root`, such as an `onLevel` level: the bake holds no
30
+ * light passing through a leaf.
31
+ */
32
+ export declare function foliageLevels(root: Object3D, { translucency, tint }: FoliageOptions): void;
@@ -0,0 +1,137 @@
1
+ import { Color, ConvertNode, MeshStandardNodeMaterial, PhysicalLightingModel, TSL, } from "three/webgpu";
2
+ import { Fn, color, dFdx, dFdy, dot, log2, materialColor, materialOpacity, max, normalView, positionViewDirection, pow, saturate, uv, vec2, vec3, vec4, } from "three/tsl";
3
+ import { cosine } from "./impostor/mesh/surface.js";
4
+ import { isImpostorMesh, isMesh, isShadowPass, isStandard } from "./three.js";
5
+ import { isNodeOf } from "./tsl.js";
6
+ const TINT = "#e4ff8a";
7
+ /**
8
+ * A leaf material, lit with translucency: sunlight hitting the far side of a thin leaf shows on the near side, so
9
+ * back-lit leaves glow instead of turning black. It rides on the direct-light term, so it is shadowed exactly like front
10
+ * light. Set up by `foliage`. Its own class so that the copies levels draw with (clones) keep it.
11
+ */
12
+ export class Foliage extends MeshStandardNodeMaterial {
13
+ translucency = 0;
14
+ tint = new Color(1, 1, 1);
15
+ copy(source) {
16
+ super.copy(source);
17
+ // NodeMaterial.copy skips Material accessors, including the cutout threshold.
18
+ this.alphaTest = source.alphaTest;
19
+ if (source instanceof Foliage) {
20
+ this.translucency = source.translucency;
21
+ this.tint.copy(source.tint);
22
+ }
23
+ return this;
24
+ }
25
+ setupLightingModel() {
26
+ return new Translucent(transmitted(leafBehind, this.translucency, this.tint));
27
+ }
28
+ // The lighting model is no node: materials alike in their nodes would share a shader.
29
+ customProgramCacheKey() {
30
+ return `${super.customProgramCacheKey()}|foliage-${this.translucency}-${this.tint.getHexString()}`;
31
+ }
32
+ }
33
+ /**
34
+ * Makes `material` foliage with `options`. Cut-out leaves also get alpha to coverage and a mip-dependent alpha boost, in
35
+ * the view and in shadow maps alike: plain alpha testing loses coverage in smaller mips, which makes distant needles and
36
+ * leaves vanish.
37
+ */
38
+ export function foliage(material, { translucency, tint = TINT }) {
39
+ material.translucency = translucency;
40
+ material.tint.set(tint);
41
+ if (!(material.alphaTest > 0 && material.map))
42
+ return material;
43
+ material.alphaToCoverage = true;
44
+ const boost = boostOf(material.map);
45
+ material.opacityNode = materialOpacity.mul(boost);
46
+ // A shadow pass multiplies the map's alpha by the colour's: there the colour is the boost alone.
47
+ material.colorNode = Fn((builder) => (isShadowPass(builder.material) ? vec4(vec3(1), boost) : baseColor))();
48
+ return material;
49
+ }
50
+ /** Turns every alpha-tested standard material under `root`, such as a loaded plant model's leaves, into foliage. */
51
+ export function foliageModel(root, options) {
52
+ const made = new Map();
53
+ const swap = (material) => {
54
+ if (!isStandard(material) || material.alphaTest === 0)
55
+ return material;
56
+ let leaf = made.get(material);
57
+ if (!leaf)
58
+ made.set(material, (leaf = foliage(new Foliage().copy(material), options)));
59
+ return leaf;
60
+ };
61
+ root.traverse((node) => {
62
+ if (isMesh(node))
63
+ node.material = Array.isArray(node.material) ? node.material.map(swap) : swap(node.material);
64
+ });
65
+ }
66
+ /**
67
+ * Adds leaf translucency to the lighting of the impostors under `root`, such as an `onLevel` level: the bake holds no
68
+ * light passing through a leaf.
69
+ */
70
+ export function foliageLevels(root, { translucency, tint = TINT }) {
71
+ const shade = new Color(tint);
72
+ root.traverse((node) => {
73
+ if (!isImpostorMesh(node))
74
+ return;
75
+ const { material } = node;
76
+ // The mean over the leaves a texel averages: its one unit normal would light them all one way.
77
+ material.directTerm = transmitted((direction) => cosine(material.spread, direction.negate()), translucency, shade);
78
+ });
79
+ }
80
+ /**
81
+ * A material's colour times its map, its alpha included: three's `materialColor`, which builds to a vec4 where the
82
+ * material has a map, and to a vec3 (typed so) where not.
83
+ */
84
+ const baseColor = Fn(() => {
85
+ const base = vec4(1).toVar();
86
+ base.assign(materialColor);
87
+ return base;
88
+ })();
89
+ /** Boosts alpha by the mip `map` is read at. */
90
+ function boostOf(map) {
91
+ const image = map.image;
92
+ if (typeof image !== "object" ||
93
+ image === null ||
94
+ !("width" in image) ||
95
+ !("height" in image) ||
96
+ typeof image.width !== "number" ||
97
+ typeof image.height !== "number")
98
+ throw new Error(`@drawcall/lod: the leaves' map "${map.name}" has no image to measure`);
99
+ const texel = uv().mul(vec2(image.width, image.height));
100
+ const mip = max(log2(max(dot(dFdx(texel), dFdx(texel)), dot(dFdy(texel), dFdy(texel)))).mul(0.5), 0);
101
+ return mip.mul(0.25).add(1);
102
+ }
103
+ /** The share of a leaf's sunlight arriving on its far side, by its normal. */
104
+ const leafBehind = (direction) => saturate(dot(normalView, direction).negate());
105
+ /**
106
+ * The light passing through a leaf from a direct light in `direction`, of that light × the leaf's colour: `behind` the
107
+ * share arriving on its far side.
108
+ */
109
+ function transmitted(behind, share, tint) {
110
+ return (direction) => {
111
+ // light scatters forward through the leaf: strongest when looking toward the sun
112
+ const forward = pow(saturate(dot(positionViewDirection, direction.negate())), 3)
113
+ .mul(0.65)
114
+ .add(0.35);
115
+ return behind(direction).mul(forward).mul(share).mul(color(tint));
116
+ };
117
+ }
118
+ /** Three's lighting with `term` of each direct light's direction added, of that light × the surface's colour. */
119
+ class Translucent extends PhysicalLightingModel {
120
+ term;
121
+ constructor(term) {
122
+ super();
123
+ this.term = term;
124
+ }
125
+ direct(input, builder) {
126
+ super.direct(input, builder);
127
+ const { lightDirection, lightColor, reflectedLight } = input;
128
+ const { directDiffuse } = reflectedLight;
129
+ if (!isNodeOf(lightDirection, "vec3", builder) || !isNodeOf(directDiffuse, "vec3", builder))
130
+ throw new Error("@drawcall/lod: three's direct light is not a direction and a sum");
131
+ // Converted, not asked its type: asked here, before its shadow is set up, three (0.186) answers a colour, keeps
132
+ // that, and writes invalid WGSL for the shadow's vec4.
133
+ const light = vec3(new ConvertNode(lightColor, "vec3"));
134
+ directDiffuse.addAssign(this.term(lightDirection).mul(light).mul(TSL.diffuseContribution));
135
+ }
136
+ }
137
+ //# sourceMappingURL=foliage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"foliage.js","sourceRoot":"","sources":["../src/foliage.ts"],"names":[],"mappings":"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"}
@@ -4,11 +4,11 @@ import type { ImpostorMap } from "../impostor.js";
4
4
  * The bake stores the normals two ways (see its materials): the maps hold the surface's
5
5
  * own normals, `turned` the shading normals turned toward the camera, each with the share
6
6
  * of the surface that shades with the normal rather than its opposite (in orm.a). One way
7
- * is kept for the whole impostor, as texels filtered together must mean the same thing.
7
+ * serves the whole impostor, as texels filtered together must mean the same thing.
8
8
  * With `specular`, the bake also writes each surface's dielectric specular, of which only
9
- * the coverage-weighted sum is kept, for its mean.
9
+ * the coverage-weighted sum is stored, for its mean.
10
10
  */
11
- export declare class Atlas {
11
+ export declare class ImpostorAtlasMip {
12
12
  readonly maps: ImpostorMap[];
13
13
  readonly frames: number;
14
14
  readonly cell: number;
@@ -26,7 +26,7 @@ export declare class Atlas {
26
26
  /** F0 RGB and F90 summed over the texels by coverage, and the coverage summed. */
27
27
  private readonly specularSum;
28
28
  constructor(maps: ImpostorMap[], frames: number, cell: number, specular: boolean);
29
- /** Keep the turned normals: write them over the own normals and their shares. */
29
+ /** Use the turned normals: write them over the own normals and their shares. */
30
30
  useTurned(): void;
31
31
  private layer;
32
32
  /**
@@ -11,11 +11,11 @@ const NEIGHBOURS = [
11
11
  * The bake stores the normals two ways (see its materials): the maps hold the surface's
12
12
  * own normals, `turned` the shading normals turned toward the camera, each with the share
13
13
  * of the surface that shades with the normal rather than its opposite (in orm.a). One way
14
- * is kept for the whole impostor, as texels filtered together must mean the same thing.
14
+ * serves the whole impostor, as texels filtered together must mean the same thing.
15
15
  * With `specular`, the bake also writes each surface's dielectric specular, of which only
16
- * the coverage-weighted sum is kept, for its mean.
16
+ * the coverage-weighted sum is stored, for its mean.
17
17
  */
18
- export class Atlas {
18
+ export class ImpostorAtlasMip {
19
19
  maps;
20
20
  frames;
21
21
  cell;
@@ -39,7 +39,7 @@ export class Atlas {
39
39
  this.coverage = new Float32Array(this.size * this.size);
40
40
  this.turned = new Uint8Array(this.size * this.size * 4);
41
41
  }
42
- /** Keep the turned normals: write them over the own normals and their shares. */
42
+ /** Use the turned normals: write them over the own normals and their shares. */
43
43
  useTurned() {
44
44
  const normalDepth = this.layer("normalDepth");
45
45
  const orm = this.layer("orm");
@@ -52,7 +52,7 @@ export class Atlas {
52
52
  layer(map) {
53
53
  const layer = this.layers[this.maps.indexOf(map)];
54
54
  if (!layer)
55
- throw new Error(`Atlas: no ${map} layer`);
55
+ throw new Error(`ImpostorAtlasMip: no ${map} layer`);
56
56
  return layer;
57
57
  }
58
58
  /**
@@ -66,7 +66,7 @@ export class Atlas {
66
66
  const { cell, size, maps, layers } = this;
67
67
  const [alpha] = pixels;
68
68
  if (!alpha || pixels.length !== maps.length + (this.specular ? 2 : 1))
69
- throw new Error("Atlas.write: one pixel array per map, then the turned normals, then the specular if baked");
69
+ throw new Error("ImpostorAtlasMip.write: one pixel array per map, then the turned normals, then the specular if baked");
70
70
  const sources = [...maps, "turned"];
71
71
  const specular = this.specular ? pixels[maps.length + 1] : undefined;
72
72
  for (let y = 0; y < cell; y++)
@@ -104,7 +104,7 @@ export class Atlas {
104
104
  const source = pixels[m];
105
105
  const layer = map === "turned" ? this.turned : layers[m];
106
106
  if (!source || !layer)
107
- throw new Error(`Atlas.write: no pixels for ${map}`);
107
+ throw new Error(`ImpostorAtlasMip.write: no pixels for ${map}`);
108
108
  const [r, g, b, a] = average(source);
109
109
  if (map === "normalDepth")
110
110
  this.agreement.own += cover * Math.hypot(r * 2 - 1, g * 2 - 1, b * 2 - 1);
@@ -118,7 +118,7 @@ export class Atlas {
118
118
  meanSpecular() {
119
119
  const { value, coverage } = this.specularSum;
120
120
  if (!this.specular || coverage === 0)
121
- throw new Error("Atlas.meanSpecular: no specular was baked");
121
+ throw new Error("ImpostorAtlasMip.meanSpecular: no specular was baked");
122
122
  const [r = 0, g = 0, b = 0, f90 = 0] = value.map((v) => v / coverage);
123
123
  return [r, g, b, f90];
124
124
  }
@@ -162,7 +162,7 @@ export class Atlas {
162
162
  filled[ny * cell + nx] = 1;
163
163
  queue[tail++] = ny * cell + nx;
164
164
  const to = ((y0 + ny) * size + x0 + nx) * 4;
165
- // Base keeps zero coverage; the other layers' alpha is data (depth) and spreads too.
165
+ // Base coverage stays zero; the other layers' alpha is data (depth) and spreads too.
166
166
  this.layers.forEach((layer, m) => {
167
167
  const n = this.maps[m] === "base" ? 3 : 4;
168
168
  for (let k = 0; k < n; k++)
@@ -176,9 +176,9 @@ export class Atlas {
176
176
  }
177
177
  /**
178
178
  * Pack one texel into `layer` at byte `out`: colour as sRGB if `srgb`, the rest linearly.
179
- * An averaged normal keeps its length, which says how far the normals it averages agree
180
- * and is lit by: renormalised, a texel of leaves facing every which way would light as one
181
- * smooth surface turned to the camera.
179
+ * An averaged normal is not renormalised: its length says how far the normals it averages
180
+ * agree, and is lit by. Renormalised, a texel of leaves facing every which way would light
181
+ * as one smooth surface turned to the camera.
182
182
  */
183
183
  function store(layer, out, [r, g, b, a], srgb) {
184
184
  const encode = srgb ? toSrgb : (v) => Math.round(v * 255);