@driftengine/core 3.63.0 → 4.1.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 +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,60 @@
1
+ /**
2
+ * The hierarchical depth buffer, and the one decision in it that is easy to get backwards.
3
+ *
4
+ * A texel of level *n+1* must hold the depth **furthest from the camera** of the four it covers.
5
+ * Taking the nearest culls geometry that is visible, which appears as holes that come and go with
6
+ * camera motion and is diagnosed as almost anything else first.
7
+ *
8
+ * **Under reversed-Z, furthest is the minimum value, not the maximum.** `depthConvention.ts` maps
9
+ * the near plane to 1 and the far plane to 0, so the conventional `max` reduction every published
10
+ * description gives is exactly wrong for this engine. That inversion is the reason this module
11
+ * exists as its own file with this paragraph in it rather than as four lines inside a pass.
12
+ *
13
+ * **An odd level includes its extra row and column rather than dropping them.** Dropping them
14
+ * loses the depth of a strip one texel wide along two edges, and a strip of missing occluder is a
15
+ * strip of geometry culled against nothing — conservative in the wrong direction.
16
+ */
17
+ /** How many levels a pyramid over this size has, down to a single texel. */
18
+ export declare function hzbMipCount(width: number, height: number): number;
19
+ /** Dimensions of the level below one of this size: halved, never below one. */
20
+ export declare function hzbMipSize(width: number, height: number): {
21
+ width: number;
22
+ height: number;
23
+ };
24
+ /**
25
+ * Reduce one level into the next, taking the furthest depth of each group.
26
+ *
27
+ * `out` must hold `hzbMipSize(width, height)` texels. Returns the size written.
28
+ */
29
+ export declare function hzbReduce(src: Float32Array, width: number, height: number, out: Float32Array): {
30
+ width: number;
31
+ height: number;
32
+ };
33
+ /**
34
+ * A light's pyramid's base: half its shadow map, each texel the furthest of the group under it,
35
+ * **turned over into the camera's convention.**
36
+ *
37
+ * A shadow map's depth is conventional — near is zero — because the lookup both pipelines share
38
+ * reads it so, and `depthConvention.ts` leaves shadow maps alone. Everything downstream of a
39
+ * pyramid is written for reversed-Z, so this stores `1 - depth`, where the furthest of a group is
40
+ * the smallest value, and from here the light's pyramid is the camera's: `hzbReduce` builds the
41
+ * rest, and the cull reads it through a matrix whose depth is turned over to match. The groups are
42
+ * `hzbReduce`'s, an odd map's extra row and column folded in, and so is the answer — it is
43
+ * `hzbReduce` of the turned-over map, exactly.
44
+ *
45
+ * **Half the map rather than all of it**, because the base level is the one that costs: a whole
46
+ * 2048 map's pyramid would be 22 MB beside the 16 MB of the map itself. `out` holds
47
+ * `hzbMipSize(width, height)` texels; returns that size.
48
+ */
49
+ export declare function shadowPyramidBase(depth: Float32Array, width: number, height: number, out: Float32Array): {
50
+ width: number;
51
+ height: number;
52
+ };
53
+ /**
54
+ * Whether a sphere is hidden behind the depth already in the pyramid.
55
+ *
56
+ * `sphereDepth` is the **nearest** clip depth of the sphere, which under reversed-Z is its
57
+ * *largest* value. It is hidden when even that is further away than the occluder depth — again a
58
+ * smaller number here.
59
+ */
60
+ export declare function hzbOccluded(sphereNearestDepth: number, occluderFurthestDepth: number): boolean;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * The hierarchical depth buffer, and the one decision in it that is easy to get backwards.
3
+ *
4
+ * A texel of level *n+1* must hold the depth **furthest from the camera** of the four it covers.
5
+ * Taking the nearest culls geometry that is visible, which appears as holes that come and go with
6
+ * camera motion and is diagnosed as almost anything else first.
7
+ *
8
+ * **Under reversed-Z, furthest is the minimum value, not the maximum.** `depthConvention.ts` maps
9
+ * the near plane to 1 and the far plane to 0, so the conventional `max` reduction every published
10
+ * description gives is exactly wrong for this engine. That inversion is the reason this module
11
+ * exists as its own file with this paragraph in it rather than as four lines inside a pass.
12
+ *
13
+ * **An odd level includes its extra row and column rather than dropping them.** Dropping them
14
+ * loses the depth of a strip one texel wide along two edges, and a strip of missing occluder is a
15
+ * strip of geometry culled against nothing — conservative in the wrong direction.
16
+ */
17
+ /** How many levels a pyramid over this size has, down to a single texel. */
18
+ export function hzbMipCount(width, height) {
19
+ return Math.floor(Math.log2(Math.max(1, Math.max(width, height)))) + 1;
20
+ }
21
+ /** Dimensions of the level below one of this size: halved, never below one. */
22
+ export function hzbMipSize(width, height) {
23
+ return { width: Math.max(1, width >> 1), height: Math.max(1, height >> 1) };
24
+ }
25
+ /**
26
+ * Reduce one level into the next, taking the furthest depth of each group.
27
+ *
28
+ * `out` must hold `hzbMipSize(width, height)` texels. Returns the size written.
29
+ */
30
+ export function hzbReduce(src, width, height, out) {
31
+ const size = hzbMipSize(width, height);
32
+ for (let y = 0; y < size.height; y += 1) {
33
+ for (let x = 0; x < size.width; x += 1) {
34
+ const x0 = x * 2;
35
+ const y0 = y * 2;
36
+ /* The extra row and column of an odd level are folded into the last group. See the header. */
37
+ const x1 = Math.min(width - 1, x0 + 1);
38
+ const y1 = Math.min(height - 1, y0 + 1);
39
+ const lastX = x === size.width - 1 ? width - 1 : x1;
40
+ const lastY = y === size.height - 1 ? height - 1 : y1;
41
+ let furthest = Infinity;
42
+ for (let sy = y0; sy <= lastY; sy += 1) {
43
+ for (let sx = x0; sx <= lastX; sx += 1) {
44
+ /* Minimum, because reversed-Z puts the far plane at zero. */
45
+ furthest = Math.min(furthest, src[sy * width + sx]);
46
+ }
47
+ }
48
+ out[y * size.width + x] = furthest;
49
+ }
50
+ }
51
+ return size;
52
+ }
53
+ /**
54
+ * A light's pyramid's base: half its shadow map, each texel the furthest of the group under it,
55
+ * **turned over into the camera's convention.**
56
+ *
57
+ * A shadow map's depth is conventional — near is zero — because the lookup both pipelines share
58
+ * reads it so, and `depthConvention.ts` leaves shadow maps alone. Everything downstream of a
59
+ * pyramid is written for reversed-Z, so this stores `1 - depth`, where the furthest of a group is
60
+ * the smallest value, and from here the light's pyramid is the camera's: `hzbReduce` builds the
61
+ * rest, and the cull reads it through a matrix whose depth is turned over to match. The groups are
62
+ * `hzbReduce`'s, an odd map's extra row and column folded in, and so is the answer — it is
63
+ * `hzbReduce` of the turned-over map, exactly.
64
+ *
65
+ * **Half the map rather than all of it**, because the base level is the one that costs: a whole
66
+ * 2048 map's pyramid would be 22 MB beside the 16 MB of the map itself. `out` holds
67
+ * `hzbMipSize(width, height)` texels; returns that size.
68
+ */
69
+ export function shadowPyramidBase(depth, width, height, out) {
70
+ const size = hzbMipSize(width, height);
71
+ for (let y = 0; y < size.height; y += 1) {
72
+ for (let x = 0; x < size.width; x += 1) {
73
+ const x0 = x * 2;
74
+ const y0 = y * 2;
75
+ const lastX = x === size.width - 1 ? width - 1 : Math.min(width - 1, x0 + 1);
76
+ const lastY = y === size.height - 1 ? height - 1 : Math.min(height - 1, y0 + 1);
77
+ let deepest = -Infinity;
78
+ for (let sy = y0; sy <= lastY; sy += 1) {
79
+ for (let sx = x0; sx <= lastX; sx += 1) {
80
+ deepest = Math.max(deepest, depth[sy * width + sx]);
81
+ }
82
+ }
83
+ out[y * size.width + x] = 1 - deepest;
84
+ }
85
+ }
86
+ return size;
87
+ }
88
+ /**
89
+ * Whether a sphere is hidden behind the depth already in the pyramid.
90
+ *
91
+ * `sphereDepth` is the **nearest** clip depth of the sphere, which under reversed-Z is its
92
+ * *largest* value. It is hidden when even that is further away than the occluder depth — again a
93
+ * smaller number here.
94
+ */
95
+ export function hzbOccluded(sphereNearestDepth, occluderFurthestDepth) {
96
+ return sphereNearestDepth < occluderFurthestDepth;
97
+ }
@@ -0,0 +1,85 @@
1
+ /** The split sum's second half, in TypeScript, so the second pipeline's copy has a reference. */
2
+ /**
3
+ * **`flat/lobes.ts` in TypeScript: how much of an environment a surface returns.**
4
+ *
5
+ * The convolution decides *what* a surface reflects — a rougher one reads a blurrier level of the
6
+ * prefiltered chain — and this decides *how much*. Both halves are a fit and an algebraic
7
+ * compensation, which is to say both are arithmetic nobody can check by looking at a frame: the
8
+ * failure they exist to prevent was reported twice from consumers as *metals reading opaque*, and
9
+ * traced to a term that asserts a perfect mirror absorbs 55% of the light once it is roughened.
10
+ *
11
+ * **Metalness is a per-material scalar here, not an ORM map.** `flat/main.ts` reads it per texel
12
+ * from the blue channel of an occlusion-roughness-metallic image, which is a thing this pipeline
13
+ * has no textures to read; a GPU-driven material carries one number instead. That is a *subset* and
14
+ * not a second opinion: everywhere a texel could vary, a material is constant, and every expression
15
+ * below is the forward path's with a uniform standing in for a fetch.
16
+ *
17
+ * **What stays collapsed is the environment gain.** `flat/main.ts` scales what a metal reflects by
18
+ * `uEnvironmentGain`, which exists because a metal has no diffuse behind its reflection and a probe
19
+ * that under-reports the room leaves it with no other way to be lit. `PassEnvironment` carries no
20
+ * such control, so the gain is 1 and `mix(1, gain, metal)` is exactly 1 at every metalness — a
21
+ * collapse that is exact rather than approximate, which is the standard every term here is held to.
22
+ */
23
+ /** A dielectric's normal-incidence reflectance, which is what a material with no metalness is. */
24
+ export declare const DIELECTRIC_F0 = 0.04;
25
+ /**
26
+ * A surface's normal-incidence reflectance, from its metalness.
27
+ *
28
+ * **A metal's Fresnel base is close to its albedo and a dielectric's is four per cent**, and
29
+ * `flat/main.ts` records what leaving it at 0.04 costs: a smooth metal seen head-on takes a four
30
+ * per cent reflection and reads as dark paint. The chromatic half of that — a metal's `f0` being
31
+ * its own colour rather than white — is in `lit.ts`, where the albedo is; this is the scalar the
32
+ * split sum takes.
33
+ */
34
+ export declare function surfaceF0(metalness: number): number;
35
+ /**
36
+ * The split sum's second half, as a two-term fit: `dfg.x` scales `f0` and `dfg.y` is added on top.
37
+ *
38
+ * **Karis's analytic fit rather than the tabulated integral**, which is a texture this pipeline
39
+ * would otherwise have to carry and bind. Its published error is around one per cent of the
40
+ * tabulated term, far below what an eight-bit frame can show. **What would make it wrong** is a
41
+ * material model with a second lobe — a clearcoat or a sheen carries its own BRDF and its own
42
+ * integral, and this is Trowbridge-Reitz with Smith masking and nothing else.
43
+ */
44
+ export declare function envBrdfApprox(ndv: number, roughness: number, out: Float32Array): Float32Array;
45
+ /**
46
+ * The same, with the light that bounces more than once inside the microsurface put back.
47
+ *
48
+ * **The split sum integrates a *single* scattering event**, so it silently discards every ray that
49
+ * strikes one microfacet, bounces, and leaves. Roughness scatters light; it does not absorb it, so
50
+ * a surface with `f0` 1 has to return everything at every roughness — and the bare sum returns
51
+ * about `1 - 0.55 * roughness`, which is a 44% loss at roughness 0.8.
52
+ *
53
+ * Fdez-Agüera's compensation: the missing energy, returned at the surface's average Fresnel over
54
+ * the hemisphere, summed as a geometric series over repeated bounces. **At `f0` 1 it comes back to
55
+ * exactly 1.0 at every roughness** — `average` is 1, `multi` is `energy / energy`, and the sum
56
+ * telescopes — which is the invariant the test beside this file asserts across the whole range.
57
+ *
58
+ * **No divide guard, because the denominator cannot reach zero.** `missing` is at most 0.55 and
59
+ * `average` at most 1, so `1 - missing * average` bottoms out at 0.45 — the worst case in both
60
+ * variables at once.
61
+ */
62
+ export declare function envSpecularEnergy(f0: number, dfgX: number, dfgY: number): number;
63
+ /**
64
+ * How much of what the surface sees in the mirror direction reaches the frame.
65
+ *
66
+ * **Two expressions and a selector, because they answer different questions.** `prefiltered` is 1
67
+ * where the radiance came from a GGX-convolved chain, and there the split sum is the correct share
68
+ * of that integral — it carries the angular dependence itself, so it replaces the Fresnel sweep
69
+ * rather than multiplying it. Where the radiance is anything else, applying it would assert an
70
+ * integral that was never performed: `flat/main.ts` measured that mistake as the grazing-to-head-on
71
+ * ratio falling from about 15 to 1 down to 5 to 1, reported twice as a metal going opaque.
72
+ *
73
+ * So without a chain this is the engine's own long-standing weight — Schlick's Fresnel times
74
+ * `reflectivity * (1 - roughness)` — and with one it is the integral. The two are deliberately not
75
+ * blended into a single formula; a selector that is exactly 0 or exactly 1 is what makes a scene
76
+ * with no environment arithmetically identical to the frame it already rendered.
77
+ *
78
+ * `ndv` is `dot(n, toEye)` clamped at zero, as the caller's own facing term already computes.
79
+ */
80
+ export declare function environmentWeight(ndv: number, roughness: number, reflectivity: number, prefiltered: number,
81
+ /**
82
+ * 0 is a dielectric and 1 is a metal. **Defaults to 0**, so every caller written before this
83
+ * argument existed gets the arithmetic it had.
84
+ */
85
+ metalness?: number): number;
@@ -0,0 +1,129 @@
1
+ /** The split sum's second half, in TypeScript, so the second pipeline's copy has a reference. */
2
+ /**
3
+ * **`flat/lobes.ts` in TypeScript: how much of an environment a surface returns.**
4
+ *
5
+ * The convolution decides *what* a surface reflects — a rougher one reads a blurrier level of the
6
+ * prefiltered chain — and this decides *how much*. Both halves are a fit and an algebraic
7
+ * compensation, which is to say both are arithmetic nobody can check by looking at a frame: the
8
+ * failure they exist to prevent was reported twice from consumers as *metals reading opaque*, and
9
+ * traced to a term that asserts a perfect mirror absorbs 55% of the light once it is roughened.
10
+ *
11
+ * **Metalness is a per-material scalar here, not an ORM map.** `flat/main.ts` reads it per texel
12
+ * from the blue channel of an occlusion-roughness-metallic image, which is a thing this pipeline
13
+ * has no textures to read; a GPU-driven material carries one number instead. That is a *subset* and
14
+ * not a second opinion: everywhere a texel could vary, a material is constant, and every expression
15
+ * below is the forward path's with a uniform standing in for a fetch.
16
+ *
17
+ * **What stays collapsed is the environment gain.** `flat/main.ts` scales what a metal reflects by
18
+ * `uEnvironmentGain`, which exists because a metal has no diffuse behind its reflection and a probe
19
+ * that under-reports the room leaves it with no other way to be lit. `PassEnvironment` carries no
20
+ * such control, so the gain is 1 and `mix(1, gain, metal)` is exactly 1 at every metalness — a
21
+ * collapse that is exact rather than approximate, which is the standard every term here is held to.
22
+ */
23
+ /** A dielectric's normal-incidence reflectance, which is what a material with no metalness is. */
24
+ export const DIELECTRIC_F0 = 0.04;
25
+ /**
26
+ * A surface's normal-incidence reflectance, from its metalness.
27
+ *
28
+ * **A metal's Fresnel base is close to its albedo and a dielectric's is four per cent**, and
29
+ * `flat/main.ts` records what leaving it at 0.04 costs: a smooth metal seen head-on takes a four
30
+ * per cent reflection and reads as dark paint. The chromatic half of that — a metal's `f0` being
31
+ * its own colour rather than white — is in `lit.ts`, where the albedo is; this is the scalar the
32
+ * split sum takes.
33
+ */
34
+ export function surfaceF0(metalness) {
35
+ return DIELECTRIC_F0 + (1 - DIELECTRIC_F0) * metalness;
36
+ }
37
+ /**
38
+ * The split sum's second half, as a two-term fit: `dfg.x` scales `f0` and `dfg.y` is added on top.
39
+ *
40
+ * **Karis's analytic fit rather than the tabulated integral**, which is a texture this pipeline
41
+ * would otherwise have to carry and bind. Its published error is around one per cent of the
42
+ * tabulated term, far below what an eight-bit frame can show. **What would make it wrong** is a
43
+ * material model with a second lobe — a clearcoat or a sheen carries its own BRDF and its own
44
+ * integral, and this is Trowbridge-Reitz with Smith masking and nothing else.
45
+ */
46
+ export function envBrdfApprox(ndv, roughness, out) {
47
+ const c0 = [-1, -0.0275, -0.572, 0.022];
48
+ const c1 = [1, 0.0425, 1.04, -0.04];
49
+ const rx = roughness * c0[0] + c1[0];
50
+ const ry = roughness * c0[1] + c1[1];
51
+ const rz = roughness * c0[2] + c1[2];
52
+ const rw = roughness * c0[3] + c1[3];
53
+ const a004 = Math.min(rx * rx, Math.pow(2, -9.28 * ndv)) * rx + ry;
54
+ out[0] = -1.04 * a004 + rz;
55
+ out[1] = 1.04 * a004 + rw;
56
+ return out;
57
+ }
58
+ /**
59
+ * The same, with the light that bounces more than once inside the microsurface put back.
60
+ *
61
+ * **The split sum integrates a *single* scattering event**, so it silently discards every ray that
62
+ * strikes one microfacet, bounces, and leaves. Roughness scatters light; it does not absorb it, so
63
+ * a surface with `f0` 1 has to return everything at every roughness — and the bare sum returns
64
+ * about `1 - 0.55 * roughness`, which is a 44% loss at roughness 0.8.
65
+ *
66
+ * Fdez-Agüera's compensation: the missing energy, returned at the surface's average Fresnel over
67
+ * the hemisphere, summed as a geometric series over repeated bounces. **At `f0` 1 it comes back to
68
+ * exactly 1.0 at every roughness** — `average` is 1, `multi` is `energy / energy`, and the sum
69
+ * telescopes — which is the invariant the test beside this file asserts across the whole range.
70
+ *
71
+ * **No divide guard, because the denominator cannot reach zero.** `missing` is at most 0.55 and
72
+ * `average` at most 1, so `1 - missing * average` bottoms out at 0.45 — the worst case in both
73
+ * variables at once.
74
+ */
75
+ export function envSpecularEnergy(f0, dfgX, dfgY) {
76
+ const single = f0 * dfgX + dfgY;
77
+ const energy = dfgX + dfgY;
78
+ const missing = 1 - energy;
79
+ const average = f0 + (1 - f0) / 21;
80
+ const multi = (single * average) / (1 - missing * average);
81
+ return single + multi * missing;
82
+ }
83
+ /**
84
+ * How much of what the surface sees in the mirror direction reaches the frame.
85
+ *
86
+ * **Two expressions and a selector, because they answer different questions.** `prefiltered` is 1
87
+ * where the radiance came from a GGX-convolved chain, and there the split sum is the correct share
88
+ * of that integral — it carries the angular dependence itself, so it replaces the Fresnel sweep
89
+ * rather than multiplying it. Where the radiance is anything else, applying it would assert an
90
+ * integral that was never performed: `flat/main.ts` measured that mistake as the grazing-to-head-on
91
+ * ratio falling from about 15 to 1 down to 5 to 1, reported twice as a metal going opaque.
92
+ *
93
+ * So without a chain this is the engine's own long-standing weight — Schlick's Fresnel times
94
+ * `reflectivity * (1 - roughness)` — and with one it is the integral. The two are deliberately not
95
+ * blended into a single formula; a selector that is exactly 0 or exactly 1 is what makes a scene
96
+ * with no environment arithmetically identical to the frame it already rendered.
97
+ *
98
+ * `ndv` is `dot(n, toEye)` clamped at zero, as the caller's own facing term already computes.
99
+ */
100
+ export function environmentWeight(ndv, roughness, reflectivity, prefiltered,
101
+ /**
102
+ * 0 is a dielectric and 1 is a metal. **Defaults to 0**, so every caller written before this
103
+ * argument existed gets the arithmetic it had.
104
+ */
105
+ metalness = 0) {
106
+ const f0 = surfaceF0(metalness);
107
+ const facing = 1 - ndv;
108
+ const fresnel = f0 + (1 - f0) * (facing * facing * facing * facing * facing);
109
+ /*
110
+ * **`max(reflectivity * (1 - roughness), metal)`, and both halves of that are repairs.**
111
+ *
112
+ * `reflectivity` is a per-material control, and it is zero for exactly the surfaces that carry
113
+ * their metalness some other way — `flat/main.ts` measured reading it alone as a chromed subject
114
+ * coming out near black with a baked probe sitting unread, because the whole block was skipped.
115
+ * So a metal reflects whether or not the material asked for reflections.
116
+ *
117
+ * And the `1 - roughness` thinning does not reach the metal. It stands for a polish that
118
+ * scatters a dielectric's reflection into no image at all; a metal has no diffuse to fall back
119
+ * on, so scaling it throws away 40% of everything a surface at roughness 0.4 shows and replaces
120
+ * it with a dark constant. It is also double counting — the level the sample comes from already
121
+ * *is* the roughness.
122
+ */
123
+ const amount = Math.max(reflectivity * (1 - roughness), metalness);
124
+ const sweep = Math.min(Math.max(fresnel * amount, 0), 1);
125
+ const dfg = new Float32Array(2);
126
+ envBrdfApprox(ndv, roughness, dfg);
127
+ const integrated = Math.min(Math.max(envSpecularEnergy(f0, dfg[0], dfg[1]) * Math.max(reflectivity, metalness), 0), 1);
128
+ return sweep + (integrated - sweep) * prefiltered;
129
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * The arguments a culled frame hands the rasteriser, written by the device and read by it.
3
+ *
4
+ * **The whole pipeline exists so that the processor never learns how much there is to draw.** A
5
+ * cull dispatch writes the count into a buffer and the draw reads it from the same buffer; the
6
+ * frame is submitted before either number exists. So these are layouts rather than calls: what a
7
+ * block holds, in what order, and what a caller must have cleared before the dispatch runs.
8
+ *
9
+ * **One draw for the whole frame, not one per cluster.** Every surviving cluster is an *instance*
10
+ * of a fixed 128-triangle draw, which is what `VIS_MAX_TRIANGLES` is for: the index count is the
11
+ * same for all of them, so there is one block instead of thousands and no multi-draw extension is
12
+ * needed. A cluster with fewer triangles emits degenerate ones for the remainder — see
13
+ * `clusterVertexCluster` — and a degenerate triangle covers no pixel, so the picture is unchanged
14
+ * and the cost is the vertex stage running on indices that produce nothing.
15
+ *
16
+ * **What that costs, stated rather than hidden**: a scene whose clusters average 64 triangles runs
17
+ * the vertex stage twice for every triangle it draws. The alternative is a block per cluster and a
18
+ * loop of indirect draws on the processor, which is the draw-call bound this pipeline exists to
19
+ * remove. If a consumer's clusters are persistently half full, the fix is in the *baker* — see
20
+ * `assets/src/bake/cluster.ts`, whose target is the full 128.
21
+ */
22
+ /** Words in a `drawIndexedIndirect` block: index count, instances, first index, base vertex, first instance. */
23
+ export declare const INDIRECT_DRAW_WORDS = 5;
24
+ /** Words in a `dispatchWorkgroups` block: three group counts. */
25
+ export declare const INDIRECT_DISPATCH_WORDS = 3;
26
+ /** Indices a cluster draw always issues, whatever the cluster actually holds. */
27
+ export declare const CLUSTER_INDEX_CAP: number;
28
+ /**
29
+ * The draw block for a frame that kept `clusters` of them.
30
+ *
31
+ * `firstInstance` is zero and the *instance index* is the slot in the kept list rather than the
32
+ * cluster identifier: the list is compacted, so slot and identifier differ, and the shader reads
33
+ * the identifier out of the list. Putting the identifier here instead would need a block per
34
+ * cluster, which is the thing this avoids.
35
+ */
36
+ export declare function writeClusterDrawArgs(out: Uint32Array, at: number, clusters: number): void;
37
+ /**
38
+ * The dispatch block for `count` items at `groupSize` a group.
39
+ *
40
+ * **Rounded up, and zero items is zero groups rather than one.** A group that runs with nothing to
41
+ * do is harmless in this pipeline — every entry point range-checks its own invocation — but a
42
+ * dispatch of one group over an empty list still reads a buffer that a caller may not have bound,
43
+ * and "nothing to do" is the case a frame hits before anything has streamed in.
44
+ *
45
+ * **Zero falls out of the division rather than out of a special case**, and the special case that
46
+ * stood here is gone because a perturbation survived it: `ceil(0 / n)` is already 0, so the branch
47
+ * changed no answer and was a second statement of the rule to keep in step. The behaviour is still
48
+ * held by a test — what is gone is the code that was not doing the holding.
49
+ */
50
+ export declare function writeDispatchArgs(out: Uint32Array, at: number, count: number, groupSize: number): void;
51
+ /**
52
+ * Which slot of the kept list a vertex belongs to, and which triangle of that cluster.
53
+ *
54
+ * The vertex stage's whole addressing, on the processor so a test can read it. `vertex` is
55
+ * `@builtin(vertex_index)` and runs to `CLUSTER_INDEX_CAP`; `instance` is
56
+ * `@builtin(instance_index)` and is the slot.
57
+ *
58
+ * **A triangle past the cluster's own count is reported rather than clamped.** Clamping draws the
59
+ * last triangle of the cluster over and over, which is a visible sliver on every cluster that is
60
+ * not exactly full; reporting it lets the shader emit a degenerate triangle, which covers nothing.
61
+ */
62
+ export declare function clusterVertexCluster(vertex: number, instance: number, triangleCount: number): {
63
+ slot: number;
64
+ triangle: number;
65
+ corner: number;
66
+ degenerate: boolean;
67
+ };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The arguments a culled frame hands the rasteriser, written by the device and read by it.
3
+ *
4
+ * **The whole pipeline exists so that the processor never learns how much there is to draw.** A
5
+ * cull dispatch writes the count into a buffer and the draw reads it from the same buffer; the
6
+ * frame is submitted before either number exists. So these are layouts rather than calls: what a
7
+ * block holds, in what order, and what a caller must have cleared before the dispatch runs.
8
+ *
9
+ * **One draw for the whole frame, not one per cluster.** Every surviving cluster is an *instance*
10
+ * of a fixed 128-triangle draw, which is what `VIS_MAX_TRIANGLES` is for: the index count is the
11
+ * same for all of them, so there is one block instead of thousands and no multi-draw extension is
12
+ * needed. A cluster with fewer triangles emits degenerate ones for the remainder — see
13
+ * `clusterVertexCluster` — and a degenerate triangle covers no pixel, so the picture is unchanged
14
+ * and the cost is the vertex stage running on indices that produce nothing.
15
+ *
16
+ * **What that costs, stated rather than hidden**: a scene whose clusters average 64 triangles runs
17
+ * the vertex stage twice for every triangle it draws. The alternative is a block per cluster and a
18
+ * loop of indirect draws on the processor, which is the draw-call bound this pipeline exists to
19
+ * remove. If a consumer's clusters are persistently half full, the fix is in the *baker* — see
20
+ * `assets/src/bake/cluster.ts`, whose target is the full 128.
21
+ */
22
+ import { VIS_MAX_TRIANGLES } from './visbuffer.js';
23
+ /** Words in a `drawIndexedIndirect` block: index count, instances, first index, base vertex, first instance. */
24
+ export const INDIRECT_DRAW_WORDS = 5;
25
+ /** Words in a `dispatchWorkgroups` block: three group counts. */
26
+ export const INDIRECT_DISPATCH_WORDS = 3;
27
+ /** Indices a cluster draw always issues, whatever the cluster actually holds. */
28
+ export const CLUSTER_INDEX_CAP = VIS_MAX_TRIANGLES * 3;
29
+ /**
30
+ * The draw block for a frame that kept `clusters` of them.
31
+ *
32
+ * `firstInstance` is zero and the *instance index* is the slot in the kept list rather than the
33
+ * cluster identifier: the list is compacted, so slot and identifier differ, and the shader reads
34
+ * the identifier out of the list. Putting the identifier here instead would need a block per
35
+ * cluster, which is the thing this avoids.
36
+ */
37
+ export function writeClusterDrawArgs(out, at, clusters) {
38
+ out[at] = CLUSTER_INDEX_CAP;
39
+ out[at + 1] = Math.max(0, clusters);
40
+ out[at + 2] = 0;
41
+ out[at + 3] = 0;
42
+ out[at + 4] = 0;
43
+ }
44
+ /**
45
+ * The dispatch block for `count` items at `groupSize` a group.
46
+ *
47
+ * **Rounded up, and zero items is zero groups rather than one.** A group that runs with nothing to
48
+ * do is harmless in this pipeline — every entry point range-checks its own invocation — but a
49
+ * dispatch of one group over an empty list still reads a buffer that a caller may not have bound,
50
+ * and "nothing to do" is the case a frame hits before anything has streamed in.
51
+ *
52
+ * **Zero falls out of the division rather than out of a special case**, and the special case that
53
+ * stood here is gone because a perturbation survived it: `ceil(0 / n)` is already 0, so the branch
54
+ * changed no answer and was a second statement of the rule to keep in step. The behaviour is still
55
+ * held by a test — what is gone is the code that was not doing the holding.
56
+ */
57
+ export function writeDispatchArgs(out, at, count, groupSize) {
58
+ const groups = Math.ceil(Math.max(0, count) / Math.max(1, groupSize));
59
+ out[at] = groups;
60
+ out[at + 1] = 1;
61
+ out[at + 2] = 1;
62
+ }
63
+ /**
64
+ * Which slot of the kept list a vertex belongs to, and which triangle of that cluster.
65
+ *
66
+ * The vertex stage's whole addressing, on the processor so a test can read it. `vertex` is
67
+ * `@builtin(vertex_index)` and runs to `CLUSTER_INDEX_CAP`; `instance` is
68
+ * `@builtin(instance_index)` and is the slot.
69
+ *
70
+ * **A triangle past the cluster's own count is reported rather than clamped.** Clamping draws the
71
+ * last triangle of the cluster over and over, which is a visible sliver on every cluster that is
72
+ * not exactly full; reporting it lets the shader emit a degenerate triangle, which covers nothing.
73
+ */
74
+ export function clusterVertexCluster(vertex, instance, triangleCount) {
75
+ const triangle = Math.floor(vertex / 3);
76
+ return { slot: instance, triangle, corner: vertex % 3, degenerate: triangle >= triangleCount };
77
+ }
@@ -0,0 +1,43 @@
1
+ /** Four floats a mesh: world centre and radius. `CULL_INSTANCES_WGSL` reads this stride. */
2
+ export declare const INSTANCE_FLOATS = 4;
3
+ /** What the instance cull writes for a mesh wholly outside the view. Zero is everything else. */
4
+ export declare const INSTANCE_HIDDEN = 1;
5
+ /** Four words a cluster in the uploaded meta: index offset, index count, identifier, mesh. */
6
+ export declare const CLUSTER_META_WORDS = 4;
7
+ /**
8
+ * Each mesh's world bounding sphere, from the world spheres of its clusters.
9
+ *
10
+ * **Held to the numbers the device reads.** The centre is the middle of the clusters' box, stored
11
+ * in single precision first; the radius is then measured from the *stored* centre and rounded up,
12
+ * never to nearest — a sphere rounded the wrong way is a few parts in ten million short of a
13
+ * cluster's far edge, and a cull that is not conservative is a hole in the picture.
14
+ *
15
+ * A mesh no cluster names is a point at the origin, which draws nothing whatever the cull says. A
16
+ * cluster naming a mesh past `meshCount` is refused: it would be bounded by nothing and drawn by a
17
+ * transform that does not exist.
18
+ */
19
+ export declare function instanceBounds(cull: Float32Array, meshOf: Uint32Array, count: number, meshCount: number): Float32Array;
20
+ /**
21
+ * One mesh's bounding sphere, from a contiguous run of its clusters' world bounds.
22
+ *
23
+ * **A run rather than a `meshOf` scan, because a streamed mesh's clusters are contiguous by
24
+ * construction** — the allocator hands out a range — so the scan `instanceBounds` does is work a
25
+ * streaming caller has already done.
26
+ *
27
+ * **A mesh with no clusters gets a sphere of zero radius rather than an empty box's arithmetic.**
28
+ * `Infinity - (-Infinity)` is `-Infinity`, and every comparison against `NaN` is false, which
29
+ * reads as a mesh that is never culled rather than one that is never drawn.
30
+ *
31
+ * The two forms must agree, and `instances.test.ts` is what holds them to it.
32
+ */
33
+ export declare function instanceSphereInto(cull: Float32Array, from: number, count: number, out: Float32Array, at: number): void;
34
+ /**
35
+ * One flag a mesh: `INSTANCE_HIDDEN` where its sphere is wholly outside the view. Returns how many
36
+ * are. Mirrors `CULL_INSTANCES_WGSL`, which `gpu-parity.mjs` holds to `sphereOutsideFrustum`.
37
+ */
38
+ export declare function cullInstances(planes: Float32Array, spheres: Float32Array, count: number, out: Uint32Array): number;
39
+ /**
40
+ * The cut, over every cluster, with the instance flags applied first: one flag a cluster, and how
41
+ * many were selected. Mirrors `LOD_CUT_WGSL`.
42
+ */
43
+ export declare function selectClusters(lod: Float32Array, meta: Uint32Array, hidden: Uint32Array, screenHeight: number, fovY: number, thresholdPixels: number, eyeX: number, eyeY: number, eyeZ: number, out: Uint32Array): number;