@driftengine/core 3.63.0 → 4.0.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 (428) hide show
  1. package/CHANGELOG.json +111 -0
  2. package/NOTICE +20 -0
  3. package/README.md +1 -1
  4. package/dist/core/loop.js +18 -2
  5. package/dist/core/storage.js +5 -0
  6. package/dist/geometry/meshBuilder.d.ts +1 -1
  7. package/dist/geometry/meshBuilder.js +6 -2
  8. package/dist/index.d.ts +69 -4
  9. package/dist/index.js +112 -2
  10. package/dist/input/input.js +6 -1
  11. package/dist/math/exact.d.ts +13 -3
  12. package/dist/math/exact.js +68 -3
  13. package/dist/math/frustum.d.ts +17 -2
  14. package/dist/math/frustum.js +24 -0
  15. package/dist/render/backend/api.d.ts +34 -1
  16. package/dist/render/backend/api.js +22 -1
  17. package/dist/render/backend/budget.d.ts +7 -6
  18. package/dist/render/backend/budget.js +7 -6
  19. package/dist/render/backend/createRenderer.d.ts +57 -0
  20. package/dist/render/backend/createRenderer.js +51 -2
  21. package/dist/render/backend/materialChanges.d.ts +41 -0
  22. package/dist/render/backend/materialChanges.js +38 -0
  23. package/dist/render/backend/select.js +8 -0
  24. package/dist/render/backend/webgl2/renderer.d.ts +80 -1
  25. package/dist/render/backend/webgl2/renderer.js +208 -10
  26. package/dist/render/backend/webgpu/buffers.d.ts +20 -1
  27. package/dist/render/backend/webgpu/buffers.js +116 -58
  28. package/dist/render/backend/webgpu/fieldCompose.d.ts +156 -0
  29. package/dist/render/backend/webgpu/fieldCompose.js +396 -0
  30. package/dist/render/backend/webgpu/giFieldPass.d.ts +66 -0
  31. package/dist/render/backend/webgpu/giFieldPass.js +137 -0
  32. package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +728 -0
  33. package/dist/render/backend/webgpu/gpuDrivenPass.js +2473 -0
  34. package/dist/render/backend/webgpu/linePass.d.ts +4 -14
  35. package/dist/render/backend/webgpu/linePass.js +4 -33
  36. package/dist/render/backend/webgpu/probeBake.d.ts +148 -0
  37. package/dist/render/backend/webgpu/probeBake.js +493 -0
  38. package/dist/render/backend/webgpu/renderer.d.ts +379 -24
  39. package/dist/render/backend/webgpu/renderer.js +1369 -76
  40. package/dist/render/backend/webgpu/scatterPass.js +15 -1
  41. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +19 -9
  42. package/dist/render/backend/webgpu/surfaceTexturePass.js +58 -32
  43. package/dist/render/causticsRenderer.d.ts +3 -1
  44. package/dist/render/causticsRenderer.js +4 -1
  45. package/dist/render/depthConvention.d.ts +12 -0
  46. package/dist/render/depthConvention.js +14 -0
  47. package/dist/render/deviceFeatures.d.ts +32 -0
  48. package/dist/render/deviceFeatures.js +41 -0
  49. package/dist/render/fog.d.ts +79 -0
  50. package/dist/render/fog.js +138 -0
  51. package/dist/render/frame/alias.d.ts +30 -0
  52. package/dist/render/frame/alias.js +61 -0
  53. package/dist/render/frame/deps.d.ts +37 -0
  54. package/dist/render/frame/deps.js +122 -0
  55. package/dist/render/frame/flushGraph.d.ts +43 -0
  56. package/dist/render/frame/flushGraph.js +84 -0
  57. package/dist/render/frame/graphSchedule.d.ts +49 -0
  58. package/dist/render/frame/graphSchedule.js +120 -0
  59. package/dist/render/frame/index.d.ts +15 -0
  60. package/dist/render/frame/index.js +8 -0
  61. package/dist/render/frame/lifetime.d.ts +24 -0
  62. package/dist/render/frame/lifetime.js +36 -0
  63. package/dist/render/frame/passTimings.d.ts +42 -0
  64. package/dist/render/frame/passTimings.js +38 -0
  65. package/dist/render/frame/validate.d.ts +15 -0
  66. package/dist/render/frame/validate.js +22 -0
  67. package/dist/render/frame/virtual.d.ts +44 -0
  68. package/dist/render/frame/virtual.js +61 -0
  69. package/dist/render/gi/chain.d.ts +82 -0
  70. package/dist/render/gi/chain.js +135 -0
  71. package/dist/render/gi/denoise.d.ts +114 -0
  72. package/dist/render/gi/denoise.js +169 -0
  73. package/dist/render/gi/fieldScene.d.ts +125 -0
  74. package/dist/render/gi/fieldScene.js +219 -0
  75. package/dist/render/gi/globalField.d.ts +157 -0
  76. package/dist/render/gi/globalField.js +373 -0
  77. package/dist/render/gi/probeGridFit.d.ts +24 -0
  78. package/dist/render/gi/probeGridFit.js +71 -0
  79. package/dist/render/gi/probeTrace.d.ts +82 -0
  80. package/dist/render/gi/probeTrace.js +128 -0
  81. package/dist/render/gi/probeVolume.d.ts +136 -0
  82. package/dist/render/gi/probeVolume.js +191 -0
  83. package/dist/render/gi/reflection.d.ts +73 -0
  84. package/dist/render/gi/reflection.js +109 -0
  85. package/dist/render/gi/traceField.d.ts +91 -0
  86. package/dist/render/gi/traceField.js +129 -0
  87. package/dist/render/gi/traceScreen.d.ts +68 -0
  88. package/dist/render/gi/traceScreen.js +82 -0
  89. package/dist/render/gpuScene.d.ts +38 -0
  90. package/dist/render/gpuScene.js +41 -0
  91. package/dist/render/gpudriven/alphaTest.d.ts +28 -0
  92. package/dist/render/gpudriven/alphaTest.js +32 -0
  93. package/dist/render/gpudriven/clusterUpload.d.ts +59 -0
  94. package/dist/render/gpudriven/clusterUpload.js +75 -0
  95. package/dist/render/gpudriven/clusterWorld.d.ts +57 -0
  96. package/dist/render/gpudriven/clusterWorld.js +155 -0
  97. package/dist/render/gpudriven/compact.d.ts +51 -0
  98. package/dist/render/gpudriven/compact.js +68 -0
  99. package/dist/render/gpudriven/cullClusters.d.ts +129 -0
  100. package/dist/render/gpudriven/cullClusters.js +237 -0
  101. package/dist/render/gpudriven/decodeTables.d.ts +64 -0
  102. package/dist/render/gpudriven/decodeTables.js +219 -0
  103. package/dist/render/gpudriven/frustum.d.ts +25 -0
  104. package/dist/render/gpudriven/frustum.js +59 -0
  105. package/dist/render/gpudriven/geometryHarness.d.ts +15 -0
  106. package/dist/render/gpudriven/geometryHarness.js +31 -0
  107. package/dist/render/gpudriven/hzb.d.ts +60 -0
  108. package/dist/render/gpudriven/hzb.js +97 -0
  109. package/dist/render/gpudriven/ibl.d.ts +85 -0
  110. package/dist/render/gpudriven/ibl.js +129 -0
  111. package/dist/render/gpudriven/indirect.d.ts +67 -0
  112. package/dist/render/gpudriven/indirect.js +77 -0
  113. package/dist/render/gpudriven/instances.d.ts +43 -0
  114. package/dist/render/gpudriven/instances.js +172 -0
  115. package/dist/render/gpudriven/lit.d.ts +165 -0
  116. package/dist/render/gpudriven/lit.js +165 -0
  117. package/dist/render/gpudriven/lodCut.d.ts +28 -0
  118. package/dist/render/gpudriven/lodCut.js +38 -0
  119. package/dist/render/gpudriven/materialBin.d.ts +60 -0
  120. package/dist/render/gpudriven/materialBin.js +108 -0
  121. package/dist/render/gpudriven/materialTable.d.ts +88 -0
  122. package/dist/render/gpudriven/materialTable.js +115 -0
  123. package/dist/render/gpudriven/pipeline.d.ts +135 -0
  124. package/dist/render/gpudriven/pipeline.js +237 -0
  125. package/dist/render/gpudriven/rangeAlloc.d.ts +50 -0
  126. package/dist/render/gpudriven/rangeAlloc.js +112 -0
  127. package/dist/render/gpudriven/sceneUpload.d.ts +96 -0
  128. package/dist/render/gpudriven/sceneUpload.js +115 -0
  129. package/dist/render/gpudriven/shadeBins.d.ts +92 -0
  130. package/dist/render/gpudriven/shadeBins.js +182 -0
  131. package/dist/render/gpudriven/shadow.d.ts +136 -0
  132. package/dist/render/gpudriven/shadow.js +224 -0
  133. package/dist/render/gpudriven/shadowCamera.d.ts +87 -0
  134. package/dist/render/gpudriven/shadowCamera.js +345 -0
  135. package/dist/render/gpudriven/streamScene.d.ts +194 -0
  136. package/dist/render/gpudriven/streamScene.js +459 -0
  137. package/dist/render/gpudriven/surfaceFrame.d.ts +25 -0
  138. package/dist/render/gpudriven/surfaceFrame.js +51 -0
  139. package/dist/render/gpudriven/twoPhase.d.ts +122 -0
  140. package/dist/render/gpudriven/twoPhase.js +160 -0
  141. package/dist/render/gpudriven/visbuffer.d.ts +25 -0
  142. package/dist/render/gpudriven/visbuffer.js +37 -0
  143. package/dist/render/halfFloat.d.ts +10 -0
  144. package/dist/render/halfFloat.js +23 -4
  145. package/dist/render/inference/attentionTiled.d.ts +27 -0
  146. package/dist/render/inference/attentionTiled.js +117 -0
  147. package/dist/render/inference/denseKernels.d.ts +29 -0
  148. package/dist/render/inference/denseKernels.js +312 -0
  149. package/dist/render/inference/device.d.ts +21 -0
  150. package/dist/render/inference/device.js +32 -0
  151. package/dist/render/inference/deviceGraph.d.ts +34 -0
  152. package/dist/render/inference/deviceGraph.js +17 -0
  153. package/dist/render/inference/fuse.d.ts +15 -0
  154. package/dist/render/inference/fuse.js +37 -0
  155. package/dist/render/inference/kernelKit.d.ts +52 -0
  156. package/dist/render/inference/kernelKit.js +70 -0
  157. package/dist/render/inference/kernels.d.ts +3 -0
  158. package/dist/render/inference/kernels.js +11 -0
  159. package/dist/render/inference/plan.d.ts +13 -0
  160. package/dist/render/inference/plan.js +18 -0
  161. package/dist/render/inference/reuse.d.ts +39 -0
  162. package/dist/render/inference/reuse.js +65 -0
  163. package/dist/render/inference/runner.d.ts +31 -0
  164. package/dist/render/inference/runner.js +175 -0
  165. package/dist/render/inference/schedule.d.ts +39 -0
  166. package/dist/render/inference/schedule.js +59 -0
  167. package/dist/render/inference/shapeKernels.d.ts +10 -0
  168. package/dist/render/inference/shapeKernels.js +80 -0
  169. package/dist/render/inference/spatialKernels.d.ts +21 -0
  170. package/dist/render/inference/spatialKernels.js +179 -0
  171. package/dist/render/inference/splatRaster.wgsl.d.ts +75 -0
  172. package/dist/render/inference/splatRaster.wgsl.js +337 -0
  173. package/dist/render/inference/splatTiles.d.ts +79 -0
  174. package/dist/render/inference/splatTiles.js +161 -0
  175. package/dist/render/lineBatch.d.ts +2 -5
  176. package/dist/render/lineBatch.js +4 -24
  177. package/dist/render/mesh.d.ts +4 -0
  178. package/dist/render/mesh.js +45 -1
  179. package/dist/render/pass.d.ts +145 -8
  180. package/dist/render/prefilterEnvMap.d.ts +22 -0
  181. package/dist/render/prefilterEnvMap.js +31 -0
  182. package/dist/render/readback.d.ts +30 -0
  183. package/dist/render/readback.js +47 -0
  184. package/dist/render/recon/clamp.d.ts +36 -0
  185. package/dist/render/recon/clamp.js +92 -0
  186. package/dist/render/recon/disocclusion.d.ts +60 -0
  187. package/dist/render/recon/disocclusion.js +109 -0
  188. package/dist/render/recon/frameGen.d.ts +81 -0
  189. package/dist/render/recon/frameGen.js +150 -0
  190. package/dist/render/recon/frameSizes.d.ts +34 -0
  191. package/dist/render/recon/frameSizes.js +58 -0
  192. package/dist/render/recon/jitter.d.ts +60 -0
  193. package/dist/render/recon/jitter.js +118 -0
  194. package/dist/render/recon/motionVectors.d.ts +55 -0
  195. package/dist/render/recon/motionVectors.js +107 -0
  196. package/dist/render/recon/reproject.d.ts +41 -0
  197. package/dist/render/recon/reproject.js +131 -0
  198. package/dist/render/recon/resolve.d.ts +90 -0
  199. package/dist/render/recon/resolve.js +313 -0
  200. package/dist/render/recon/tier.d.ts +24 -0
  201. package/dist/render/recon/tier.js +8 -0
  202. package/dist/render/reflectionProbe.d.ts +26 -0
  203. package/dist/render/reflectionProbe.js +33 -0
  204. package/dist/render/renderQuality.d.ts +69 -0
  205. package/dist/render/renderQuality.js +22 -0
  206. package/dist/render/screenSpaceReflection.d.ts +23 -0
  207. package/dist/render/screenSpaceReflection.js +22 -3
  208. package/dist/render/sdfFont.js +2 -0
  209. package/dist/render/segmentQuads.d.ts +13 -0
  210. package/dist/render/segmentQuads.js +32 -0
  211. package/dist/render/shaders/flat/lobes.d.ts +27 -0
  212. package/dist/render/shaders/flat/lobes.js +33 -3
  213. package/dist/render/shaders/flat/preamble.d.ts +7 -0
  214. package/dist/render/shaders/flat/preamble.js +24 -1
  215. package/dist/render/shaders/flat/probeGrid.d.ts +1 -1
  216. package/dist/render/shaders/flat/probeGrid.js +71 -2
  217. package/dist/render/shaders/generated/flat.wgsl.d.ts +48 -8
  218. package/dist/render/shaders/generated/flat.wgsl.js +64 -24
  219. package/dist/render/shaders/gi/composeField.wgsl.d.ts +56 -0
  220. package/dist/render/shaders/gi/composeField.wgsl.js +231 -0
  221. package/dist/render/shaders/gi/marchField.wgsl.d.ts +30 -0
  222. package/dist/render/shaders/gi/marchField.wgsl.js +141 -0
  223. package/dist/render/shaders/gi/probeBake.wgsl.d.ts +113 -0
  224. package/dist/render/shaders/gi/probeBake.wgsl.js +635 -0
  225. package/dist/render/shaders/gi/probeTrace.wgsl.d.ts +72 -0
  226. package/dist/render/shaders/gi/probeTrace.wgsl.js +261 -0
  227. package/dist/render/shaders/gi/probeVolume.wgsl.d.ts +49 -0
  228. package/dist/render/shaders/gi/probeVolume.wgsl.js +242 -0
  229. package/dist/render/shaders/gi/sampleField.wgsl.d.ts +32 -0
  230. package/dist/render/shaders/gi/sampleField.wgsl.js +134 -0
  231. package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +26 -0
  232. package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +339 -0
  233. package/dist/render/shaders/gpudriven/compact.wgsl.d.ts +29 -0
  234. package/dist/render/shaders/gpudriven/compact.wgsl.js +58 -0
  235. package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +90 -0
  236. package/dist/render/shaders/gpudriven/cull.wgsl.js +423 -0
  237. package/dist/render/shaders/gpudriven/decode.wgsl.d.ts +72 -0
  238. package/dist/render/shaders/gpudriven/decode.wgsl.js +349 -0
  239. package/dist/render/shaders/gpudriven/environment.wgsl.d.ts +44 -0
  240. package/dist/render/shaders/gpudriven/environment.wgsl.js +137 -0
  241. package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +28 -0
  242. package/dist/render/shaders/gpudriven/fog.wgsl.js +107 -0
  243. package/dist/render/shaders/gpudriven/frameBlock.wgsl.d.ts +13 -0
  244. package/dist/render/shaders/gpudriven/frameBlock.wgsl.js +62 -0
  245. package/dist/render/shaders/gpudriven/materialBin.wgsl.d.ts +51 -0
  246. package/dist/render/shaders/gpudriven/materialBin.wgsl.js +112 -0
  247. package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +25 -0
  248. package/dist/render/shaders/gpudriven/materialTable.wgsl.js +43 -0
  249. package/dist/render/shaders/gpudriven/meshTransform.wgsl.d.ts +18 -0
  250. package/dist/render/shaders/gpudriven/meshTransform.wgsl.js +37 -0
  251. package/dist/render/shaders/gpudriven/present.wgsl.d.ts +43 -0
  252. package/dist/render/shaders/gpudriven/present.wgsl.js +127 -0
  253. package/dist/render/shaders/gpudriven/shade.wgsl.d.ts +127 -0
  254. package/dist/render/shaders/gpudriven/shade.wgsl.js +874 -0
  255. package/dist/render/shaders/gpudriven/shadow.wgsl.d.ts +44 -0
  256. package/dist/render/shaders/gpudriven/shadow.wgsl.js +308 -0
  257. package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.d.ts +28 -0
  258. package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.js +245 -0
  259. package/dist/render/shaders/network.wgsl.d.ts +101 -0
  260. package/dist/render/shaders/network.wgsl.js +206 -0
  261. package/dist/render/shaders/recon/motion.wgsl.d.ts +44 -0
  262. package/dist/render/shaders/recon/motion.wgsl.js +96 -0
  263. package/dist/render/shaders/recon/resolve.wgsl.d.ts +51 -0
  264. package/dist/render/shaders/recon/resolve.wgsl.js +733 -0
  265. package/dist/render/temporalAa.js +8 -33
  266. package/dist/render/textLayout.js +12 -6
  267. package/dist/render/textRenderer.d.ts +3 -1
  268. package/dist/render/textRenderer.js +4 -1
  269. package/dist/render/translucentQueue.d.ts +6 -0
  270. package/dist/render/translucentQueue.js +11 -0
  271. package/dist/render/windStreakRenderer.d.ts +2 -1
  272. package/dist/render/windStreakRenderer.js +3 -1
  273. package/dist/world/cell.d.ts +63 -0
  274. package/dist/world/cell.js +181 -0
  275. package/dist/world/cellStream.d.ts +103 -0
  276. package/dist/world/cellStream.js +198 -0
  277. package/dist/world/freeze.d.ts +81 -0
  278. package/dist/world/freeze.js +114 -0
  279. package/dist/world/rebase.d.ts +29 -0
  280. package/dist/world/rebase.js +41 -0
  281. package/package.json +8 -3
  282. package/scripts/frames.mjs +92 -0
  283. package/scripts/gpuCompute.mjs +323 -0
  284. package/scripts/png.d.mts +16 -0
  285. package/scripts/png.mjs +25 -0
  286. package/src/core/loop.ts +19 -2
  287. package/src/core/storage.ts +5 -0
  288. package/src/geometry/meshBuilder.ts +5 -1
  289. package/src/index.ts +246 -4
  290. package/src/input/input.ts +6 -1
  291. package/src/math/exact.ts +69 -3
  292. package/src/math/frustum.ts +52 -3
  293. package/src/render/backend/api.ts +42 -1
  294. package/src/render/backend/budget.ts +7 -6
  295. package/src/render/backend/createRenderer.ts +92 -3
  296. package/src/render/backend/materialChanges.ts +54 -0
  297. package/src/render/backend/select.ts +8 -0
  298. package/src/render/backend/webgl2/renderer.ts +211 -9
  299. package/src/render/backend/webgpu/buffers.ts +182 -69
  300. package/src/render/backend/webgpu/fieldCompose.ts +482 -0
  301. package/src/render/backend/webgpu/giFieldPass.ts +200 -0
  302. package/src/render/backend/webgpu/gpuDrivenPass.ts +2993 -0
  303. package/src/render/backend/webgpu/linePass.ts +4 -39
  304. package/src/render/backend/webgpu/probeBake.ts +588 -0
  305. package/src/render/backend/webgpu/renderer.ts +1481 -76
  306. package/src/render/backend/webgpu/scatterPass.ts +15 -1
  307. package/src/render/backend/webgpu/surfaceTexturePass.ts +63 -36
  308. package/src/render/causticsRenderer.ts +5 -2
  309. package/src/render/depthConvention.ts +15 -0
  310. package/src/render/deviceFeatures.ts +77 -0
  311. package/src/render/fog.ts +185 -0
  312. package/src/render/frame/alias.ts +97 -0
  313. package/src/render/frame/deps.ts +155 -0
  314. package/src/render/frame/flushGraph.ts +135 -0
  315. package/src/render/frame/graphSchedule.ts +170 -0
  316. package/src/render/frame/index.ts +52 -0
  317. package/src/render/frame/lifetime.ts +61 -0
  318. package/src/render/frame/passTimings.ts +69 -0
  319. package/src/render/frame/validate.ts +40 -0
  320. package/src/render/frame/virtual.ts +91 -0
  321. package/src/render/gi/chain.ts +225 -0
  322. package/src/render/gi/denoise.ts +276 -0
  323. package/src/render/gi/fieldScene.ts +264 -0
  324. package/src/render/gi/globalField.ts +543 -0
  325. package/src/render/gi/probeGridFit.ts +89 -0
  326. package/src/render/gi/probeTrace.ts +143 -0
  327. package/src/render/gi/probeVolume.ts +288 -0
  328. package/src/render/gi/reflection.ts +163 -0
  329. package/src/render/gi/traceField.ts +223 -0
  330. package/src/render/gi/traceScreen.ts +106 -0
  331. package/src/render/gpuScene.ts +80 -0
  332. package/src/render/gpudriven/alphaTest.ts +33 -0
  333. package/src/render/gpudriven/clusterUpload.ts +123 -0
  334. package/src/render/gpudriven/clusterWorld.ts +239 -0
  335. package/src/render/gpudriven/compact.ts +80 -0
  336. package/src/render/gpudriven/cullClusters.ts +333 -0
  337. package/src/render/gpudriven/decodeTables.ts +332 -0
  338. package/src/render/gpudriven/frustum.ts +70 -0
  339. package/src/render/gpudriven/geometryHarness.ts +51 -0
  340. package/src/render/gpudriven/hzb.ts +113 -0
  341. package/src/render/gpudriven/ibl.ts +147 -0
  342. package/src/render/gpudriven/indirect.ts +89 -0
  343. package/src/render/gpudriven/instances.ts +234 -0
  344. package/src/render/gpudriven/lit.ts +329 -0
  345. package/src/render/gpudriven/lodCut.ts +62 -0
  346. package/src/render/gpudriven/materialBin.ts +131 -0
  347. package/src/render/gpudriven/materialTable.ts +164 -0
  348. package/src/render/gpudriven/pipeline.ts +336 -0
  349. package/src/render/gpudriven/rangeAlloc.ts +122 -0
  350. package/src/render/gpudriven/sceneUpload.ts +173 -0
  351. package/src/render/gpudriven/shadeBins.ts +222 -0
  352. package/src/render/gpudriven/shadow.ts +285 -0
  353. package/src/render/gpudriven/shadowCamera.ts +406 -0
  354. package/src/render/gpudriven/streamScene.ts +575 -0
  355. package/src/render/gpudriven/surfaceFrame.ts +68 -0
  356. package/src/render/gpudriven/twoPhase.ts +214 -0
  357. package/src/render/gpudriven/visbuffer.ts +41 -0
  358. package/src/render/halfFloat.ts +22 -4
  359. package/src/render/inference/attentionTiled.ts +132 -0
  360. package/src/render/inference/denseKernels.ts +369 -0
  361. package/src/render/inference/device.ts +44 -0
  362. package/src/render/inference/deviceGraph.ts +39 -0
  363. package/src/render/inference/fuse.ts +47 -0
  364. package/src/render/inference/kernelKit.ts +120 -0
  365. package/src/render/inference/kernels.ts +18 -0
  366. package/src/render/inference/plan.ts +26 -0
  367. package/src/render/inference/reuse.ts +79 -0
  368. package/src/render/inference/runner.ts +204 -0
  369. package/src/render/inference/schedule.ts +80 -0
  370. package/src/render/inference/shapeKernels.ts +112 -0
  371. package/src/render/inference/spatialKernels.ts +220 -0
  372. package/src/render/inference/splatRaster.wgsl.ts +348 -0
  373. package/src/render/inference/splatTiles.ts +186 -0
  374. package/src/render/lineBatch.ts +4 -24
  375. package/src/render/mesh.ts +46 -1
  376. package/src/render/pass.ts +155 -10
  377. package/src/render/prefilterEnvMap.ts +33 -0
  378. package/src/render/readback.ts +73 -0
  379. package/src/render/recon/clamp.ts +113 -0
  380. package/src/render/recon/disocclusion.ts +143 -0
  381. package/src/render/recon/frameGen.ts +191 -0
  382. package/src/render/recon/frameSizes.ts +64 -0
  383. package/src/render/recon/jitter.ts +126 -0
  384. package/src/render/recon/motionVectors.ts +138 -0
  385. package/src/render/recon/reproject.ts +179 -0
  386. package/src/render/recon/resolve.ts +444 -0
  387. package/src/render/recon/tier.ts +31 -0
  388. package/src/render/reflectionProbe.ts +34 -0
  389. package/src/render/renderQuality.ts +87 -0
  390. package/src/render/screenSpaceReflection.ts +37 -3
  391. package/src/render/sdfFont.ts +2 -0
  392. package/src/render/segmentQuads.ts +39 -0
  393. package/src/render/shaders/flat/lobes.ts +35 -3
  394. package/src/render/shaders/flat/preamble.ts +25 -1
  395. package/src/render/shaders/flat/probeGrid.ts +77 -2
  396. package/src/render/shaders/generated/flat.wgsl.ts +64 -24
  397. package/src/render/shaders/gi/composeField.wgsl.ts +239 -0
  398. package/src/render/shaders/gi/marchField.wgsl.ts +146 -0
  399. package/src/render/shaders/gi/probeBake.wgsl.ts +649 -0
  400. package/src/render/shaders/gi/probeTrace.wgsl.ts +269 -0
  401. package/src/render/shaders/gi/probeVolume.wgsl.ts +246 -0
  402. package/src/render/shaders/gi/sampleField.wgsl.ts +140 -0
  403. package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +343 -0
  404. package/src/render/shaders/gpudriven/compact.wgsl.ts +59 -0
  405. package/src/render/shaders/gpudriven/cull.wgsl.ts +433 -0
  406. package/src/render/shaders/gpudriven/decode.wgsl.ts +373 -0
  407. package/src/render/shaders/gpudriven/environment.wgsl.ts +141 -0
  408. package/src/render/shaders/gpudriven/fog.wgsl.ts +110 -0
  409. package/src/render/shaders/gpudriven/frameBlock.wgsl.ts +62 -0
  410. package/src/render/shaders/gpudriven/materialBin.wgsl.ts +116 -0
  411. package/src/render/shaders/gpudriven/materialTable.wgsl.ts +46 -0
  412. package/src/render/shaders/gpudriven/meshTransform.wgsl.ts +37 -0
  413. package/src/render/shaders/gpudriven/present.wgsl.ts +129 -0
  414. package/src/render/shaders/gpudriven/shade.wgsl.ts +884 -0
  415. package/src/render/shaders/gpudriven/shadow.wgsl.ts +322 -0
  416. package/src/render/shaders/gpudriven/visbufferRaster.wgsl.ts +251 -0
  417. package/src/render/shaders/network.wgsl.ts +238 -0
  418. package/src/render/shaders/recon/motion.wgsl.ts +101 -0
  419. package/src/render/shaders/recon/resolve.wgsl.ts +741 -0
  420. package/src/render/temporalAa.ts +9 -33
  421. package/src/render/textLayout.ts +12 -6
  422. package/src/render/textRenderer.ts +5 -2
  423. package/src/render/translucentQueue.ts +11 -0
  424. package/src/render/windStreakRenderer.ts +4 -2
  425. package/src/world/cell.ts +231 -0
  426. package/src/world/cellStream.ts +278 -0
  427. package/src/world/freeze.ts +157 -0
  428. package/src/world/rebase.ts +56 -0
