@driftengine/core 3.62.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 +122 -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 +70 -4
  9. package/dist/index.js +123 -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 +47 -14
  42. package/dist/render/backend/webgpu/surfaceTexturePass.js +128 -80
  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 +261 -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 +158 -88
  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
@@ -1,4 +1,5 @@
1
1
  import { mat4 } from 'gl-matrix';
2
+ import { jitterTable } from './recon/jitter.js';
2
3
  /**
3
4
  * The sub-pixel sequence a temporal resolve samples along, and the state that says whether there
4
5
  * is anything to resolve *against* yet.
@@ -33,44 +34,18 @@ export const JITTER_PERIOD = 8;
33
34
  */
34
35
  export const TEMPORAL_HISTORY_BLEND = 0.9;
35
36
  /**
36
- * The radical inverse of `index` in `base`, which is what makes a Halton sequence fill a gap
37
- * before it fills a corner.
37
+ * The period's offsets, centred so they sum to zero — `recon/jitter.ts`'s sequence at eight phases.
38
38
  *
39
- * Consecutive samples land as far from each other as the base allows, so eight of them cover the
40
- * pixel evenly where eight random ones would leave holes and pairs.
39
+ * **One sequence for the temporal resolve and for reconstruction**, and these are the numbers the
40
+ * resolve has always used: Halton in bases two and three, each period centred on its own mean,
41
+ * because accumulating towards an off-centre mean resolves to a picture displaced from the depth
42
+ * it was tested against.
41
43
  */
42
- function halton(index, base) {
43
- let result = 0;
44
- let fraction = 1;
45
- let i = index;
46
- while (i > 0) {
47
- fraction /= base;
48
- result += fraction * (i % base);
49
- i = Math.floor(i / base);
50
- }
51
- return result;
52
- }
53
- /**
54
- * The period's offsets, centred so they sum to zero.
55
- *
56
- * **Halton's own mean is not the middle of the pixel** — over eight samples base two averages
57
- * 0.445 rather than 0.5 — and accumulating towards a mean that is off centre resolves to a picture
58
- * displaced from the depth buffer it was tested against and from every pass that did not jitter.
59
- * Subtracting the period's own mean costs nothing and makes the property exact rather than
60
- * approximate, which is what lets the test assert it.
61
- */
62
- const OFFSETS = (() => {
63
- const raw = [];
64
- for (let i = 1; i <= JITTER_PERIOD; i++)
65
- raw.push([halton(i, 2), halton(i, 3)]);
66
- const meanX = raw.reduce((sum, o) => sum + o[0], 0) / JITTER_PERIOD;
67
- const meanY = raw.reduce((sum, o) => sum + o[1], 0) / JITTER_PERIOD;
68
- return raw.map(([x, y]) => [x - meanX, y - meanY]);
69
- })();
44
+ const OFFSETS = jitterTable(JITTER_PERIOD);
70
45
  /** Where in its pixel frame `frameIndex` samples, in pixels, centred on zero. */
71
46
  export function jitterOffset(frameIndex) {
72
47
  const at = ((frameIndex % JITTER_PERIOD) + JITTER_PERIOD) % JITTER_PERIOD;
73
- return OFFSETS[at];
48
+ return [OFFSETS[at * 2], OFFSETS[at * 2 + 1]];
74
49
  }
75
50
  /**
76
51
  * `source` shifted by `offsetX`, `offsetY` pixels on a `width` by `height` target.
@@ -180,13 +180,19 @@ function buildCube() {
180
180
  for (const face of faces) {
181
181
  const [a, b, c, d] = face.corners;
182
182
  /*
183
- * Wound clockwise, which is backwards — deliberately. The vertex shader flips Y to put the
184
- * origin at the top left, and a mirror reverses winding, so faces authored the usual way
185
- * come out back-facing and every one of them is culled. The symptom is text that renders
186
- * with no GL error and no pixels, which is a genuinely difficult thing to look at and
187
- * diagnose.
183
+ * **Wound the usual way, and it was wound backwards on purpose until 2026-09-16.**
184
+ *
185
+ * The comment that stood here said the vertex shader's Y flip mirrors the winding, so faces
186
+ * authored the usual way "come out back-facing and every one of them is culled". Measured on
187
+ * both backends, that is not what happens: with the usual winding both draw solid glyphs, and
188
+ * with the reversed one **WebGL2 draws a one-pixel sliver of every cell** while WebGPU draws
189
+ * them solid. The text on the default backend has been a dotted outline of itself.
190
+ *
191
+ * It survived because it is legible. A reader sees letters; only a capture beside the other
192
+ * backend says the cells are hollow, and `demo/dev/overlay.html` is where that comparison is
193
+ * cheap — 7,678 lit pixels against 14,982 for the same string.
188
194
  */
