@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,56 @@
1
+ /** Composing the world's distance field, on the device, because 707 ms is not a frame. */
2
+ /**
3
+ * **This is the only version of `composeGlobalField` that can run in a frame.**
4
+ *
5
+ * The TypeScript in `gi/globalField.ts` is the reference and says so in its own header: it visits
6
+ * every sample of every cascade for every instance it cannot cull outright, deliberately, because
7
+ * a reference that was already accelerated would be a second thing to be wrong rather than the
8
+ * thing the first is checked by. Measured by `scripts/gi-schemes.mjs`, that costs **707 ms a
9
+ * frame** for 32 instances over four cascades of 65 cubed — 35 million inverse transforms and
10
+ * trilinear reads, which is exactly the shape a GPU is for and exactly the shape a CPU is not.
11
+ *
12
+ * **One invocation a sample, and no culling at all.** The reference culls an instance further from
13
+ * a cascade than that cascade's reach, and the measurement that justified it there — 19.4 ms
14
+ * against 150.2 — is a statement about a serial loop. Here every sample is already parallel, so
15
+ * what the cull would save is a branch per instance per thread and what it would cost is a
16
+ * divergent one. It is left out, and `scripts/gi-parity.mjs` is what proves that changes no answer:
17
+ * the cull cannot change a result, only the time taken to reach it, because a culled instance is
18
+ * one whose contribution the minimum would have discarded.
19
+ *
20
+ * **The layouts are the reference's, restated rather than shared, and that is the hazard.** A
21
+ * shader and a TypeScript function cannot import a struct from each other, so the eight-corner
22
+ * blend below and `read()` in `globalField.ts` are two spellings of one decision. `gi-parity.mjs`
23
+ * runs both over generated input and compares every sample, which is the arrangement
24
+ * `gpu-parity.mjs` established for exactly this reason.
25
+ */
26
+ /** Floats per instance in the `instances` buffer. See `INSTANCE_*` below for what they are. */
27
+ export declare const COMPOSE_INSTANCE_FLOATS = 32;
28
+ /** Where each field of an instance record starts, in floats. */
29
+ export declare const INSTANCE_INVERSE = 0;
30
+ export declare const INSTANCE_SCALE = 16;
31
+ export declare const INSTANCE_BOUNDS = 17;
32
+ export declare const INSTANCE_DIMS = 23;
33
+ export declare const INSTANCE_OFFSET = 26;
34
+ /** The instance's own colour, three floats. White where a consumer declared none. */
35
+ export declare const INSTANCE_ALBEDO = 28;
36
+ /**
37
+ * Floats in the `params` buffer: cascade origin, step, dims, reach, instance count, output base.
38
+ *
39
+ * **Every cascade has its own copy, at its own 256-byte-aligned offset.** `queue.writeBuffer` is a
40
+ * queue operation and is not ordered against the commands of an encoder, so rewriting one params
41
+ * buffer between dispatches gives every dispatch the *last* write — three cascades composed with
42
+ * the outermost one's origin and step, which looks like a field that is simply wrong everywhere.
43
+ */
44
+ export declare const COMPOSE_PARAM_FLOATS = 12;
45
+ /** Where a cascade's samples start in the shared output, in floats. `params[9]`. */
46
+ export declare const COMPOSE_OUTPUT_BASE = 9;
47
+ /**
48
+ * Bytes between one cascade's params and the next.
49
+ *
50
+ * A storage binding's offset must be a multiple of `minStorageBufferOffsetAlignment`, which is 256
51
+ * on every device this targets — the same limit the GPU-driven pyramid's levels are padded to.
52
+ */
53
+ export declare const COMPOSE_PARAM_STRIDE = 256;
54
+ /** Invocations a workgroup. 64 is this backend's default everywhere else. */
55
+ export declare const COMPOSE_WORKGROUP = 64;
56
+ export declare const COMPOSE_FIELD_WGSL = "\nstruct Params {\n originX: f32,\n originY: f32,\n originZ: f32,\n step: f32,\n countX: f32,\n countY: f32,\n countZ: f32,\n reach: f32,\n instances: f32,\n padA: f32,\n padB: f32,\n padC: f32,\n};\n\n@group(0) @binding(0) var<storage, read> params: array<f32>;\n@group(0) @binding(1) var<storage, read> instances: array<f32>;\n@group(0) @binding(2) var<storage, read> sources: array<f32>;\n@group(0) @binding(3) var<storage, read_write> field: array<f32>;\n/* The colour of whatever won the union at each sample, three floats. See GlobalFieldCascade. */\n@group(0) @binding(4) var<storage, read_write> albedo: array<f32>;\n\n/*\n * The eight-corner blend of one object's field, at a point already in that object's space.\n *\n * Clamped at the grid's edge, exactly as the reference is: a sample past the last plane takes that\n * plane rather than extrapolating, and the index stops one short so the pair it interpolates\n * between is always inside.\n */\nfn sourceAt(base: u32, bounds0: vec3<f32>, bounds1: vec3<f32>, dims: vec3<f32>, p: vec3<f32>) -> f32 {\n /* One step for all three axes, because an object's voxels are cubic. bakeObjectSdf is why. */\n let step = (bounds1.x - bounds0.x) / (dims.x - 1.0);\n\n var low = vec3<f32>(0.0, 0.0, 0.0);\n var frac = vec3<f32>(0.0, 0.0, 0.0);\n for (var axis = 0u; axis < 3u; axis = axis + 1u) {\n let count = dims[axis];\n let local = (p[axis] - bounds0[axis]) / step;\n let clamped = clamp(local, 0.0, count - 1.0);\n let index = min(floor(clamped), count - 2.0);\n low[axis] = index;\n frac[axis] = clamped - index;\n }\n\n let nx = u32(dims.x);\n let ny = u32(dims.y);\n let lx = u32(low.x);\n let ly = u32(low.y);\n let lz = u32(low.z);\n\n var total = 0.0;\n for (var cz = 0u; cz < 2u; cz = cz + 1u) {\n let wz = select(1.0 - frac.z, frac.z, cz == 1u);\n for (var cy = 0u; cy < 2u; cy = cy + 1u) {\n let wy = select(1.0 - frac.y, frac.y, cy == 1u);\n for (var cx = 0u; cx < 2u; cx = cx + 1u) {\n let wx = select(1.0 - frac.x, frac.x, cx == 1u);\n let at = lx + cx + nx * (ly + cy + ny * (lz + cz));\n total = total + sources[base + at] * wx * wy * wz;\n }\n }\n }\n return total;\n}\n\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) id: vec3<u32>) {\n let countX = u32(params[4]);\n let countY = u32(params[5]);\n let countZ = u32(params[6]);\n let total = countX * countY * countZ;\n let index = id.x;\n if (index >= total) {\n return;\n }\n\n let ix = index % countX;\n let iy = (index / countX) % countY;\n let iz = index / (countX * countY);\n let step = params[3];\n let world = vec3<f32>(\n params[0] + f32(ix) * step,\n params[1] + f32(iy) * step,\n params[2] + f32(iz) * step,\n );\n\n /* The reach, which is both the initial value and a bound on what any instance can lower it to. */\n var best = params[7];\n /* White, so a sample no instance reached is neutral rather than a light that vanishes. */\n var bestAlbedo = vec3<f32>(1.0, 1.0, 1.0);\n let instanceCount = u32(params[8]);\n\n for (var i = 0u; i < instanceCount; i = i + 1u) {\n let base = i * 32u;\n\n /*\n * The world point carried into the object's space through the **inverse**. Column-major, the\n * order gl-matrix stores a matrix in, which is the order the reference reads it in too.\n */\n let object = vec3<f32>(\n instances[base + 0u] * world.x + instances[base + 4u] * world.y + instances[base + 8u] * world.z + instances[base + 12u],\n instances[base + 1u] * world.x + instances[base + 5u] * world.y + instances[base + 9u] * world.z + instances[base + 13u],\n instances[base + 2u] * world.x + instances[base + 6u] * world.y + instances[base + 10u] * world.z + instances[base + 14u],\n );\n\n let scale = instances[base + 16u];\n let bounds0 = vec3<f32>(\n instances[base + 17u],\n instances[base + 17u + 1u],\n instances[base + 17u + 2u],\n );\n let bounds1 = vec3<f32>(\n instances[base + 17u + 3u],\n instances[base + 17u + 4u],\n instances[base + 17u + 5u],\n );\n\n /*\n * **Outside the source's box, bounded two ways and the larger taken.** The distance to the box\n * alone is a true bound and a useless one: just outside it says zero, so a sphere trace stops\n * on a phantom shell around every instance. d(q) >= d(c) - |q - c| by the triangle\n * inequality, against the field's own value at the nearest point of the box, is the bound that\n * reports the real clearance. See sampleInstance in globalField.ts.\n */\n let clamped = clamp(object, bounds0, bounds1);\n let outside = length(object - clamped);\n\n var distance = 0.0;\n if (outside > 0.0) {\n let dims = vec3<f32>(\n instances[base + 23u],\n instances[base + 23u + 1u],\n instances[base + 23u + 2u],\n );\n let sourceBase = u32(instances[base + 26u]);\n let atBox = sourceAt(sourceBase, bounds0, bounds1, dims, clamped);\n distance = max(outside, atBox - outside) * scale;\n } else {\n let dims = vec3<f32>(\n instances[base + 23u],\n instances[base + 23u + 1u],\n instances[base + 23u + 2u],\n );\n let sourceBase = u32(instances[base + 26u]);\n distance = sourceAt(sourceBase, bounds0, bounds1, dims, object) * scale;\n }\n\n /*\n * **The minimum, because the union of two solids is the nearer surface** \u2014 and the colour goes\n * with it rather than beside it. Writing the albedo unconditionally would paint every sample\n * with whichever instance happened to come last, which is a field of the right shape in the\n * wrong colours and looks like a lighting bug rather than a composition one.\n */\n if (distance < best) {\n best = distance;\n bestAlbedo = vec3<f32>(\n instances[base + 28u],\n instances[base + 28u + 1u],\n instances[base + 28u + 2u],\n );\n }\n }\n\n /*\n * **Into this cascade's own region of one shared buffer.** Without the base every cascade writes\n * the same samples and the last one wins, which reads as a field that has only its outermost\n * level \u2014 the innermost detail simply absent, at the resolution a viewer is closest to.\n */\n field[u32(params[9]) + index] = best;\n let colourAt = (u32(params[9]) + index) * 3u;\n albedo[colourAt] = bestAlbedo.x;\n albedo[colourAt + 1u] = bestAlbedo.y;\n albedo[colourAt + 2u] = bestAlbedo.z;\n}\n";
@@ -0,0 +1,231 @@
1
+ /** Composing the world's distance field, on the device, because 707 ms is not a frame. */
2
+ /**
3
+ * **This is the only version of `composeGlobalField` that can run in a frame.**
4
+ *
5
+ * The TypeScript in `gi/globalField.ts` is the reference and says so in its own header: it visits
6
+ * every sample of every cascade for every instance it cannot cull outright, deliberately, because
7
+ * a reference that was already accelerated would be a second thing to be wrong rather than the
8
+ * thing the first is checked by. Measured by `scripts/gi-schemes.mjs`, that costs **707 ms a
9
+ * frame** for 32 instances over four cascades of 65 cubed — 35 million inverse transforms and
10
+ * trilinear reads, which is exactly the shape a GPU is for and exactly the shape a CPU is not.
11
+ *
12
+ * **One invocation a sample, and no culling at all.** The reference culls an instance further from
13
+ * a cascade than that cascade's reach, and the measurement that justified it there — 19.4 ms
14
+ * against 150.2 — is a statement about a serial loop. Here every sample is already parallel, so
15
+ * what the cull would save is a branch per instance per thread and what it would cost is a
16
+ * divergent one. It is left out, and `scripts/gi-parity.mjs` is what proves that changes no answer:
17
+ * the cull cannot change a result, only the time taken to reach it, because a culled instance is
18
+ * one whose contribution the minimum would have discarded.
19
+ *
20
+ * **The layouts are the reference's, restated rather than shared, and that is the hazard.** A
21
+ * shader and a TypeScript function cannot import a struct from each other, so the eight-corner
22
+ * blend below and `read()` in `globalField.ts` are two spellings of one decision. `gi-parity.mjs`
23
+ * runs both over generated input and compares every sample, which is the arrangement
24
+ * `gpu-parity.mjs` established for exactly this reason.
25
+ */
26
+ /** Floats per instance in the `instances` buffer. See `INSTANCE_*` below for what they are. */
27
+ export const COMPOSE_INSTANCE_FLOATS = 32;
28
+ /** Where each field of an instance record starts, in floats. */
29
+ export const INSTANCE_INVERSE = 0;
30
+ export const INSTANCE_SCALE = 16;
31
+ export const INSTANCE_BOUNDS = 17;
32
+ export const INSTANCE_DIMS = 23;
33
+ export const INSTANCE_OFFSET = 26;
34
+ /** The instance's own colour, three floats. White where a consumer declared none. */
35
+ export const INSTANCE_ALBEDO = 28;
36
+ /**
37
+ * Floats in the `params` buffer: cascade origin, step, dims, reach, instance count, output base.
38
+ *
39
+ * **Every cascade has its own copy, at its own 256-byte-aligned offset.** `queue.writeBuffer` is a
40
+ * queue operation and is not ordered against the commands of an encoder, so rewriting one params
41
+ * buffer between dispatches gives every dispatch the *last* write — three cascades composed with
42
+ * the outermost one's origin and step, which looks like a field that is simply wrong everywhere.
43
+ */
44
+ export const COMPOSE_PARAM_FLOATS = 12;
45
+ /** Where a cascade's samples start in the shared output, in floats. `params[9]`. */
46
+ export const COMPOSE_OUTPUT_BASE = 9;
47
+ /**
48
+ * Bytes between one cascade's params and the next.
49
+ *
50
+ * A storage binding's offset must be a multiple of `minStorageBufferOffsetAlignment`, which is 256
51
+ * on every device this targets — the same limit the GPU-driven pyramid's levels are padded to.
52
+ */
53
+ export const COMPOSE_PARAM_STRIDE = 256;
54
+ /** Invocations a workgroup. 64 is this backend's default everywhere else. */
55
+ export const COMPOSE_WORKGROUP = 64;
56
+ export const COMPOSE_FIELD_WGSL = /* wgsl */ `
57
+ struct Params {
58
+ originX: f32,
59
+ originY: f32,
60
+ originZ: f32,
61
+ step: f32,
62
+ countX: f32,
63
+ countY: f32,
64
+ countZ: f32,
65
+ reach: f32,
66
+ instances: f32,
67
+ padA: f32,
68
+ padB: f32,
69
+ padC: f32,
70
+ };
71
+
72
+ @group(0) @binding(0) var<storage, read> params: array<f32>;
73
+ @group(0) @binding(1) var<storage, read> instances: array<f32>;
74
+ @group(0) @binding(2) var<storage, read> sources: array<f32>;
75
+ @group(0) @binding(3) var<storage, read_write> field: array<f32>;
76
+ /* The colour of whatever won the union at each sample, three floats. See GlobalFieldCascade. */
77
+ @group(0) @binding(4) var<storage, read_write> albedo: array<f32>;
78
+
79
+ /*
80
+ * The eight-corner blend of one object's field, at a point already in that object's space.
81
+ *
82
+ * Clamped at the grid's edge, exactly as the reference is: a sample past the last plane takes that
83
+ * plane rather than extrapolating, and the index stops one short so the pair it interpolates
84
+ * between is always inside.
85
+ */
86
+ fn sourceAt(base: u32, bounds0: vec3<f32>, bounds1: vec3<f32>, dims: vec3<f32>, p: vec3<f32>) -> f32 {
87
+ /* One step for all three axes, because an object's voxels are cubic. bakeObjectSdf is why. */
88
+ let step = (bounds1.x - bounds0.x) / (dims.x - 1.0);
89
+
90
+ var low = vec3<f32>(0.0, 0.0, 0.0);
91
+ var frac = vec3<f32>(0.0, 0.0, 0.0);
92
+ for (var axis = 0u; axis < 3u; axis = axis + 1u) {
93
+ let count = dims[axis];
94
+ let local = (p[axis] - bounds0[axis]) / step;
95
+ let clamped = clamp(local, 0.0, count - 1.0);
96
+ let index = min(floor(clamped), count - 2.0);
97
+ low[axis] = index;
98
+ frac[axis] = clamped - index;
99
+ }
100
+
101
+ let nx = u32(dims.x);
102
+ let ny = u32(dims.y);
103
+ let lx = u32(low.x);
104
+ let ly = u32(low.y);
105
+ let lz = u32(low.z);
106
+
107
+ var total = 0.0;
108
+ for (var cz = 0u; cz < 2u; cz = cz + 1u) {
109
+ let wz = select(1.0 - frac.z, frac.z, cz == 1u);
110
+ for (var cy = 0u; cy < 2u; cy = cy + 1u) {
111
+ let wy = select(1.0 - frac.y, frac.y, cy == 1u);
112
+ for (var cx = 0u; cx < 2u; cx = cx + 1u) {
113
+ let wx = select(1.0 - frac.x, frac.x, cx == 1u);
114
+ let at = lx + cx + nx * (ly + cy + ny * (lz + cz));
115
+ total = total + sources[base + at] * wx * wy * wz;
116
+ }
117
+ }
118
+ }
119
+ return total;
120
+ }
121
+
122
+ @compute @workgroup_size(${COMPOSE_WORKGROUP})
123
+ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
124
+ let countX = u32(params[4]);
125
+ let countY = u32(params[5]);
126
+ let countZ = u32(params[6]);
127
+ let total = countX * countY * countZ;
128
+ let index = id.x;
129
+ if (index >= total) {
130
+ return;
131
+ }
132
+
133
+ let ix = index % countX;
134
+ let iy = (index / countX) % countY;
135
+ let iz = index / (countX * countY);
136
+ let step = params[3];
137
+ let world = vec3<f32>(
138
+ params[0] + f32(ix) * step,
139
+ params[1] + f32(iy) * step,
140
+ params[2] + f32(iz) * step,
141
+ );
142
+
143
+ /* The reach, which is both the initial value and a bound on what any instance can lower it to. */
144
+ var best = params[7];
145
+ /* White, so a sample no instance reached is neutral rather than a light that vanishes. */
146
+ var bestAlbedo = vec3<f32>(1.0, 1.0, 1.0);
147
+ let instanceCount = u32(params[8]);
148
+
149
+ for (var i = 0u; i < instanceCount; i = i + 1u) {
150
+ let base = i * ${COMPOSE_INSTANCE_FLOATS}u;
151
+
152
+ /*
153
+ * The world point carried into the object's space through the **inverse**. Column-major, the
154
+ * order gl-matrix stores a matrix in, which is the order the reference reads it in too.
155
+ */
156
+ let object = vec3<f32>(
157
+ instances[base + 0u] * world.x + instances[base + 4u] * world.y + instances[base + 8u] * world.z + instances[base + 12u],
158
+ instances[base + 1u] * world.x + instances[base + 5u] * world.y + instances[base + 9u] * world.z + instances[base + 13u],
159
+ instances[base + 2u] * world.x + instances[base + 6u] * world.y + instances[base + 10u] * world.z + instances[base + 14u],
160
+ );
161
+
162
+ let scale = instances[base + ${INSTANCE_SCALE}u];
163
+ let bounds0 = vec3<f32>(
164
+ instances[base + ${INSTANCE_BOUNDS}u],
165
+ instances[base + ${INSTANCE_BOUNDS}u + 1u],
166
+ instances[base + ${INSTANCE_BOUNDS}u + 2u],
167
+ );
168
+ let bounds1 = vec3<f32>(
169
+ instances[base + ${INSTANCE_BOUNDS}u + 3u],
170
+ instances[base + ${INSTANCE_BOUNDS}u + 4u],
171
+ instances[base + ${INSTANCE_BOUNDS}u + 5u],
172
+ );
173
+
174
+ /*
175
+ * **Outside the source's box, bounded two ways and the larger taken.** The distance to the box
176
+ * alone is a true bound and a useless one: just outside it says zero, so a sphere trace stops
177
+ * on a phantom shell around every instance. d(q) >= d(c) - |q - c| by the triangle
178
+ * inequality, against the field's own value at the nearest point of the box, is the bound that
179
+ * reports the real clearance. See sampleInstance in globalField.ts.
180
+ */
181
+ let clamped = clamp(object, bounds0, bounds1);
182
+ let outside = length(object - clamped);
183
+
184
+ var distance = 0.0;
185
+ if (outside > 0.0) {
186
+ let dims = vec3<f32>(
187
+ instances[base + 23u],
188
+ instances[base + 23u + 1u],
189
+ instances[base + 23u + 2u],
190
+ );
191
+ let sourceBase = u32(instances[base + 26u]);
192
+ let atBox = sourceAt(sourceBase, bounds0, bounds1, dims, clamped);
193
+ distance = max(outside, atBox - outside) * scale;
194
+ } else {
195
+ let dims = vec3<f32>(
196
+ instances[base + ${INSTANCE_DIMS}u],
197
+ instances[base + ${INSTANCE_DIMS}u + 1u],
198
+ instances[base + ${INSTANCE_DIMS}u + 2u],
199
+ );
200
+ let sourceBase = u32(instances[base + ${INSTANCE_OFFSET}u]);
201
+ distance = sourceAt(sourceBase, bounds0, bounds1, dims, object) * scale;
202
+ }
203
+
204
+ /*
205
+ * **The minimum, because the union of two solids is the nearer surface** — and the colour goes
206
+ * with it rather than beside it. Writing the albedo unconditionally would paint every sample
207
+ * with whichever instance happened to come last, which is a field of the right shape in the
208
+ * wrong colours and looks like a lighting bug rather than a composition one.
209
+ */
210
+ if (distance < best) {
211
+ best = distance;
212
+ bestAlbedo = vec3<f32>(
213
+ instances[base + ${INSTANCE_ALBEDO}u],
214
+ instances[base + ${INSTANCE_ALBEDO}u + 1u],
215
+ instances[base + ${INSTANCE_ALBEDO}u + 2u],
216
+ );
217
+ }
218
+ }
219
+
220
+ /*
221
+ * **Into this cascade's own region of one shared buffer.** Without the base every cascade writes
222
+ * the same samples and the last one wins, which reads as a field that has only its outermost
223
+ * level — the innermost detail simply absent, at the resolution a viewer is closest to.
224
+ */
225
+ field[u32(params[9]) + index] = best;
226
+ let colourAt = (u32(params[9]) + index) * 3u;
227
+ albedo[colourAt] = bestAlbedo.x;
228
+ albedo[colourAt + 1u] = bestAlbedo.y;
229
+ albedo[colourAt + 2u] = bestAlbedo.z;
230
+ }
231
+ `;
@@ -0,0 +1,30 @@
1
+ /** The composed field, drawn — so a pass that fills one can be looked at rather than trusted. */
2
+ /**
3
+ * **A visualisation, and it is the honest first consumer of the field.**
4
+ *
5
+ * What Wave 4A's chain is eventually for is indirect light in the shading path, and that is a far
6
+ * larger integration than a pass. What a pass can do now is prove the composition runs on a device
7
+ * and say what it costs — and a distance field is a thing you can *see*, by sphere-tracing it from
8
+ * the camera. If the geometry in the picture is the geometry in the scene, in the right places and
9
+ * the right sizes, the composition is right; if a cascade boundary shows as a seam, the fade is
10
+ * wrong. Neither is available from a number.
11
+ *
12
+ * That is what `DRAFT_SCENES` is for, and it is the same shape the GPU-driven pipeline's three rigs
13
+ * took: a second path drawn beside the first, measured, and kept out of the published set until
14
+ * what it draws is the whole material.
15
+ *
16
+ * **The march is `traceField.ts`'s, minus the cone.** Step by the field's own value, which is a
17
+ * distance nothing can be nearer than; stop where it falls under an epsilon; give up where the ray
18
+ * leaves the outermost cascade, because past that there is no information and stepping on a clamped
19
+ * value converges on the boundary and reports a surface made of nothing.
20
+ */
21
+ /** Floats in the march's params: the inverse view-projection, the eye, and four scalars. */
22
+ export declare const MARCH_PARAM_FLOATS = 24;
23
+ /** Where each field starts. `INV_VIEW_PROJ` is column-major, as `gl-matrix` stores it. */
24
+ export declare const MARCH_INV_VIEW_PROJ = 0;
25
+ export declare const MARCH_EYE = 16;
26
+ export declare const MARCH_LEVELS = 20;
27
+ export declare const MARCH_SIDE = 21;
28
+ export declare const MARCH_STEPS = 22;
29
+ export declare const MARCH_EPSILON = 23;
30
+ export declare const MARCH_FIELD_WGSL: string;
@@ -0,0 +1,141 @@
1
+ /** The composed field, drawn — so a pass that fills one can be looked at rather than trusted. */
2
+ import { SAMPLE_FIELD_WGSL } from './sampleField.wgsl.js';
3
+ /**
4
+ * **A visualisation, and it is the honest first consumer of the field.**
5
+ *
6
+ * What Wave 4A's chain is eventually for is indirect light in the shading path, and that is a far
7
+ * larger integration than a pass. What a pass can do now is prove the composition runs on a device
8
+ * and say what it costs — and a distance field is a thing you can *see*, by sphere-tracing it from
9
+ * the camera. If the geometry in the picture is the geometry in the scene, in the right places and
10
+ * the right sizes, the composition is right; if a cascade boundary shows as a seam, the fade is
11
+ * wrong. Neither is available from a number.
12
+ *
13
+ * That is what `DRAFT_SCENES` is for, and it is the same shape the GPU-driven pipeline's three rigs
14
+ * took: a second path drawn beside the first, measured, and kept out of the published set until
15
+ * what it draws is the whole material.
16
+ *
17
+ * **The march is `traceField.ts`'s, minus the cone.** Step by the field's own value, which is a
18
+ * distance nothing can be nearer than; stop where it falls under an epsilon; give up where the ray
19
+ * leaves the outermost cascade, because past that there is no information and stepping on a clamped
20
+ * value converges on the boundary and reports a surface made of nothing.
21
+ */
22
+ /** Floats in the march's params: the inverse view-projection, the eye, and four scalars. */
23
+ export const MARCH_PARAM_FLOATS = 24;
24
+ /** Where each field starts. `INV_VIEW_PROJ` is column-major, as `gl-matrix` stores it. */
25
+ export const MARCH_INV_VIEW_PROJ = 0;
26
+ export const MARCH_EYE = 16;
27
+ export const MARCH_LEVELS = 20;
28
+ export const MARCH_SIDE = 21;
29
+ export const MARCH_STEPS = 22;
30
+ export const MARCH_EPSILON = 23;
31
+ export const MARCH_FIELD_WGSL = /* wgsl */ `
32
+ @group(0) @binding(0) var<storage, read> params: array<f32>;
33
+ @group(0) @binding(1) var<storage, read> cascades: array<f32>;
34
+ @group(0) @binding(2) var<storage, read> fields: array<f32>;
35
+
36
+ ${SAMPLE_FIELD_WGSL}
37
+
38
+ struct Varying {
39
+ @builtin(position) position: vec4<f32>,
40
+ @location(0) uv: vec2<f32>,
41
+ };
42
+
43
+ /*
44
+ * One triangle covering the frame, which is one fewer than two and has no diagonal for a
45
+ * derivative to straddle. Clip y of +1 is the top of the image on both backends — see
46
+ * CLIP_CORRECTION's own note, which spent months saying otherwise — so uv.y counts down from it.
47
+ */
48
+ @vertex
49
+ fn vertexMain(@builtin(vertex_index) index: u32) -> Varying {
50
+ var out: Varying;
51
+ let x = f32(i32(index) / 2) * 4.0 - 1.0;
52
+ let y = f32(i32(index) & 1) * 4.0 - 1.0;
53
+ out.position = vec4<f32>(x, y, 0.0, 1.0);
54
+ out.uv = vec2<f32>(x * 0.5 + 0.5, 0.5 - y * 0.5);
55
+ return out;
56
+ }
57
+
58
+ fn unproject(ndc: vec2<f32>) -> vec3<f32> {
59
+ let m = ${MARCH_INV_VIEW_PROJ}u;
60
+ let clip = vec4<f32>(ndc.x, ndc.y, 0.5, 1.0);
61
+ /*
62
+ * Column-major, so column c is params[c * 4 .. c * 4 + 3]. Any depth gives the same ray from the
63
+ * eye, which is why the z above is a half rather than a near or a far plane — this is the one
64
+ * place the depth convention does not have to be known.
65
+ */
66
+ var world = vec4<f32>(0.0, 0.0, 0.0, 0.0);
67
+ for (var row = 0u; row < 4u; row = row + 1u) {
68
+ world[row] =
69
+ params[m + row] * clip.x +
70
+ params[m + 4u + row] * clip.y +
71
+ params[m + 8u + row] * clip.z +
72
+ params[m + 12u + row] * clip.w;
73
+ }
74
+ return world.xyz / world.w;
75
+ }
76
+
77
+ /** The field's gradient, which for a distance field is the surface normal. */
78
+ fn normalAt(levels: u32, side: u32, p: vec3<f32>, h: f32) -> vec3<f32> {
79
+ let dx = sampleField(levels, side, p + vec3<f32>(h, 0.0, 0.0)) - sampleField(levels, side, p - vec3<f32>(h, 0.0, 0.0));
80
+ let dy = sampleField(levels, side, p + vec3<f32>(0.0, h, 0.0)) - sampleField(levels, side, p - vec3<f32>(0.0, h, 0.0));
81
+ let dz = sampleField(levels, side, p + vec3<f32>(0.0, 0.0, h)) - sampleField(levels, side, p - vec3<f32>(0.0, 0.0, h));
82
+ let g = vec3<f32>(dx, dy, dz);
83
+ let length2 = dot(g, g);
84
+ return select(vec3<f32>(0.0, 1.0, 0.0), g * inverseSqrt(length2), length2 > 1e-12);
85
+ }
86
+
87
+ /** Whether a point is still inside the outermost cascade, which is all the field knows about. */
88
+ fn withinField(levels: u32, p: vec3<f32>) -> bool {
89
+ let base = (levels - 1u) * 8u;
90
+ let low = vec3<f32>(cascades[base], cascades[base + 1u], cascades[base + 2u]);
91
+ let high = vec3<f32>(cascades[base + 3u], cascades[base + 4u], cascades[base + 5u]);
92
+ return all(p >= low) && all(p <= high);
93
+ }
94
+
95
+ @fragment
96
+ fn fragmentMain(vary: Varying) -> @location(0) vec4<f32> {
97
+ let levels = u32(params[${MARCH_LEVELS}]);
98
+ let side = u32(params[${MARCH_SIDE}]);
99
+ let steps = u32(params[${MARCH_STEPS}]);
100
+ let epsilon = params[${MARCH_EPSILON}];
101
+ let eye = vec3<f32>(
102
+ params[${MARCH_EYE}],
103
+ params[${MARCH_EYE} + 1u],
104
+ params[${MARCH_EYE} + 2u],
105
+ );
106
+
107
+ let ndc = vec2<f32>(vary.uv.x * 2.0 - 1.0, 1.0 - vary.uv.y * 2.0);
108
+ let direction = normalize(unproject(ndc) - eye);
109
+
110
+ /* The finest cascade's step, which is the smallest move worth making. */
111
+ let floorStep = cascades[6] * 0.25;
112
+ var travelled = 0.0;
113
+ var hit = false;
114
+ var at = eye;
115
+ for (var i = 0u; i < steps; i = i + 1u) {
116
+ at = eye + direction * travelled;
117
+ if (!withinField(levels, at)) {
118
+ break;
119
+ }
120
+ let distance = sampleField(levels, side, at);
121
+ if (distance <= epsilon) {
122
+ hit = true;
123
+ break;
124
+ }
125
+ travelled = travelled + max(distance, floorStep);
126
+ }
127
+
128
+ if (!hit) {
129
+ /* Nothing here, so the frame keeps whatever drew before this. */
130
+ discard;
131
+ }
132
+
133
+ let normal = normalAt(levels, side, at, cascades[6] * 0.5);
134
+ let sun = normalize(vec3<f32>(0.4, 0.8, 0.45));
135
+ let lambert = max(dot(normal, sun), 0.0);
136
+ /* A hemispheric fill under it, so a face turned away is readable rather than black. */
137
+ let ambient = 0.18 + 0.12 * (normal.y * 0.5 + 0.5);
138
+ let shade = vec3<f32>(0.62, 0.66, 0.72) * (lambert * 0.85 + ambient);
139
+ return vec4<f32>(shade, 1.0);
140
+ }
141
+ `;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * A probe's own bake, on the device: trace a sphere of rays, convolve them into an octahedral map.
3
+ *
4
+ * **Two dispatches rather than one, and the split is what makes it affordable.** A probe's texel
5
+ * is a cosine-weighted sum over every direction, so one invocation a texel that also traced would
6
+ * trace the same `PROBE_DIRECTIONS` rays once per texel — 256 rays becoming 256 × edge², which for
7
+ * an edge of 16 is sixty-five thousand marches for a probe that needs 256. So `traceMain` casts
8
+ * the rays once and writes them down, and `convolveMain` reads them back.
9
+ *
10
+ * **The octahedral mapping is a third spelling and that is a hazard this file states rather than
11
+ * hides.** `octahedral.ts` holds it in TypeScript and in GLSL; this is WGSL, because a hand-written
12
+ * compute shader cannot include the generated one. `scripts/probe-bake-parity.mjs` is what holds
13
+ * the three together, over the texels and the directions both.
14
+ *
15
+ * **A probe's normal is its ray's own direction, which is right here and wrong on a surface.**
16
+ * `probeTraceField` lifts the start along the normal to keep a ray from immediately hitting the
17
+ * surface it left, and its header says lifting along the ray as well double-counts — for a *surface*
18
+ * sample, where the normal and the ray are different things. A probe stands in open space and has
19
+ * no surface and no normal, so the only thing to lift along is the ray, and what it buys is a probe
20
+ * that has come to rest inside a wall casting rays that leave it rather than all reporting a hit at
21
+ * zero distance.
22
+ *
23
+ * The accessors an including module must define, before including the core, are `probeIndirect`'s
24
+ * — see `probeTrace.wgsl.ts` — plus `bake: ProbeBake` as a uniform.
25
+ */
26
+ /**
27
+ * Floats in the bake block, and where each field of it starts.
28
+ *
29
+ * **A `vec3<f32>` is sixteen-byte *aligned* and twelve bytes *long*, and an `f32` after one fills
30
+ * the gap rather than starting a new row.** So `counts` occupies floats 8 to 10 and `edge` is float
31
+ * **11**, not 12 — which cost an afternoon: written at 12, the shader read `edge` as `frame` and
32
+ * every direction came back rotated by the difference, at exactly the right radius. The radius
33
+ * matching is what said it was the angle and not the set.
34
+ *
35
+ * Exported as named offsets for that reason. A caller that counts rows gets this wrong; a caller
36
+ * that names the field cannot.
37
+ */
38
+ export declare const BAKE_ORIGIN = 0;
39
+ export declare const BAKE_SPACING = 4;
40
+ export declare const BAKE_COUNTS = 8;
41
+ export declare const BAKE_EDGE = 11;
42
+ export declare const BAKE_FRAME = 12;
43
+ export declare const BAKE_SCHEDULED = 13;
44
+ /** The sun, which the trace evaluates itself so a light that moves changes the bounce. */
45
+ export declare const BAKE_SUN_DIR = 16;
46
+ export declare const BAKE_SUN_COLOUR = 20;
47
+ /** What a ray that left the world finds. The frame's ambient, so nothing rasterised is read. */
48
+ export declare const BAKE_SKY_COLOUR = 24;
49
+ /** Rounded up to the struct's own sixteen-byte alignment, with two vec3 rows for the sun. */
50
+ export declare const PROBE_BAKE_FLOATS = 28;
51
+ /** Invocations a workgroup, for both entry points. 64 is this backend's default everywhere. */
52
+ export declare const PROBE_BAKE_WORKGROUP = 64;
53
+ /** Floats a ray's radiance takes in the intermediate buffer. */
54
+ export declare const PROBE_RAY_FLOATS = 3;
55
+ /** Floats a baked texel takes. Three and not four: the alpha of an irradiance map means nothing. */
56
+ export declare const PROBE_TEXEL_FLOATS = 3;
57
+ export declare const PROBE_BAKE_STRUCT_WGSL = "\nstruct ProbeBake {\n /* Where the grid's first probe stands, and how far apart they are. */\n origin: vec3<f32>,\n spacing: vec3<f32>,\n /* How many probes along each axis. Whole numbers carried as floats, as every block here does. */\n counts: vec3<f32>,\n /* Texels across one probe's map, gutter included. */\n edge: f32,\n /* Which frame this is, which turns the direction set so a probe converges rather than repeats. */\n frame: f32,\n /* How many probes this dispatch bakes. The schedule says which. */\n scheduled: f32,\n pad: f32,\n /* Towards the sun, and what colour it is. The trace shades what it hits rather than reading a\n capture, which is what lets a bounce follow a light that moved. */\n sunDir: vec3<f32>,\n sunColour: vec3<f32>,\n /* And what is outside, for a ray that left. See probeDistantRadiance. */\n skyColour: vec3<f32>,\n}\n";
58
+ /**
59
+ * The octahedral mapping and the probe lattice, as text.
60
+ *
61
+ * Defines `bakeOctInsetDir(u, v, edge)` and `bakeProbePosition(layer)`.
62
+ */
63
+ export declare const PROBE_BAKE_CORE_WGSL: string;
64
+ /**
65
+ * The parity module: the bake over plain buffers, with a radiance that is a function of position.
66
+ *
67
+ * **The radiance is positional for the reason `probeTraceParityWgsl` gives**: a march that landed a
68
+ * voxel from where the reference landed would return almost the right answer from a smooth field
69
+ * and exactly the right one from a constant, so a constant would check the convolution and nothing
70
+ * about the trace.
71
+ *
72
+ * What this check is *for*, over and above `indirect-parity.mjs`, is the three pieces of arithmetic
73
+ * that only exist in this file: the octahedral texel-to-direction fold, the layer-to-position
74
+ * lattice, and the Fibonacci direction set. Each is a second spelling of something `octahedral.ts`,
75
+ * `probeGrid.ts` and `probeTrace.ts` already hold, and a second spelling is what this repository
76
+ * has learned to check rather than trust.
77
+ */
78
+ export declare function probeBakeParityWgsl(): string;
79
+ /**
80
+ * The production module: the same core, reading the renderer's composed field and probe array.
81
+ *
82
+ * **`probeRadianceAt` is the probe volume here and a sine of position in the parity module**, which
83
+ * is the whole reason the core takes it as an accessor. A probe traced against radiance that is
84
+ * itself probe radiance converges on several bounces over a few refreshes — the maintainer's answer
85
+ * of 2026-09-17 — and that is a property of what is bound rather than of the arithmetic.
86
+ *
87
+ * **The probe array is sampled while a later pass writes a mip of it, and that is legal.** WebGPU
88
+ * forbids a texture being read and written inside one pass, not across two on one encoder: the
89
+ * dispatches here read the array as it stood, and the blit that follows writes the levels the next
90
+ * frame's dispatches will read. What that costs is a frame of latency in the bounce, which is what
91
+ * a probe volume has anyway because it accumulates.
92
+ */
93
+ export declare function probeBakeWgsl(): string;
94
+ /** Bytes between one blit's parameters and the next. A dynamic offset must be 256-aligned. */
95
+ export declare const PROBE_BLIT_STRIDE = 256;
96
+ /** Floats a blit's parameters hold: the slot, the map's edge, and the target level's edge. */
97
+ export declare const PROBE_BLIT_FLOATS = 4;
98
+ /**
99
+ * Carrying a baked map into the probe array the shading already samples.
100
+ *
101
+ * **A render pass rather than a storage write, because the probe array is not a storage texture.**
102
+ * It is created with `RENDER_ATTACHMENT | TEXTURE_BINDING` and its format is the surface's, which
103
+ * needs a device feature before it can be written from compute. Rendering into one mip of one layer
104
+ * needs neither, and the array already carries the usage for it.
105
+ *
106
+ * **The target edge is a parameter because not every level is the irradiance level.** A layer the
107
+ * scene has never rasterised holds undefined contents in its roughness chain, and a fragment
108
+ * sampling that is worse than a fragment sampling a flat colour. So a layer being filled for the
109
+ * first time has every level written from the same map — blocky at level 0, which is the honest
110
+ * thing a diffuse solution can say about a mirror — and every frame after that writes only the
111
+ * irradiance level.
112
+ */
113
+ export declare const PROBE_BLIT_WGSL: string;