@@ -0,0 +1,125 @@
1
+ /**
2
+ * The frame's declared distance fields — what the renderer's indirect light may be traced against.
3
+ *
4
+ * **A consumer declares this, and the seam is `addOccluder`'s for `addOccluder`'s reason.** A
5
+ * distance field is the shape of a thing it is *safe* to be traced against, and only the consumer
6
+ * knows which of its objects that is true of: the terrain and the walls, not the leaves, not the
7
+ * water, not the thing that is about to be deleted. `quality.occlusionCulling` already makes that
8
+ * sentence about occluders and culls nothing until somebody declares one. This makes it about
9
+ * light, and lights nothing until somebody declares a field.
10
+ *
11
+ * **A field and its placement are separate arguments on purpose.** Forty identical pillars are one
12
+ * baked field and forty matrices: the samples are megabytes and the matrices are bytes. So a source
13
+ * declared twice in a frame is two instances sharing one packed copy of its samples, and the queue
14
+ * is what knows the difference.
15
+ *
16
+ * **The transform is copied and the samples are not.** A consumer holds a matrix and moves it —
17
+ * that is what a matrix is for — so a queue that kept the reference would replay every field
18
+ * wearing the last pose written, which is `DecalQueue`'s recorded mistake and is the dangerous
19
+ * kind: a plausible picture rather than a broken one. A `FieldSource`, by contrast, is baked and
20
+ * does not move, and copying its samples once a frame would move the whole field across the bus to
21
+ * say the same thing.
22
+ *
23
+ * **Records are pooled and never released**, per `AGENTS.md`: `reset` returns the count to zero
24
+ * and keeps the storage, so a steady scene allocates on its first frame and never again.
25
+ */
26
+ import type { ReadonlyMat4 } from 'gl-matrix';
27
+ import type { FieldSource } from './globalField.ts';
28
+ /**
29
+ * How many placed fields one frame may declare.
30
+ *
31
+ * **Thirty-two, which is what `composeGlobalField` was measured against** — 707 ms on the CPU for
32
+ * thirty-two instances over four cascades, and the number the device composition has carried since.
33
+ * The cost is not in the count itself but in the instance buffer being sized once and bound for
34
+ * every cascade's dispatch, so it is a cap rather than a growth.
35
+ */
36
+ export declare const MAX_DISTANCE_FIELDS = 32;
37
+ /**
38
+ * How many samples the frame's distinct sources may add up to, across all of them.
39
+ *
40
+ * Four million floats is sixteen megabytes on the device, which is a 160-cubed field or two
41
+ * hundred 27-cubed ones. **The budget is over the distinct sources rather than the instances**,
42
+ * because that is what is actually uploaded.
43
+ */
44
+ export declare const MAX_DISTANCE_FIELD_SAMPLES: number;
45
+ /** One placed field. `transform` is this queue's own copy; `source` is the consumer's object. */
46
+ export interface DistanceFieldInstance {
47
+ /** The baked field. Shared by reference: it does not move and it is the large thing. */
48
+ source: FieldSource;
49
+ /** World from object, copied at the moment it was declared. Uniform scale only. */
50
+ readonly transform: Float32Array;
51
+ /**
52
+ * What colour this placement's surface is, copied like the transform. White where none was given.
53
+ *
54
+ * **A ray that lands on a wall needs to know what colour it is**, because what leaves a surface
55
+ * is the light arriving times its albedo — and a composed distance field is a union that has
56
+ * already forgotten which instance won. `demo/dev/bounce.html` is what made it necessary: a
57
+ * trace without it returned the same answer for a red wall and a white one.
58
+ *
59
+ * On the placement rather than the field, because the same baked shape is placed many times and
60
+ * two pillars cut from one mould may be painted differently.
61
+ */
62
+ readonly albedo: Float32Array;
63
+ }
64
+ export declare class DistanceFieldScene {
65
+ private readonly pool;
66
+ private count;
67
+ /** The distinct sources of this frame, in the order they were first declared. */
68
+ private readonly distinct;
69
+ /** Where each distinct source's samples start in the packed upload, in floats. */
70
+ private readonly offsets;
71
+ private samples;
72
+ /** The distinct sources of the frame that `reset` last ended, for `packingChanged`. */
73
+ private packed;
74
+ /** Set once when a budget is first reached, so a scene over it says so and then draws. */
75
+ private warnedInstances;
76
+ private warnedSamples;
77
+ /** How many placed fields this frame has recorded. */
78
+ get length(): number;
79
+ /** How many records are pooled, which a test uses to assert a steady scene stops allocating. */
80
+ get capacity(): number;
81
+ /** This frame's distinct sources, in the order their samples are packed. */
82
+ get sources(): readonly FieldSource[];
83
+ /** Floats the packed upload holds — the sum of the distinct sources' fields. */
84
+ get sampleCount(): number;
85
+ /**
86
+ * Whether the samples have to be uploaded again, or the placements alone will do.
87
+ *
88
+ * True when this frame's distinct sources are not the last frame's in the same order, since the
89
+ * offsets are positional. A scene whose fields never change answers false from its second frame
90
+ * on, which is what keeps a sixteen-megabyte upload out of the frame loop.
91
+ */
92
+ get packingChanged(): boolean;
93
+ /** Where a source's samples start in the packed upload, or -1 if it is not in this frame. */
94
+ offsetOf(source: FieldSource): number;
95
+ /**
96
+ * Declare a field, placed.
97
+ *
98
+ * **A source whose samples do not fit is refused whole rather than clipped.** Half a field on the
99
+ * device is not a coarser field; it is a field whose far half reads whatever the buffer held, and
100
+ * that composes as surfaces that are not there — the failure Wave 4A already paid for once, where
101
+ * a phantom surface passed 111,907 parity samples and was found by looking at a picture.
102
+ */
103
+ record(source: FieldSource, model: ReadonlyMat4, albedo?: ArrayLike<number>): void;
104
+ replay(each: (instance: DistanceFieldInstance) => void): void;
105
+ /** Empty it for the next frame, keeping the storage and remembering what was packed. */
106
+ reset(): void;
107
+ }
108
+ /**
109
+ * The world extent of everything a frame declared, into vectors the caller owns.
110
+ *
111
+ * **This is what a probe grid is fitted to when a scene declared none.** A renderer asked for
112
+ * indirect light has to put its probes somewhere, and the only description of the world it holds is
113
+ * the set of fields a consumer said its light may be traced against. That is also the *right*
114
+ * description: a grid sized to include everything drawn would spend its probes on the inside of the
115
+ * sky sphere, while a grid sized to the traceable geometry is a grid around the room.
116
+ *
117
+ * **Every corner is transformed, not the box.** A rotated box's axis-aligned extent is decided by
118
+ * where its corners went; transforming the two extremes and taking their min and max gives a box
119
+ * that is too small wherever a rotation is not a multiple of a quarter turn, and too small is a
120
+ * probe grid that stops short of the wall it is meant to surround.
121
+ *
122
+ * False when the frame declared nothing, rather than an empty box at the origin — which
123
+ * `fitProbeGrid` would answer with a plausible grid of one standing in a place no scene chose.
124
+ */
125
+ export declare function distanceFieldBounds(scene: DistanceFieldScene, min: Float32Array, max: Float32Array): boolean;
@@ -0,0 +1,219 @@
1
+ /**
2
+ * The frame's declared distance fields — what the renderer's indirect light may be traced against.
3
+ *
4
+ * **A consumer declares this, and the seam is `addOccluder`'s for `addOccluder`'s reason.** A
5
+ * distance field is the shape of a thing it is *safe* to be traced against, and only the consumer
6
+ * knows which of its objects that is true of: the terrain and the walls, not the leaves, not the
7
+ * water, not the thing that is about to be deleted. `quality.occlusionCulling` already makes that
8
+ * sentence about occluders and culls nothing until somebody declares one. This makes it about
9
+ * light, and lights nothing until somebody declares a field.
10
+ *
11
+ * **A field and its placement are separate arguments on purpose.** Forty identical pillars are one
12
+ * baked field and forty matrices: the samples are megabytes and the matrices are bytes. So a source
13
+ * declared twice in a frame is two instances sharing one packed copy of its samples, and the queue
14
+ * is what knows the difference.
15
+ *
16
+ * **The transform is copied and the samples are not.** A consumer holds a matrix and moves it —
17
+ * that is what a matrix is for — so a queue that kept the reference would replay every field
18
+ * wearing the last pose written, which is `DecalQueue`'s recorded mistake and is the dangerous
19
+ * kind: a plausible picture rather than a broken one. A `FieldSource`, by contrast, is baked and
20
+ * does not move, and copying its samples once a frame would move the whole field across the bus to
21
+ * say the same thing.
22
+ *
23
+ * **Records are pooled and never released**, per `AGENTS.md`: `reset` returns the count to zero
24
+ * and keeps the storage, so a steady scene allocates on its first frame and never again.
25
+ */
26
+ import { assertCubicVoxels } from './globalField.js';
27
+ /**
28
+ * How many placed fields one frame may declare.
29
+ *
30
+ * **Thirty-two, which is what `composeGlobalField` was measured against** — 707 ms on the CPU for
31
+ * thirty-two instances over four cascades, and the number the device composition has carried since.
32
+ * The cost is not in the count itself but in the instance buffer being sized once and bound for
33
+ * every cascade's dispatch, so it is a cap rather than a growth.
34
+ */
35
+ export const MAX_DISTANCE_FIELDS = 32;
36
+ /**
37
+ * How many samples the frame's distinct sources may add up to, across all of them.
38
+ *
39
+ * Four million floats is sixteen megabytes on the device, which is a 160-cubed field or two
40
+ * hundred 27-cubed ones. **The budget is over the distinct sources rather than the instances**,
41
+ * because that is what is actually uploaded.
42
+ */
43
+ export const MAX_DISTANCE_FIELD_SAMPLES = 1 << 22;
44
+ function newRecord() {
45
+ return {
46
+ source: EMPTY_SOURCE,
47
+ transform: new Float32Array(16),
48
+ albedo: Float32Array.from([1, 1, 1]),
49
+ };
50
+ }
51
+ /** A placeholder a pooled record holds before its first use, so `source` is never null. */
52
+ const EMPTY_SOURCE = {
53
+ field: new Float32Array(0),
54
+ dims: [0, 0, 0],
55
+ bounds: new Float32Array(6),
56
+ };
57
+ export class DistanceFieldScene {
58
+ pool = [];
59
+ count = 0;
60
+ /** The distinct sources of this frame, in the order they were first declared. */
61
+ distinct = [];
62
+ /** Where each distinct source's samples start in the packed upload, in floats. */
63
+ offsets = new Map();
64
+ samples = 0;
65
+ /** The distinct sources of the frame that `reset` last ended, for `packingChanged`. */
66
+ packed = [];
67
+ /** Set once when a budget is first reached, so a scene over it says so and then draws. */
68
+ warnedInstances = false;
69
+ warnedSamples = false;
70
+ /** How many placed fields this frame has recorded. */
71
+ get length() {
72
+ return this.count;
73
+ }
74
+ /** How many records are pooled, which a test uses to assert a steady scene stops allocating. */
75
+ get capacity() {
76
+ return this.pool.length;
77
+ }
78
+ /** This frame's distinct sources, in the order their samples are packed. */
79
+ get sources() {
80
+ return this.distinct;
81
+ }
82
+ /** Floats the packed upload holds — the sum of the distinct sources' fields. */
83
+ get sampleCount() {
84
+ return this.samples;
85
+ }
86
+ /**
87
+ * Whether the samples have to be uploaded again, or the placements alone will do.
88
+ *
89
+ * True when this frame's distinct sources are not the last frame's in the same order, since the
90
+ * offsets are positional. A scene whose fields never change answers false from its second frame
91
+ * on, which is what keeps a sixteen-megabyte upload out of the frame loop.
92
+ */
93
+ get packingChanged() {
94
+ if (this.distinct.length !== this.packed.length)
95
+ return true;
96
+ for (let i = 0; i < this.distinct.length; i += 1) {
97
+ if (this.distinct[i] !== this.packed[i])
98
+ return true;
99
+ }
100
+ return false;
101
+ }
102
+ /** Where a source's samples start in the packed upload, or -1 if it is not in this frame. */
103
+ offsetOf(source) {
104
+ return this.offsets.get(source) ?? -1;
105
+ }
106
+ /**
107
+ * Declare a field, placed.
108
+ *
109
+ * **A source whose samples do not fit is refused whole rather than clipped.** Half a field on the
110
+ * device is not a coarser field; it is a field whose far half reads whatever the buffer held, and
111
+ * that composes as surfaces that are not there — the failure Wave 4A already paid for once, where
112
+ * a phantom surface passed 111,907 parity samples and was found by looking at a picture.
113
+ */
114
+ record(source, model, albedo) {
115
+ /*
116
+ * **Before anything else, because a malformed source is not a budget.** The two warnings below
117
+ * are a frame asking for more than it can carry and dropping the surplus is the honest answer;
118
+ * there is none to a source the composer cannot read. The renderer composes on the device and
119
+ * never reaches `composeGlobalField`, so its own check protects only the reference path.
120
+ */
121
+ assertCubicVoxels(source);
122
+ if (this.count >= MAX_DISTANCE_FIELDS) {
123
+ if (!this.warnedInstances) {
124
+ this.warnedInstances = true;
125
+ console.warn(`driftengine: more than ${MAX_DISTANCE_FIELDS} distance fields were declared in one ` +
126
+ 'frame, so the rest are not traced against. Fields that never move are cheaper baked ' +
127
+ 'into one source, which is composed as a single instance.');
128
+ }
129
+ return;
130
+ }
131
+ const known = this.offsets.get(source);
132
+ if (known === undefined) {
133
+ if (this.samples + source.field.length > MAX_DISTANCE_FIELD_SAMPLES) {
134
+ if (!this.warnedSamples) {
135
+ this.warnedSamples = true;
136
+ console.warn(`driftengine: the frame's distance fields exceed ${MAX_DISTANCE_FIELD_SAMPLES} ` +
137
+ 'samples, so this one is not traced against at all. A field composed in part reads ' +
138
+ 'whatever the buffer held beyond it, which is surfaces that are not there.');
139
+ }
140
+ return;
141
+ }
142
+ this.offsets.set(source, this.samples);
143
+ this.distinct.push(source);
144
+ this.samples += source.field.length;
145
+ }
146
+ let record = this.pool[this.count];
147
+ if (record === undefined) {
148
+ record = newRecord();
149
+ this.pool.push(record);
150
+ }
151
+ record.source = source;
152
+ for (let at = 0; at < 16; at += 1)
153
+ record.transform[at] = model[at] ?? 0;
154
+ /* Copied like the transform, and white where none was declared. */
155
+ for (let at = 0; at < 3; at += 1)
156
+ record.albedo[at] = albedo?.[at] ?? 1;
157
+ this.count += 1;
158
+ }
159
+ replay(each) {
160
+ for (let i = 0; i < this.count; i += 1) {
161
+ const record = this.pool[i];
162
+ if (record !== undefined)
163
+ each(record);
164
+ }
165
+ }
166
+ /** Empty it for the next frame, keeping the storage and remembering what was packed. */
167
+ reset() {
168
+ this.packed = this.distinct.slice();
169
+ this.count = 0;
170
+ this.distinct.length = 0;
171
+ this.offsets.clear();
172
+ this.samples = 0;
173
+ }
174
+ }
175
+ /**
176
+ * The world extent of everything a frame declared, into vectors the caller owns.
177
+ *
178
+ * **This is what a probe grid is fitted to when a scene declared none.** A renderer asked for
179
+ * indirect light has to put its probes somewhere, and the only description of the world it holds is
180
+ * the set of fields a consumer said its light may be traced against. That is also the *right*
181
+ * description: a grid sized to include everything drawn would spend its probes on the inside of the
182
+ * sky sphere, while a grid sized to the traceable geometry is a grid around the room.
183
+ *
184
+ * **Every corner is transformed, not the box.** A rotated box's axis-aligned extent is decided by
185
+ * where its corners went; transforming the two extremes and taking their min and max gives a box
186
+ * that is too small wherever a rotation is not a multiple of a quarter turn, and too small is a
187
+ * probe grid that stops short of the wall it is meant to surround.
188
+ *
189
+ * False when the frame declared nothing, rather than an empty box at the origin — which
190
+ * `fitProbeGrid` would answer with a plausible grid of one standing in a place no scene chose.
191
+ */
192
+ export function distanceFieldBounds(scene, min, max) {
193
+ if (scene.length === 0)
194
+ return false;
195
+ for (let axis = 0; axis < 3; axis += 1) {
196
+ min[axis] = Infinity;
197
+ max[axis] = -Infinity;
198
+ }
199
+ scene.replay((instance) => {
200
+ const box = instance.source.bounds;
201
+ const m = instance.transform;
202
+ for (let corner = 0; corner < 8; corner += 1) {
203
+ const x = box[(corner & 1) === 0 ? 0 : 3];
204
+ const y = box[(corner & 2) === 0 ? 1 : 4];
205
+ const z = box[(corner & 4) === 0 ? 2 : 5];
206
+ for (let axis = 0; axis < 3; axis += 1) {
207
+ const value = m[axis] * x +
208
+ m[4 + axis] * y +
209
+ m[8 + axis] * z +
210
+ m[12 + axis];
211
+ if (value < min[axis])
212
+ min[axis] = value;
213
+ if (value > max[axis])
214
+ max[axis] = value;
215
+ }
216
+ }
217
+ });
218
+ return true;
219
+ }
@@ -0,0 +1,157 @@
1
+ /** The world near the camera as one distance field, assembled from the objects standing in it. */
2
+ import type { ReadonlyMat4, ReadonlyVec3 } from 'gl-matrix';
3
+ import type { Vec3 } from '../../math/color.ts';
4
+ /**
5
+ * A baked object field, as this package can describe one.
6
+ *
7
+ * **Structural rather than imported**, because `@driftengine/core` does not depend on
8
+ * `@driftengine/assets` and must not start: the baker is a build step and this is a frame. What
9
+ * `bakeObjectSdf` returns satisfies this shape, and so does what `readSdfv` hands back from a
10
+ * container. That is the arrangement `Terrain` already has with `Heightfield` across the physics
11
+ * boundary and `DTEX` has with `@driftengine/texture` across the container one.
12
+ */
13
+ export interface FieldSource {
14
+ /** Distance in metres, negative inside. `x` fastest, then `y`, then `z`. */
15
+ readonly field: Float32Array;
16
+ readonly dims: readonly [number, number, number];
17
+ /** The field's own extent in **object** space, `[minX, minY, minZ, maxX, maxY, maxZ]`. */
18
+ readonly bounds: Float32Array;
19
+ }
20
+ export interface GlobalFieldInstance {
21
+ readonly source: FieldSource;
22
+ /**
23
+ * What colour this instance's surface is, or white where it did not say.
24
+ *
25
+ * On the instance rather than the source, because the same baked field is placed many times and
26
+ * two pillars cut from one mould may be painted differently. Optional so that every caller
27
+ * written before the trace needed a colour is unchanged.
28
+ */
29
+ readonly albedo?: Vec3;
30
+ /**
31
+ * World from object.
32
+ *
33
+ * **Uniform scale only, and `composeGlobalField` refuses the rest rather than approximating.**
34
+ * A distance is not preserved by a non-uniform scale: the factor to correct by depends on the
35
+ * direction to the nearest surface, which is exactly what a distance field does not record. An
36
+ * instance squashed on one axis and sampled anyway produces something that is a distance in no
37
+ * direction and looks like one in every slice.
38
+ */
39
+ readonly transform: ReadonlyMat4;
40
+ }
41
+ /** One level of the clipmap: a grid the composer fills and `sampleGlobalField` reads. */
42
+ export interface GlobalFieldCascade {
43
+ readonly field: Float32Array;
44
+ /**
45
+ * The colour of whatever surface won the union at each sample, three floats a sample.
46
+ *
47
+ * **A union loses which instance won, and a ray that lands on a wall needs to know what colour
48
+ * it is.** `demo/dev/bounce.html` is what made this necessary: a trace whose radiance came from
49
+ * a rasterised capture could not follow a wall that changed colour, and one that read the probe
50
+ * volume's irradiance returned the same answer for a red wall and a white one — irradiance is
51
+ * light arriving, and what leaves a surface is that times its albedo.
52
+ *
53
+ * **White where no instance reached**, rather than black: the colour of a sample no ray can hit
54
+ * is never read, and black would turn a read that did happen into light quietly vanishing
55
+ * instead of a picture that is obviously wrong.
56
+ */
57
+ readonly albedo: Float32Array;
58
+ readonly dims: readonly [number, number, number];
59
+ /** Where this cascade stands, written by `composeGlobalField`. Six floats. */
60
+ readonly bounds: Float32Array;
61
+ /** Metres between samples, the same on all three axes. Written by `composeGlobalField`. */
62
+ step: number;
63
+ }
64
+ /**
65
+ * The composed world, as nested cascades centred on the camera.
66
+ *
67
+ * **A clipmap and not a sparse brick tree, which is a smaller claim than the plan made and is
68
+ * what is here.** Fine near the viewer and coarse further out is the requirement, and nesting
69
+ * grids of equal sample count at doubling extents meets it exactly: cascade 0 resolves a room and
70
+ * cascade 3 resolves a district, at one allocation each and no indirection to traverse. What a
71
+ * brick tree buys on top is *memory* — skipping the volume no surface is near — and nothing yet
72
+ * measured says this needs it. `traceField.ts` will say, because it is the thing that pays.
73
+ */
74
+ export interface GlobalField {
75
+ /** Finest first. Each is twice the reach and twice the step of the one before it. */
76
+ readonly cascades: readonly GlobalFieldCascade[];
77
+ }
78
+ /**
79
+ * How much of a cascade's extent, at each face, fades into the cascade outside it.
80
+ *
81
+ * **A hard switch between cascades is worse than either cascade's own error.** An error that is
82
+ * wrong everywhere reads as a coarse solution; one that changes abruptly along a surface reads as
83
+ * a crack, and the crack moves with the camera because the boundary does. A tenth of the extent
84
+ * is wide enough that the fade is below a voxel per step and narrow enough that the inner
85
+ * cascade's resolution is what most of the inner cascade actually delivers.
86
+ */
87
+ export declare const GLOBAL_FIELD_BLEND = 0.1;
88
+ /** Allocate a field. Called once; `composeGlobalField` fills it and allocates nothing. */
89
+ export declare function createGlobalField(resolution: number, cascades: number): GlobalField;
90
+ /**
91
+ * Put one cascade where the camera is, and answer its half-extent.
92
+ *
93
+ * **Exported because the compute path needs the same placement and two spellings drift.** A pass
94
+ * filling these on a device has to agree with this about where every cascade stands, to the last
95
+ * bit: disagree by a fraction of a step and the fade between cascades lands somewhere different on
96
+ * each side, which is a seam that appears only when both paths are compared.
97
+ *
98
+ * The snapping is the decision. See `composeGlobalField` for why a grid centred on the exact camera
99
+ * position makes the whole field shimmer.
100
+ */
101
+ export declare function placeCascade(cascade: GlobalFieldCascade, level: number, radius: number, cameraPos: ReadonlyVec3): number;
102
+ /**
103
+ * Fill every cascade from the instances standing near the camera.
104
+ *
105
+ * `radius` is the innermost cascade's half-extent in metres; each cascade outside it reaches twice
106
+ * as far at the same sample count.
107
+ *
108
+ * **Every cascade's centre is snapped to a multiple of its own step, and that is the decision this
109
+ * function exists to make.** A grid centred on the exact camera position resamples the entire
110
+ * world at a new sub-pixel offset every frame, so every value changes slightly every frame and the
111
+ * indirect light shimmers — worst on a slow camera, which is exactly when a viewer is looking at
112
+ * it. Snapped, a camera move is either nothing at all or a whole voxel, and a whole voxel leaves
113
+ * every sample the two grids share bit-identical.
114
+ *
115
+ * **A point no instance is near takes the cascade's own reach rather than infinity.** That is an
116
+ * underestimate of the true distance, which is the safe direction: a march that steps by it takes
117
+ * a shorter step than it could and converges anyway, where an overestimate steps through the wall
118
+ * it was meant to stop at.
119
+ *
120
+ * **This is the reference, and it visits every sample of every cascade for every instance that is
121
+ * not culled outright.** `scripts/gpu-parity.mjs` is the pattern the WGSL will be checked against,
122
+ * and the WGSL is where the brick culling belongs — a CPU implementation that was already
123
+ * accelerated would be a second thing to be wrong rather than the thing the first is checked by.
124
+ */
125
+ export declare function composeGlobalField(instances: readonly GlobalFieldInstance[], cameraPos: ReadonlyVec3, radius: number, out: GlobalField): void;
126
+ /**
127
+ * The field at a world point, from the finest cascade that holds it.
128
+ *
129
+ * A point past every cascade reads the outermost one clamped to its edge, rather than a sentinel:
130
+ * a caller marching outward wants a number it can step by, and the outermost cascade's own reach
131
+ * is the honest one.
132
+ */
133
+ export declare function sampleGlobalField(field: GlobalField, x: number, y: number, z: number): number;
134
+ /**
135
+ * Refuse a source whose voxels are not cubic, which `sourceAt` and the shader both assume.
136
+ *
137
+ * **One step for all three axes is the contract, and it was unwritten until it cost a feature.**
138
+ * `bakeObjectSdf` picks its step from the object's longest axis and gives each axis whatever count
139
+ * it needs at that step, so `dims` differ per axis and the spacing does not. Both readers rely on
140
+ * that: `sourceAt` here derives the step from x alone, and `composeField.wgsl.ts` says so in a
141
+ * comment. A source sampled with the same count on every axis of a box that is not a cube has
142
+ * oblong voxels, and every sample of it is taken at the wrong place along y and z — far enough
143
+ * wrong that a point at the centre of a slab reads the slab's corner.
144
+ *
145
+ * **Measured on `demo/dev/bounce.html`**, whose room is five such slabs: the composed field held
146
+ * almost no room, 98.9% of every probe's rays left a closed room, and the traced bounce delivered a
147
+ * thirty-fifth of the light. Nothing failed; the field was simply empty. Refusing is the only
148
+ * honest answer, because a distance field carries no record of the axis it was sampled along and
149
+ * there is nothing here to correct it with — the same reason a non-uniform scale is refused above.
150
+ *
151
+ * **An axis of one sample is refused here too, and by its own sentence**, because `read` addresses
152
+ * `index` and `index + 1` on every axis and cannot be given an axis with no pair. `bakeObjectSdf`
153
+ * never produces one — its counts are a ceiling plus one over a span that includes two voxels of
154
+ * padding — but `FieldSource` is a shape a consumer may build by hand, which is the whole reason
155
+ * this function exists.
156
+ */
157
+ export declare function assertCubicVoxels(source: FieldSource): void;