189
- for (const corner of [a, c, b, a, d, c]) {
195
+ for (const corner of [a, b, c, a, c, d]) {
190
196
  positions.push(corner[0], corner[1], corner[2]);
191
197
  normals.push(face.normal[0], face.normal[1], face.normal[2]);
192
198
  }
@@ -22,8 +22,10 @@ export declare class TextRenderer {
22
22
  /**
23
23
  * @param originX left edge, in pixels from the left of the viewport.
24
24
  * @param originY baseline, in pixels from the top.
25
+ *
26
+ * Answers whether it drew, which the renderer counts on its frame budget.
25
27
  */
26
- draw(viewportWidth: number, viewportHeight: number, originX: number, originY: number, style: TextStyle, timeSec: number): void;
28
+ draw(viewportWidth: number, viewportHeight: number, originX: number, originY: number, style: TextStyle, timeSec: number): boolean;
27
29
  dispose(): void;
28
30
  /** Both instance buffers, from the arrays the layout filled in place. */
29
31
  private upload;
@@ -63,10 +63,12 @@ export class TextRenderer {
63
63
  /**
64
64
  * @param originX left edge, in pixels from the left of the viewport.
65
65
  * @param originY baseline, in pixels from the top.
66
+ *
67
+ * Answers whether it drew, which the renderer counts on its frame budget.
66
68
  */
67
69
  draw(viewportWidth, viewportHeight, originX, originY, style, timeSec) {
68
70
  if (this.layout.instanceCount === 0 || style.alpha <= 0)
69
- return;
71
+ return false;
70
72
  const gl = this.gl;
71
73
  gl.useProgram(this.program);
72
74
  gl.bindVertexArray(this.vao);
@@ -122,6 +124,7 @@ export class TextRenderer {
122
124
  }
123
125
  gl.drawArraysInstanced(gl.TRIANGLES, 0, TEXT_CUBE.vertexCount, this.layout.instanceCount);
124
126
  gl.bindVertexArray(null);
127
+ return true;
125
128
  }
126
129
  dispose() {
127
130
  const gl = this.gl;
@@ -50,8 +50,14 @@ export interface TranslucentDraw {
50
50
  export declare class TranslucentQueue {
51
51
  private readonly pool;
52
52
  private count;
53
+ private refracting;
53
54
  /** How many draws this frame has recorded. */
54
55
  get length(): number;
56
+ /**
57
+ * Whether anything recorded this frame refracts, so a backend replaying the set knows to copy the
58
+ * frame behind it first, and does not copy it for a set that never reads it.
59
+ */
60
+ get refracts(): boolean;
55
61
  /** How many records are pooled, which a test uses to assert a steady scene stops allocating. */
56
62
  get capacity(): number;
57
63
  /**
@@ -19,10 +19,18 @@ function newRecord() {
19
19
  export class TranslucentQueue {
20
20
  pool = [];
21
21
  count = 0;
22
+ refracting = 0;
22
23
  /** How many draws this frame has recorded. */
23
24
  get length() {
24
25
  return this.count;
25
26
  }
27
+ /**
28
+ * Whether anything recorded this frame refracts, so a backend replaying the set knows to copy the
29
+ * frame behind it first, and does not copy it for a set that never reads it.
30
+ */
31
+ get refracts() {
32
+ return this.refracting > 0;
33
+ }
26
34
  /** How many records are pooled, which a test uses to assert a steady scene stops allocating. */
27
35
  get capacity() {
28
36
  return this.pool.length;
@@ -57,6 +65,8 @@ export class TranslucentQueue {
57
65
  record.tint = record.tintStore;
58
66
  }
59
67
  record.refraction = options.refraction ?? 0;
68
+ if (record.refraction > 0)
69
+ this.refracting++;
60
70
  record.thicknessM = options.thicknessM ?? 0;
61
71
  const refractTint = options.refractTint ?? null;
62
72
  if (refractTint === null) {
@@ -86,5 +96,6 @@ export class TranslucentQueue {
86
96
  /** Empty it for the next frame, keeping the storage. */
87
97
  reset() {
88
98
  this.count = 0;
99
+ this.refracting = 0;
89
100
  }
90
101
  }
@@ -30,8 +30,9 @@ export declare class WindStreakRenderer {
30
30
  strengthFor(speed: number): number;
31
31
  /** Refilled per call rather than allocated; this is a per-frame path. */
32
32
  private readonly resolved;
33
+ /** Answers whether it drew, which the renderer counts on its frame budget. */
33
34
  draw(gl: WebGL2RenderingContext, camera: FrameView, wind: WindField, timeSeconds: number, tint: Vec3,
34
35
  /** True when the camera is below the waterline. */
35
- submerged?: boolean): void;
36
+ submerged?: boolean): boolean;
36
37
  dispose(gl: WebGL2RenderingContext): void;
37
38
  }
@@ -47,13 +47,14 @@ export class WindStreakRenderer {
47
47
  }
48
48
  /** Refilled per call rather than allocated; this is a per-frame path. */
49
49
  resolved = createResolvedWindStreaks();
50
+ /** Answers whether it drew, which the renderer counts on its frame budget. */
50
51
  draw(gl, camera, wind, timeSeconds, tint,
51
52
  /** True when the camera is below the waterline. */
52
53
  submerged = false) {
53
54
  /* Chosen in `windStreakDraw.ts` so both backends show the same weather. */
54
55
  const settled = resolveWindStreaks(wind.speed, wind.driftX, wind.driftZ, this.onsetSpeed, this.fullSpeed, submerged, this.resolved);
55
56
  if (!settled.visible)
56
- return;
57
+ return false;
57
58
  const u = this.uniforms;
58
59
  gl.useProgram(this.program);
59
60
  gl.uniformMatrix4fv(u['uViewProj'] ?? null, false, camera.viewProjection);
@@ -76,6 +77,7 @@ export class WindStreakRenderer {
76
77
  gl.enable(gl.CULL_FACE);
77
78
  gl.depthMask(true);
78
79
  gl.disable(gl.BLEND);
80
+ return true;
79
81
  }
80
82
  dispose(gl) {
81
83
  for (const buffer of this.buffers)
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The world as a sparse grid of cells: the unit that streams, freezes and rebases.
3
+ *
4
+ * **A position on a boundary belongs to exactly one cell, and which one is decided by `Math.floor`
5
+ * rather than by rounding.** Both sides, or neither, are the two ways this goes wrong, and both
6
+ * present as an entity that flickers between cells while standing still — which then flickers
7
+ * between loaded and unloaded.
8
+ *
9
+ * **Negative coordinates work.** A naive bit-packing of the grid coordinate breaks below zero and
10
+ * the symptom is a world that is fine in one quadrant, which is the quadrant anybody tests in.
11
+ */
12
+ /** The grid coordinate a world coordinate falls in. */
13
+ export declare function cellCoord(value: number, size: number): number;
14
+ /** Whether these grid coordinates fit the packing. See `AXIS_BITS` for the range. */
15
+ export declare function cellCoordInRange(c: number): boolean;
16
+ /**
17
+ * Pack grid coordinates into one identifier.
18
+ *
19
+ * **Out of range throws rather than wrapping**, and the reason is what wrapping does: a coordinate
20
+ * past the bias produces an identifier belonging to a different, real cell, so two distant places
21
+ * in the world silently become the same cell. That is a corruption with no symptom near where it
22
+ * happened. This is a streaming-time path, not a per-vertex one, so the check costs nothing that
23
+ * matters.
24
+ */
25
+ export declare function cellIdFrom(cx: number, cy: number, cz: number): number;
26
+ export declare function cellIdFor(x: number, y: number, z: number, size: number): number;
27
+ export declare function cellCoordsOf(id: number, out: Int32Array): void;
28
+ /** Minimum corner and size, in world units. */
29
+ export declare function cellBounds(id: number, size: number, out: Float64Array): void;
30
+ /**
31
+ * Every cell within `radius` of a point, appended to `out`.
32
+ *
33
+ * Symmetric about the centre and conservative: a cell the sphere merely touches is included,
34
+ * because the cost of an extra cell is a wasted load and the cost of a missing one is a hole.
35
+ */
36
+ export declare function cellsInRadius(x: number, y: number, z: number, radius: number, size: number, out: number[]): number;
37
+ /**
38
+ * The grid a query walks: its cell, and the most cells one query may walk.
39
+ *
40
+ * **The limit is stated rather than discovered.** A view's frustum is bounded by its far plane, and
41
+ * a far plane a thousand cells away is a million-cell walk per predicted frame — a frame-time cliff
42
+ * that looks like a hang. A query that would walk more than `maxCells` refuses and says how many.
43
+ */
44
+ export interface CellGrid {
45
+ /** Cell edge length, world units. */
46
+ readonly size: number;
47
+ readonly maxCells: number;
48
+ }
49
+ export declare function createCellGrid(size: number, maxCells?: number): CellGrid;
50
+ /**
51
+ * Every cell the view looks into, into `out`, in coordinate order. Returns how many.
52
+ *
53
+ * `viewProj` is column-major and OpenGL-convention, as `gl-matrix` builds one, and in absolute
54
+ * world units — **in double precision if the world is past 2^24**, because a plane's offset out there
55
+ * is not a number a single float holds to the metre.
56
+ *
57
+ * **Conservative, as `cellsInRadius` is**: a cell is left out only when it lies wholly beyond one of
58
+ * the view's planes, so every point the view can see is in a returned cell, and a cell near a
59
+ * corner of the view can be returned without being seen. The cells walked are those inside the
60
+ * box round the view's eight corners, which is why a view with no far plane is refused: its box has
61
+ * no far side.
62
+ */
63
+ export declare function cellsInFrustum(grid: CellGrid, viewProj: ArrayLike<number>, out: number[]): number;
@@ -0,0 +1,181 @@
1
+ /**
2
+ * The world as a sparse grid of cells: the unit that streams, freezes and rebases.
3
+ *
4
+ * **A position on a boundary belongs to exactly one cell, and which one is decided by `Math.floor`
5
+ * rather than by rounding.** Both sides, or neither, are the two ways this goes wrong, and both
6
+ * present as an entity that flickers between cells while standing still — which then flickers
7
+ * between loaded and unloaded.
8
+ *
9
+ * **Negative coordinates work.** A naive bit-packing of the grid coordinate breaks below zero and
10
+ * the symptom is a world that is fine in one quadrant, which is the quadrant anybody tests in.
11
+ */
12
+ import { mat4 } from 'gl-matrix';
13
+ import { boxInFrustum, frustumFromViewProjection } from '../math/frustum.js';
14
+ /**
15
+ * Bits per axis in a packed cell identifier.
16
+ *
17
+ * Seventeen gives ±65,536 cells an axis, and three of them multiply to 2.25e15 — inside the
18
+ * 9.01e15 an integer stays exact in a double. At a 256-metre cell that is ±16,777 km an axis,
19
+ * which is more world than anybody has; at one metre it is still ±65 km.
20
+ */
21
+ const AXIS_BITS = 17;
22
+ const AXIS_SPAN = 1 << AXIS_BITS;
23
+ const AXIS_BIAS = AXIS_SPAN >> 1;
24
+ /** The grid coordinate a world coordinate falls in. */
25
+ export function cellCoord(value, size) {
26
+ return Math.floor(value / size);
27
+ }
28
+ /** Whether these grid coordinates fit the packing. See `AXIS_BITS` for the range. */
29
+ export function cellCoordInRange(c) {
30
+ return Number.isInteger(c) && c >= -AXIS_BIAS && c < AXIS_BIAS;
31
+ }
32
+ /**
33
+ * Pack grid coordinates into one identifier.
34
+ *
35
+ * **Out of range throws rather than wrapping**, and the reason is what wrapping does: a coordinate
36
+ * past the bias produces an identifier belonging to a different, real cell, so two distant places
37
+ * in the world silently become the same cell. That is a corruption with no symptom near where it
38
+ * happened. This is a streaming-time path, not a per-vertex one, so the check costs nothing that
39
+ * matters.
40
+ */
41
+ export function cellIdFrom(cx, cy, cz) {
42
+ if (!cellCoordInRange(cx) || !cellCoordInRange(cy) || !cellCoordInRange(cz)) {
43
+ throw new RangeError(`cell coordinate (${cx}, ${cy}, ${cz}) is outside the ±${AXIS_BIAS} the packing holds`);
44
+ }
45
+ const x = cx + AXIS_BIAS;
46
+ const y = cy + AXIS_BIAS;
47
+ const z = cz + AXIS_BIAS;
48
+ /* Multiplication rather than shifts: a shift in JavaScript is 32-bit and would wrap here. */
49
+ return (x * AXIS_SPAN + y) * AXIS_SPAN + z;
50
+ }
51
+ export function cellIdFor(x, y, z, size) {
52
+ return cellIdFrom(cellCoord(x, size), cellCoord(y, size), cellCoord(z, size));
53
+ }
54
+ export function cellCoordsOf(id, out) {
55
+ const z = id % AXIS_SPAN;
56
+ const rest = (id - z) / AXIS_SPAN;
57
+ const y = rest % AXIS_SPAN;
58
+ const x = (rest - y) / AXIS_SPAN;
59
+ out[0] = x - AXIS_BIAS;
60
+ out[1] = y - AXIS_BIAS;
61
+ out[2] = z - AXIS_BIAS;
62
+ }
63
+ const COORDS = new Int32Array(3);
64
+ /** Minimum corner and size, in world units. */
65
+ export function cellBounds(id, size, out) {
66
+ cellCoordsOf(id, COORDS);
67
+ out[0] = COORDS[0] * size;
68
+ out[1] = COORDS[1] * size;
69
+ out[2] = COORDS[2] * size;
70
+ out[3] = size;
71
+ }
72
+ /**
73
+ * Every cell within `radius` of a point, appended to `out`.
74
+ *
75
+ * Symmetric about the centre and conservative: a cell the sphere merely touches is included,
76
+ * because the cost of an extra cell is a wasted load and the cost of a missing one is a hole.
77
+ */
78
+ export function cellsInRadius(x, y, z, radius, size, out) {
79
+ out.length = 0;
80
+ const lo = [
81
+ cellCoord(x - radius, size),
82
+ cellCoord(y - radius, size),
83
+ cellCoord(z - radius, size),
84
+ ];
85
+ const hi = [
86
+ cellCoord(x + radius, size),
87
+ cellCoord(y + radius, size),
88
+ cellCoord(z + radius, size),
89
+ ];
90
+ for (let cx = lo[0]; cx <= hi[0]; cx += 1) {
91
+ for (let cy = lo[1]; cy <= hi[1]; cy += 1) {
92
+ for (let cz = lo[2]; cz <= hi[2]; cz += 1) {
93
+ out.push(cellIdFrom(cx, cy, cz));
94
+ }
95
+ }
96
+ }
97
+ return out.length;
98
+ }
99
+ export function createCellGrid(size, maxCells = 65_536) {
100
+ if (!(size > 0 && size < Infinity)) {
101
+ throw new RangeError(`a cell of ${String(size)} units is not a cell`);
102
+ }
103
+ if (!(Number.isInteger(maxCells) && maxCells >= 1)) {
104
+ throw new RangeError(`a limit of ${String(maxCells)} cells is not a limit`);
105
+ }
106
+ return { size, maxCells };
107
+ }
108
+ /* Double precision throughout: a world past 2^24 units is what this grid is for. */
109
+ const PLANES = new Float64Array(24);
110
+ const INVERSE = new Float64Array(16);
111
+ const CORNER_LOW = new Float64Array(3);
112
+ const CORNER_HIGH = new Float64Array(3);
113
+ /**
114
+ * Every cell the view looks into, into `out`, in coordinate order. Returns how many.
115
+ *
116
+ * `viewProj` is column-major and OpenGL-convention, as `gl-matrix` builds one, and in absolute
117
+ * world units — **in double precision if the world is past 2^24**, because a plane's offset out there
118
+ * is not a number a single float holds to the metre.
119
+ *
120
+ * **Conservative, as `cellsInRadius` is**: a cell is left out only when it lies wholly beyond one of
121
+ * the view's planes, so every point the view can see is in a returned cell, and a cell near a
122
+ * corner of the view can be returned without being seen. The cells walked are those inside the
123
+ * box round the view's eight corners, which is why a view with no far plane is refused: its box has
124
+ * no far side.
125
+ */
126
+ export function cellsInFrustum(grid, viewProj, out) {
127
+ out.length = 0;
128
+ const matrix = viewProj;
129
+ if (mat4.invert(INVERSE, matrix) === null) {
130
+ throw new RangeError('cellsInFrustum: a view with no inverse has no far plane to bound it');
131
+ }
132
+ CORNER_LOW.fill(Infinity);
133
+ CORNER_HIGH.fill(-Infinity);
134
+ for (let corner = 0; corner < 8; corner += 1) {
135
+ const x = corner & 1 ? 1 : -1;
136
+ const y = corner & 2 ? 1 : -1;
137
+ const z = corner & 4 ? 1 : -1;
138
+ const m = INVERSE;
139
+ const w = m[3] * x + m[7] * y + m[11] * z + m[15];
140
+ /*
141
+ * A corner at or behind the eye's plane is a corner at infinity: the view has no far side.
142
+ * **This is the only check the corners need.** A lens deep enough for a corner to overflow has
143
+ * its far plane at infinity in double precision, where this is exactly zero, and a matrix small
144
+ * enough to overflow its inverse has a determinant that has already underflowed to none.
145
+ */
146
+ if (!(w > 0)) {
147
+ throw new RangeError('cellsInFrustum: a view whose far plane is at infinity bounds no cells');
148
+ }
149
+ for (let axis = 0; axis < 3; axis += 1) {
150
+ const value = (m[axis] * x +
151
+ m[4 + axis] * y +
152
+ m[8 + axis] * z +
153
+ m[12 + axis]) /
154
+ w;
155
+ CORNER_LOW[axis] = Math.min(CORNER_LOW[axis], value);
156
+ CORNER_HIGH[axis] = Math.max(CORNER_HIGH[axis], value);
157
+ }
158
+ }
159
+ const size = grid.size;
160
+ const x0 = cellCoord(CORNER_LOW[0], size);
161
+ const y0 = cellCoord(CORNER_LOW[1], size);
162
+ const z0 = cellCoord(CORNER_LOW[2], size);
163
+ const x1 = cellCoord(CORNER_HIGH[0], size);
164
+ const y1 = cellCoord(CORNER_HIGH[1], size);
165
+ const z1 = cellCoord(CORNER_HIGH[2], size);
166
+ const span = (x1 - x0 + 1) * (y1 - y0 + 1) * (z1 - z0 + 1);
167
+ if (span > grid.maxCells) {
168
+ throw new RangeError(`cellsInFrustum: this view spans ${String(span)} cells, more than the ${String(grid.maxCells)} its grid allows`);
169
+ }
170
+ frustumFromViewProjection(matrix, PLANES);
171
+ for (let cx = x0; cx <= x1; cx += 1) {
172
+ for (let cy = y0; cy <= y1; cy += 1) {
173
+ for (let cz = z0; cz <= z1; cz += 1) {
174
+ if (boxInFrustum(PLANES, cx * size, cy * size, cz * size, (cx + 1) * size, (cy + 1) * size, (cz + 1) * size)) {
175
+ out.push(cellIdFrom(cx, cy, cz));
176
+ }
177
+ }
178
+ }
179
+ }
180
+ return out.length;
181
+ }
@@ -0,0 +1,103 @@
1
+ import type { CellGrid } from './cell.ts';
2
+ /** What a stream needs of whatever holds a cell's contents. */
3
+ export interface CellStore {
4
+ loaded(id: number): boolean;
5
+ /** Begin loading. Lower `priority` is sooner, matching the queue's convention. */
6
+ load(id: number, priority: number): void;
7
+ unload(id: number): void;
8
+ }
9
+ export interface CellStreamOptions {
10
+ readonly store: CellStore;
11
+ /** Cell edge length, world units. */
12
+ readonly size: number;
13
+ /** How far around a view cells are wanted. */
14
+ readonly radius: number;
15
+ /** How many pumps a cell may go unwanted before it is dropped. */
16
+ readonly hysteresis: number;
17
+ /** The render origin the predicted views are relative to. Absent means the world origin. */
18
+ readonly origin?: ArrayLike<number>;
19
+ /**
20
+ * The projection the predicted views are drawn through. With it, a stream also wants the cells
21
+ * those views look into, out to its far plane; without it, only the cells within `radius`.
22
+ */
23
+ readonly projection?: ArrayLike<number>;
24
+ /** The most cells one view's query may walk. See `CellGrid`. */
25
+ readonly maxCells?: number;
26
+ }
27
+ export interface CellStream {
28
+ readonly store: CellStore;
29
+ readonly size: number;
30
+ readonly radius: number;
31
+ readonly hysteresis: number;
32
+ /**
33
+ * Where the predicted views' origin is, in absolute world coordinates.
34
+ *
35
+ * **A view matrix is `Float32Array`, and that is why this exists.** `runPrediction` writes views
36
+ * into single precision — which is right, because a view matrix is what a renderer takes — and
37
+ * single precision stops resolving whole metres past 2²⁴. A world larger than that cannot put an
38
+ * absolute position through one: at 2²⁵ the spacing is four metres, so the camera position
39
+ * recovered from the matrix is wrong by up to two. Streaming survives it, because
40
+ * `cellsInRadius` is conservative and four metres against a five-hundred-metre cell only ever
41
+ * adds a cell — but it is wrong, and it is wrong in exactly the place this mechanism exists for.
42
+ *
43
+ * So the views are render-space, relative to this, and the stream adds it back. Zero by default,
44
+ * which is what every consumer that fits inside single precision already had.
45
+ */
46
+ readonly origin: Float64Array;
47
+ /** Cell identifier to the frame it was last wanted. What the hysteresis counts against. */
48
+ readonly lastWanted: Map<number, number>;
49
+ /** Pumps so far. Monotonic, and the only clock this has. */
50
+ frame: number;
51
+ readonly grid: CellGrid;
52
+ /**
53
+ * The caller's own array, read on every predicted frame — so a lens that zooms or pulls its far
54
+ * plane in is followed without telling the stream.
55
+ */
56
+ readonly projection: ArrayLike<number> | null;
57
+ }
58
+ export declare function createCellStream(options: CellStreamOptions): CellStream;
59
+ /**
60
+ * Move the origin the predicted views are relative to.
61
+ *
62
+ * Called with whatever `renderOrigin` answered for this frame, so the two cannot drift apart. It is
63
+ * a write rather than a parameter to `needs` because the predictor's shape is `Predictor<number>`
64
+ * and that interface is Wave 3B's, shared with texture tiles, which have no origin.
65
+ */
66
+ export declare function setCellStreamOrigin(stream: CellStream, x: number, y: number, z: number): void;
67
+ /**
68
+ * Where the camera is, out of a view matrix, into `out`.
69
+ *
70
+ * **A view matrix is `R · T(−p)`, so its translation column is in *view* space** and negating it is
71
+ * right only while the camera is unrotated. The camera's world position is `−Rᵀ · t`, and the
72
+ * transpose is the inverse because a view rotation is orthonormal. Getting this wrong is invisible
73
+ * in any test whose camera is not turned, and wrong by the whole camera offset in every other.
74
+ *
75
+ * Column-major, as `gl-matrix` writes one: `m[0..2]` is the first column.
76
+ */
77
+ export declare function cameraPositionFrom(view: ArrayLike<number>, out: Float64Array): void;
78
+ /**
79
+ * The stream as a `Predictor<number>` over cell identifiers.
80
+ *
81
+ * Structurally typed on purpose — see the header. A caller passes the result straight to
82
+ * `runPrediction` from `@driftengine/texture`.
83
+ */
84
+ export declare function cellPredictor(stream: CellStream): {
85
+ needs(view: Float32Array, out: number[], budget: number): number;
86
+ resident(id: number): boolean;
87
+ request(id: number, priority: number): void;
88
+ };
89
+ /**
90
+ * Mark what is in range *now*, then drop what has gone unwanted long enough. Returns how many went.
91
+ *
92
+ * **The pump marks as well as drops, and the first draft only dropped.** Prediction marks what is
93
+ * coming; without the pump marking what is here, a camera standing still wants nothing — its
94
+ * predicted path never leaves the cell it is in, the horizon moves past every cell it already
95
+ * occupies, and the streamer unloads the ground somebody is standing on. That is not a case to
96
+ * guard against separately: it is the same question as "what does this camera want", asked about
97
+ * the present instead of the future.
98
+ *
99
+ * So there is no special case for the camera's own cell. `cellsInRadius` includes it at any
100
+ * radius, including zero, which means the guarantee follows from the marking rather than from a
101
+ * check somebody could delete without a test failing.
102
+ */
103
+ export declare function pumpCellStream(stream: CellStream, x: number, y: number, z: number): number;