@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,30 @@
1
+ /**
2
+ * Getting a number back from the GPU without waiting for it.
3
+ *
4
+ * The answer to a request made this frame arrives two or three frames later, and a caller that
5
+ * waits has stalled the pipeline to learn something it could have learned late for free. So this
6
+ * is a ring of slots: a request takes one, the completion fills it, and the caller collects
7
+ * whatever has arrived whenever it asks.
8
+ *
9
+ * **A full ring refuses rather than overwrites.** Silently dropping the oldest result produces a
10
+ * statistic that is wrong in a way nothing detects — a frame time that is quietly somebody
11
+ * else's, which is worse than a frame time that is missing.
12
+ *
13
+ * **Deliberately not what texture residency uses.** Reactive streaming is exactly the
14
+ * arrangement where this latency becomes visible as pop-in; the answer there is to predict
15
+ * rather than to read back. This ring is for timings and statistics, where being three frames
16
+ * late costs nothing.
17
+ */
18
+ export interface ReadbackRing {
19
+ /** 0 free, 1 outstanding, 2 arrived, one per slot. */
20
+ state: Uint8Array;
21
+ /** The arrived buffer per slot, or null. */
22
+ data: (ArrayBuffer | null)[];
23
+ /** Where to start looking for a free slot, so requests spread rather than reusing one. */
24
+ next: number;
25
+ }
26
+ export declare function createReadbackRing(slots: number): ReadbackRing;
27
+ export declare function beginReadback(ring: ReadbackRing): number;
28
+ export declare function completeReadback(ring: ReadbackRing, slot: number, data: ArrayBuffer): void;
29
+ export declare function takeReadback(ring: ReadbackRing): ArrayBuffer | null;
30
+ export declare function readbackPending(ring: ReadbackRing): number;
@@ -0,0 +1,47 @@
1
+ export function createReadbackRing(slots) {
2
+ return {
3
+ state: new Uint8Array(slots),
4
+ data: Array.from({ length: slots }, () => null),
5
+ next: 0,
6
+ };
7
+ }
8
+ export function beginReadback(ring) {
9
+ const slots = ring.state.length;
10
+ for (let i = 0; i < slots; i += 1) {
11
+ const slot = (ring.next + i) % slots;
12
+ if (ring.state[slot] === 0) {
13
+ ring.state[slot] = 1;
14
+ ring.next = (slot + 1) % slots;
15
+ return slot;
16
+ }
17
+ }
18
+ return -1;
19
+ }
20
+ export function completeReadback(ring, slot, data) {
21
+ if (slot < 0 || slot >= ring.state.length)
22
+ return;
23
+ /* Only an outstanding slot may be completed: one that was evicted or never requested is not
24
+ * ours to fill, and filling it would hand the caller a result for a request it has forgotten. */
25
+ if (ring.state[slot] !== 1)
26
+ return;
27
+ ring.state[slot] = 2;
28
+ ring.data[slot] = data;
29
+ }
30
+ export function takeReadback(ring) {
31
+ for (let slot = 0; slot < ring.state.length; slot += 1) {
32
+ if (ring.state[slot] === 2) {
33
+ const data = ring.data[slot] ?? null;
34
+ ring.state[slot] = 0;
35
+ ring.data[slot] = null;
36
+ return data;
37
+ }
38
+ }
39
+ return null;
40
+ }
41
+ export function readbackPending(ring) {
42
+ let pending = 0;
43
+ for (let slot = 0; slot < ring.state.length; slot += 1)
44
+ if (ring.state[slot] === 1)
45
+ pending += 1;
46
+ return pending;
47
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * History that disagrees with its neighbourhood, pulled in without changing its hue.
3
+ *
4
+ * **Why a luminance-chrominance space, and why a variance box.** The temporal resolve bounds its
5
+ * history by the minimum and maximum of nine red-green-blue samples, which is as wide as the most
6
+ * extreme of them: one bright pixel beside a moving edge lets the whole ghost through. A box of the
7
+ * mean plus or minus `gamma` standard deviations is as wide as the neighbourhood actually varies, and
8
+ * YCoCg separates the luminance the eye is sensitive to from the chrominance it is not.
9
+ *
10
+ * **Why clipping rather than clamping**, the resolve's own reason: a clamp moves each channel on its
11
+ * own, so a history merely brighter than its surroundings lands on a corner of the box and comes back
12
+ * a different hue — coloured fringing on every moving edge. Shortening the whole offset from the
13
+ * box's centre by one ratio keeps its direction and changes only its length. `clipToBox` is
14
+ * `clipToNeighbourhood` over plain arrays, and the test holds the two to one rule.
15
+ */
16
+ /** YCoCg from linear red, green and blue, into `out`. Dyadic, so it round-trips exactly. */
17
+ export declare function rgbToYCoCg(out: Float32Array | Float64Array, r: number, g: number, b: number): void;
18
+ /** Linear red, green and blue from YCoCg, into `out`. */
19
+ export declare function yCoCgToRgb(out: Float32Array | Float64Array, y: number, co: number, cg: number): void;
20
+ /**
21
+ * The box of `count` three-channel samples: each channel's mean plus or minus `gamma` of its
22
+ * standard deviation, into `outMin` and `outMax`.
23
+ *
24
+ * **A channel whose samples all agree has that value as its box, exactly.** A mean of nine equal
25
+ * numbers is not always that number in floating point, and a box a rounding wide around the current
26
+ * colour would let a history through by a rounding instead of collapsing it onto the colour.
27
+ */
28
+ export declare function varianceBox(samples: ArrayLike<number>, count: number, gamma: number, outMin: Float32Array | Float64Array, outMax: Float32Array | Float64Array): void;
29
+ /**
30
+ * `history` pulled into the box `min`..`max`, along the line towards the box's centre, into `out`.
31
+ *
32
+ * Unchanged inside the box; on its boundary from outside it. A channel with no extent bounds any
33
+ * history that differs from it infinitely, so such a history collapses to the centre — the honest
34
+ * answer for a flat neighbourhood, and the alternative is a division by zero.
35
+ */
36
+ export declare function clipToBox(out: Float32Array | Float64Array, history: ArrayLike<number>, min: ArrayLike<number>, max: ArrayLike<number>): void;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * History that disagrees with its neighbourhood, pulled in without changing its hue.
3
+ *
4
+ * **Why a luminance-chrominance space, and why a variance box.** The temporal resolve bounds its
5
+ * history by the minimum and maximum of nine red-green-blue samples, which is as wide as the most
6
+ * extreme of them: one bright pixel beside a moving edge lets the whole ghost through. A box of the
7
+ * mean plus or minus `gamma` standard deviations is as wide as the neighbourhood actually varies, and
8
+ * YCoCg separates the luminance the eye is sensitive to from the chrominance it is not.
9
+ *
10
+ * **Why clipping rather than clamping**, the resolve's own reason: a clamp moves each channel on its
11
+ * own, so a history merely brighter than its surroundings lands on a corner of the box and comes back
12
+ * a different hue — coloured fringing on every moving edge. Shortening the whole offset from the
13
+ * box's centre by one ratio keeps its direction and changes only its length. `clipToBox` is
14
+ * `clipToNeighbourhood` over plain arrays, and the test holds the two to one rule.
15
+ */
16
+ /** YCoCg from linear red, green and blue, into `out`. Dyadic, so it round-trips exactly. */
17
+ export function rgbToYCoCg(out, r, g, b) {
18
+ out[0] = r * 0.25 + g * 0.5 + b * 0.25;
19
+ out[1] = r * 0.5 - b * 0.5;
20
+ out[2] = -r * 0.25 + g * 0.5 - b * 0.25;
21
+ }
22
+ /** Linear red, green and blue from YCoCg, into `out`. */
23
+ export function yCoCgToRgb(out, y, co, cg) {
24
+ const base = y - cg;
25
+ out[0] = base + co;
26
+ out[1] = y + cg;
27
+ out[2] = base - co;
28
+ }
29
+ /**
30
+ * The box of `count` three-channel samples: each channel's mean plus or minus `gamma` of its
31
+ * standard deviation, into `outMin` and `outMax`.
32
+ *
33
+ * **A channel whose samples all agree has that value as its box, exactly.** A mean of nine equal
34
+ * numbers is not always that number in floating point, and a box a rounding wide around the current
35
+ * colour would let a history through by a rounding instead of collapsing it onto the colour.
36
+ */
37
+ export function varianceBox(samples, count, gamma, outMin, outMax) {
38
+ for (let c = 0; c < 3; c += 1) {
39
+ const first = samples[c];
40
+ let same = true;
41
+ let sum = 0;
42
+ for (let i = 0; i < count; i += 1) {
43
+ const value = samples[i * 3 + c];
44
+ sum += value;
45
+ if (value !== first)
46
+ same = false;
47
+ }
48
+ if (same) {
49
+ outMin[c] = first;
50
+ outMax[c] = first;
51
+ continue;
52
+ }
53
+ const mean = sum / count;
54
+ let spread = 0;
55
+ for (let i = 0; i < count; i += 1) {
56
+ const d = samples[i * 3 + c] - mean;
57
+ spread += d * d;
58
+ }
59
+ const deviation = Math.sqrt(spread / count);
60
+ outMin[c] = mean - gamma * deviation;
61
+ outMax[c] = mean + gamma * deviation;
62
+ }
63
+ }
64
+ /**
65
+ * `history` pulled into the box `min`..`max`, along the line towards the box's centre, into `out`.
66
+ *
67
+ * Unchanged inside the box; on its boundary from outside it. A channel with no extent bounds any
68
+ * history that differs from it infinitely, so such a history collapses to the centre — the honest
69
+ * answer for a flat neighbourhood, and the alternative is a division by zero.
70
+ */
71
+ export function clipToBox(out, history, min, max) {
72
+ let ratio = 0;
73
+ for (let c = 0; c < 3; c += 1) {
74
+ const centre = (min[c] + max[c]) * 0.5;
75
+ const offset = history[c] - centre;
76
+ const extent = (max[c] - min[c]) * 0.5;
77
+ if (extent > 1e-7)
78
+ ratio = Math.max(ratio, Math.abs(offset) / extent);
79
+ else if (Math.abs(offset) > 1e-7)
80
+ ratio = Number.POSITIVE_INFINITY;
81
+ }
82
+ if (!(ratio > 1)) {
83
+ for (let c = 0; c < 3; c += 1)
84
+ out[c] = history[c];
85
+ return;
86
+ }
87
+ const scale = Number.isFinite(ratio) ? 1 / ratio : 0;
88
+ for (let c = 0; c < 3; c += 1) {
89
+ const centre = (min[c] + max[c]) * 0.5;
90
+ out[c] = centre + (history[c] - centre) * scale;
91
+ }
92
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Whether a pixel's history is the same surface, as a weight from one to zero.
3
+ *
4
+ * **What is compared.** The camera moved, so this frame's depth and last frame's are depths from two
5
+ * eyes. The resolve compares the depth this surface *should* have had last frame — the w of its
6
+ * reprojected position, which is a view depth — with the view depth last frame actually held where it
7
+ * lands. Equal, and it is the same surface; different, and something else was there: a pixel that was
8
+ * hidden last frame would otherwise take its colour from whatever was in front of it.
9
+ *
10
+ * **Relative, and forgiving in proportion to the motion.** A tenth of a unit is nothing at a hundred
11
+ * units and everything at one. And a depth read at a reprojected position under fast motion comes from
12
+ * a different part of a texel than the one it stands for, which at a grazing angle is a different
13
+ * depth; the tolerance grows with the motion's length.
14
+ *
15
+ * **Normals, for the case depth cannot see.** A leaf's two sides are at one depth, and the history of
16
+ * the front is not the back. The forward frame has no normal buffer, so both normals come from their
17
+ * frame's depth — `worldPositionFromDepth` and `normalFromPositions` — in world space, where the two
18
+ * frames agree.
19
+ *
20
+ * **Continuous in every input**, because a step is a line on screen along which the history is kept on
21
+ * one frame and dropped on the next: every threshold is a smoothstep, never a comparison.
22
+ *
23
+ * Anything that is not a number, a depth that is not positive — which is what the resolve passes
24
+ * where the reprojection left the screen — and a negative motion length all trust nothing.
25
+ */
26
+ export interface DisocclusionParams {
27
+ /** The relative depth disagreement trusted fully; trust falls to zero at twice it. */
28
+ readonly depthTolerance: number;
29
+ /** How much the tolerance grows per unit of motion, in uv. */
30
+ readonly motionScale: number;
31
+ /** The cosine between the two normals at and below which nothing is trusted. */
32
+ readonly normalFloor: number;
33
+ /** The cosine at and above which the normals are trusted fully. */
34
+ readonly normalCeiling: number;
35
+ }
36
+ /**
37
+ * A percent of depth, growing by half a percent for every hundredth of the screen the surface moved;
38
+ * normals trusted fully within sixty degrees and not at all past ninety.
39
+ */
40
+ export declare const DEFAULT_DISOCCLUSION: DisocclusionParams;
41
+ /**
42
+ * One where the history is trustworthy, zero where it is not, and continuous between.
43
+ *
44
+ * `currDepth` is the view depth this surface should have had last frame; `histDepth` the view depth
45
+ * last frame held where it lands, or zero where it landed off the screen; `motionLength` the motion's
46
+ * length in uv; `normalDot` the cosine between the two frames' world normals there.
47
+ */
48
+ export declare function disocclusionWeight(currDepth: number, histDepth: number, motionLength: number, normalDot: number, params: DisocclusionParams): number;
49
+ /**
50
+ * The world position a depth stands for: `(u, v, clipDepth)` through the inverse view-projection,
51
+ * in whatever depth convention that matrix was built for. Returns false where the matrix has no
52
+ * answer there — singular, or the point at infinity.
53
+ */
54
+ export declare function worldPositionFromDepth(inverseViewProj: ArrayLike<number>, u: number, v: number, clipDepth: number, out: Float64Array): boolean;
55
+ /**
56
+ * The unit normal of the surface through `centre` and its two screen neighbours, turned to face
57
+ * `eye` — so the answer is the same whichever way the target's rows run. Returns false where the
58
+ * three are in a line: there is no surface to have a normal.
59
+ */
60
+ export declare function normalFromPositions(centre: ArrayLike<number>, right: ArrayLike<number>, up: ArrayLike<number>, eye: ArrayLike<number>, out: Float64Array): boolean;
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Whether a pixel's history is the same surface, as a weight from one to zero.
3
+ *
4
+ * **What is compared.** The camera moved, so this frame's depth and last frame's are depths from two
5
+ * eyes. The resolve compares the depth this surface *should* have had last frame — the w of its
6
+ * reprojected position, which is a view depth — with the view depth last frame actually held where it
7
+ * lands. Equal, and it is the same surface; different, and something else was there: a pixel that was
8
+ * hidden last frame would otherwise take its colour from whatever was in front of it.
9
+ *
10
+ * **Relative, and forgiving in proportion to the motion.** A tenth of a unit is nothing at a hundred
11
+ * units and everything at one. And a depth read at a reprojected position under fast motion comes from
12
+ * a different part of a texel than the one it stands for, which at a grazing angle is a different
13
+ * depth; the tolerance grows with the motion's length.
14
+ *
15
+ * **Normals, for the case depth cannot see.** A leaf's two sides are at one depth, and the history of
16
+ * the front is not the back. The forward frame has no normal buffer, so both normals come from their
17
+ * frame's depth — `worldPositionFromDepth` and `normalFromPositions` — in world space, where the two
18
+ * frames agree.
19
+ *
20
+ * **Continuous in every input**, because a step is a line on screen along which the history is kept on
21
+ * one frame and dropped on the next: every threshold is a smoothstep, never a comparison.
22
+ *
23
+ * Anything that is not a number, a depth that is not positive — which is what the resolve passes
24
+ * where the reprojection left the screen — and a negative motion length all trust nothing.
25
+ */
26
+ /**
27
+ * A percent of depth, growing by half a percent for every hundredth of the screen the surface moved;
28
+ * normals trusted fully within sixty degrees and not at all past ninety.
29
+ */
30
+ export const DEFAULT_DISOCCLUSION = {
31
+ depthTolerance: 0.01,
32
+ motionScale: 0.5,
33
+ normalFloor: 0,
34
+ normalCeiling: 0.5,
35
+ };
36
+ function smoothstep(edge0, edge1, x) {
37
+ const t = Math.min(1, Math.max(0, (x - edge0) / (edge1 - edge0)));
38
+ return t * t * (3 - 2 * t);
39
+ }
40
+ /**
41
+ * One where the history is trustworthy, zero where it is not, and continuous between.
42
+ *
43
+ * `currDepth` is the view depth this surface should have had last frame; `histDepth` the view depth
44
+ * last frame held where it lands, or zero where it landed off the screen; `motionLength` the motion's
45
+ * length in uv; `normalDot` the cosine between the two frames' world normals there.
46
+ */
47
+ export function disocclusionWeight(currDepth, histDepth, motionLength, normalDot, params) {
48
+ if (!(currDepth > 0) || !(histDepth > 0) || !(motionLength >= 0) || Number.isNaN(normalDot)) {
49
+ return 0;
50
+ }
51
+ const disagreement = Math.abs(currDepth - histDepth) / currDepth;
52
+ const tolerance = params.depthTolerance + params.motionScale * motionLength;
53
+ const depth = 1 - smoothstep(tolerance, 2 * tolerance, disagreement);
54
+ const normal = smoothstep(params.normalFloor, params.normalCeiling, normalDot);
55
+ return depth * normal;
56
+ }
57
+ /**
58
+ * The world position a depth stands for: `(u, v, clipDepth)` through the inverse view-projection,
59
+ * in whatever depth convention that matrix was built for. Returns false where the matrix has no
60
+ * answer there — singular, or the point at infinity.
61
+ */
62
+ export function worldPositionFromDepth(inverseViewProj, u, v, clipDepth, out) {
63
+ const x = u * 2 - 1;
64
+ const y = v * 2 - 1;
65
+ const m = inverseViewProj;
66
+ const w = m[3] * x + m[7] * y + m[11] * clipDepth + m[15];
67
+ if (!(Math.abs(w) > 1e-12))
68
+ return false;
69
+ for (let r = 0; r < 3; r += 1) {
70
+ out[r] =
71
+ (m[r] * x +
72
+ m[4 + r] * y +
73
+ m[8 + r] * clipDepth +
74
+ m[12 + r]) /
75
+ w;
76
+ }
77
+ return Number.isFinite(out[0]) && Number.isFinite(out[1]) && Number.isFinite(out[2]);
78
+ }
79
+ /**
80
+ * The unit normal of the surface through `centre` and its two screen neighbours, turned to face
81
+ * `eye` — so the answer is the same whichever way the target's rows run. Returns false where the
82
+ * three are in a line: there is no surface to have a normal.
83
+ */
84
+ export function normalFromPositions(centre, right, up, eye, out) {
85
+ const ax = right[0] - centre[0];
86
+ const ay = right[1] - centre[1];
87
+ const az = right[2] - centre[2];
88
+ const bx = up[0] - centre[0];
89
+ const by = up[1] - centre[1];
90
+ const bz = up[2] - centre[2];
91
+ let nx = ay * bz - az * by;
92
+ let ny = az * bx - ax * bz;
93
+ let nz = ax * by - ay * bx;
94
+ const length2 = nx * nx + ny * ny + nz * nz;
95
+ const scale2 = (ax * ax + ay * ay + az * az) * (bx * bx + by * by + bz * bz);
96
+ if (!(length2 > 1e-12 * scale2))
97
+ return false;
98
+ const toEye = nx * (eye[0] - centre[0]) +
99
+ ny * (eye[1] - centre[1]) +
100
+ nz * (eye[2] - centre[2]);
101
+ const inverse = (toEye < 0 ? -1 : 1) / Math.sqrt(length2);
102
+ nx *= inverse;
103
+ ny *= inverse;
104
+ nz *= inverse;
105
+ out[0] = nx;
106
+ out[1] = ny;
107
+ out[2] = nz;
108
+ return true;
109
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * DriftFG's reference: a frame generated between two rendered ones, from their motion and depth.
3
+ *
4
+ * **One scatter, of the later frame.** Its motion points each pixel to where its surface was in the
5
+ * earlier frame, so a surface visible in the later frame stands at time `t` a fraction `1 − t` of
6
+ * that motion back from where it is now (`projectForward`), the nearest surface winning a pixel two
7
+ * land on. That one scatter places every surface the later frame shows, and carries both frames'
8
+ * colours for it: the later frame's at the pixel it came from, and the earlier frame's at the pixel
9
+ * its motion points to — when the earlier frame shows the same surface there, which its depth says.
10
+ * The colour is taken from whichever frame is nearer in time (`resolveGenerated`).
11
+ *
12
+ * **A pixel nothing lands on is a hole, filled and marked** (`fillHoles`): the later frame never
13
+ * saw what stands there, so it is a surface a moving object uncovered — and what a moving object
14
+ * uncovers is behind it, so the hole takes the farther of the two frames' surfaces at that pixel.
15
+ * The mark is kept for the device pass that follows this reference, which may treat a hole's pixels
16
+ * more carefully than a projected one's.
17
+ *
18
+ * **The interface is not in the frames generated from**: a menu drawn into them would be projected
19
+ * with whatever moved beneath it and warp. It is composited over the generated frame afterwards,
20
+ * from its own layer, at the display's rate (`composeInterface`).
21
+ *
22
+ * **Linear motion, and what that gives up.** A surface is placed along the straight line between
23
+ * its two positions, which is exact for a camera or an object moving at constant velocity across one
24
+ * render interval and wrong for anything turning within it; a turn fast enough to matter shows as a
25
+ * surface slightly off its arc for one generated frame. And a surface the later frame does not show
26
+ * — hidden in it, visible in the earlier one — is not projected at all: at small `t` it is a hole
27
+ * filled from the earlier frame, which is right, and at large `t` it is the same, which is late.
28
+ *
29
+ * Images are row-major; colour is four floats a pixel, premultiplied; depth is view distance, larger
30
+ * further; motion is two floats a pixel in pixels of this image. The engine's motion target stores
31
+ * uv with rows running upward, and converting it is the device pass's business rather than this.
32
+ */
33
+ export interface FrameImage {
34
+ readonly width: number;
35
+ readonly height: number;
36
+ readonly colour: Float32Array;
37
+ readonly depth: Float32Array;
38
+ /** Where each pixel's surface was in the frame before, as an offset in pixels. */
39
+ readonly motion: Float32Array;
40
+ }
41
+ /** Which pixel of the later frame lands on each pixel at time `t`, and at what depth. */
42
+ export interface Projection {
43
+ readonly width: number;
44
+ readonly height: number;
45
+ /** The later frame's pixel landing here, or -1 where none does. */
46
+ readonly source: Int32Array;
47
+ readonly depth: Float32Array;
48
+ }
49
+ export declare function createProjection(width: number, height: number): Projection;
50
+ /**
51
+ * Scatter the later frame's pixels to where they stand at time `t`: 0 is the earlier frame and 1
52
+ * the later. The nearest surface wins a pixel two land on.
53
+ */
54
+ export declare function projectForward(motion: Float32Array, depth: Float32Array, t: number, out: Projection): void;
55
+ /**
56
+ * Colour every projected pixel from the frame nearer in time, and mark every pixel nothing landed on
57
+ * — whose colour is left for `fillHoles`.
58
+ *
59
+ * The earlier frame is used only where it shows the same surface where the motion says it was: its
60
+ * depth there within `SAME_SURFACE` of the later frame's. Where it does not, the surface was hidden
61
+ * in it, and the later frame is the only one that saw it.
62
+ */
63
+ export declare function resolveGenerated(projection: Projection, before: FrameImage, after: FrameImage, t: number, out: Float32Array, mask: Uint8Array): void;
64
+ /** Fill every marked pixel from the farther of the two frames' surfaces there. The mark stays. */
65
+ export declare function fillHoles(out: Float32Array, before: FrameImage, after: FrameImage, mask: Uint8Array): void;
66
+ /** The interface over the generated frame, premultiplied, from its own layer and never projected. */
67
+ export declare function composeInterface(out: Float32Array, overlay: Float32Array): void;
68
+ /**
69
+ * The milliseconds frame generation adds to every rendered frame, stated rather than hidden.
70
+ *
71
+ * **A generated frame sits between two rendered ones, so it cannot be shown until the later one
72
+ * exists**, and the later one is then held back while the frames generated before it are shown:
73
+ * `displayHz / renderHz − 1` display intervals, and the generation before the first of them. At
74
+ * the render rate nothing is generated and nothing is added. The rates must be a whole multiple
75
+ * apart, or the generated frames would fall unevenly between rendered ones and the motion judder.
76
+ *
77
+ * What would make it wrong: extrapolation — generating from the earlier frame alone, ahead of the
78
+ * later — adds no hold-back and fills no hole from a frame it has not got. That is a different
79
+ * trade, and this reference does not make it.
80
+ */
81
+ export declare function frameGenLatency(displayHz: number, renderHz: number, generationMs: number): number;
@@ -0,0 +1,150 @@
1
+ /**
2
+ * DriftFG's reference: a frame generated between two rendered ones, from their motion and depth.
3
+ *
4
+ * **One scatter, of the later frame.** Its motion points each pixel to where its surface was in the
5
+ * earlier frame, so a surface visible in the later frame stands at time `t` a fraction `1 − t` of
6
+ * that motion back from where it is now (`projectForward`), the nearest surface winning a pixel two
7
+ * land on. That one scatter places every surface the later frame shows, and carries both frames'
8
+ * colours for it: the later frame's at the pixel it came from, and the earlier frame's at the pixel
9
+ * its motion points to — when the earlier frame shows the same surface there, which its depth says.
10
+ * The colour is taken from whichever frame is nearer in time (`resolveGenerated`).
11
+ *
12
+ * **A pixel nothing lands on is a hole, filled and marked** (`fillHoles`): the later frame never
13
+ * saw what stands there, so it is a surface a moving object uncovered — and what a moving object
14
+ * uncovers is behind it, so the hole takes the farther of the two frames' surfaces at that pixel.
15
+ * The mark is kept for the device pass that follows this reference, which may treat a hole's pixels
16
+ * more carefully than a projected one's.
17
+ *
18
+ * **The interface is not in the frames generated from**: a menu drawn into them would be projected
19
+ * with whatever moved beneath it and warp. It is composited over the generated frame afterwards,
20
+ * from its own layer, at the display's rate (`composeInterface`).
21
+ *
22
+ * **Linear motion, and what that gives up.** A surface is placed along the straight line between
23
+ * its two positions, which is exact for a camera or an object moving at constant velocity across one
24
+ * render interval and wrong for anything turning within it; a turn fast enough to matter shows as a
25
+ * surface slightly off its arc for one generated frame. And a surface the later frame does not show
26
+ * — hidden in it, visible in the earlier one — is not projected at all: at small `t` it is a hole
27
+ * filled from the earlier frame, which is right, and at large `t` it is the same, which is late.
28
+ *
29
+ * Images are row-major; colour is four floats a pixel, premultiplied; depth is view distance, larger
30
+ * further; motion is two floats a pixel in pixels of this image. The engine's motion target stores
31
+ * uv with rows running upward, and converting it is the device pass's business rather than this.
32
+ */
33
+ /**
34
+ * How far two depths may differ, as a fraction of the nearer, and still be one surface.
35
+ *
36
+ * What it gives up: a surface moving toward or away from the camera changes its own depth between
37
+ * frames, and one moving five per cent of its distance in a render interval reads as a different
38
+ * surface, so it takes the later frame's colour at small `t` too — its colour a render interval
39
+ * late, not wrong.
40
+ */
41
+ const SAME_SURFACE = 0.05;
42
+ export function createProjection(width, height) {
43
+ const pixels = width * height;
44
+ return { width, height, source: new Int32Array(pixels), depth: new Float32Array(pixels) };
45
+ }
46
+ /**
47
+ * Scatter the later frame's pixels to where they stand at time `t`: 0 is the earlier frame and 1
48
+ * the later. The nearest surface wins a pixel two land on.
49
+ */
50
+ export function projectForward(motion, depth, t, out) {
51
+ const { width, height, source } = out;
52
+ source.fill(-1);
53
+ out.depth.fill(Infinity);
54
+ const back = 1 - t;
55
+ for (let y = 0; y < height; y += 1) {
56
+ for (let x = 0; x < width; x += 1) {
57
+ const from = y * width + x;
58
+ const tx = Math.round(x + back * motion[from * 2]);
59
+ const ty = Math.round(y + back * motion[from * 2 + 1]);
60
+ if (tx < 0 || tx >= width || ty < 0 || ty >= height)
61
+ continue;
62
+ const at = ty * width + tx;
63
+ const z = depth[from];
64
+ if (z < out.depth[at]) {
65
+ out.depth[at] = z;
66
+ source[at] = from;
67
+ }
68
+ }
69
+ }
70
+ }
71
+ function copyColour(out, at, from, index) {
72
+ for (let c = 0; c < 4; c += 1)
73
+ out[at * 4 + c] = from[index * 4 + c];
74
+ }
75
+ /**
76
+ * Colour every projected pixel from the frame nearer in time, and mark every pixel nothing landed on
77
+ * — whose colour is left for `fillHoles`.
78
+ *
79
+ * The earlier frame is used only where it shows the same surface where the motion says it was: its
80
+ * depth there within `SAME_SURFACE` of the later frame's. Where it does not, the surface was hidden
81
+ * in it, and the later frame is the only one that saw it.
82
+ */
83
+ export function resolveGenerated(projection, before, after, t, out, mask) {
84
+ const { width, height, source } = projection;
85
+ const early = t < 0.5;
86
+ for (let at = 0; at < source.length; at += 1) {
87
+ const from = source[at];
88
+ if (from < 0) {
89
+ mask[at] = 1;
90
+ continue;
91
+ }
92
+ mask[at] = 0;
93
+ if (early) {
94
+ const x = Math.round((from % width) + after.motion[from * 2]);
95
+ const y = Math.round(Math.floor(from / width) + after.motion[from * 2 + 1]);
96
+ if (x >= 0 && x < width && y >= 0 && y < height) {
97
+ const was = y * width + x;
98
+ const then = before.depth[was];
99
+ const now = after.depth[from];
100
+ if (Math.abs(then - now) <= SAME_SURFACE * Math.min(then, now)) {
101
+ copyColour(out, at, before.colour, was);
102
+ continue;
103
+ }
104
+ }
105
+ }
106
+ copyColour(out, at, after.colour, from);
107
+ }
108
+ }
109
+ /** Fill every marked pixel from the farther of the two frames' surfaces there. The mark stays. */
110
+ export function fillHoles(out, before, after, mask) {
111
+ for (let at = 0; at < mask.length; at += 1) {
112
+ if (mask[at] !== 1)
113
+ continue;
114
+ const behind = before.depth[at] > after.depth[at] ? before : after;
115
+ copyColour(out, at, behind.colour, at);
116
+ }
117
+ }
118
+ /** The interface over the generated frame, premultiplied, from its own layer and never projected. */
119
+ export function composeInterface(out, overlay) {
120
+ for (let i = 0; i < out.length; i += 4) {
121
+ const keep = 1 - overlay[i + 3];
122
+ for (let c = 0; c < 4; c += 1) {
123
+ out[i + c] = overlay[i + c] + out[i + c] * keep;
124
+ }
125
+ }
126
+ }
127
+ /**
128
+ * The milliseconds frame generation adds to every rendered frame, stated rather than hidden.
129
+ *
130
+ * **A generated frame sits between two rendered ones, so it cannot be shown until the later one
131
+ * exists**, and the later one is then held back while the frames generated before it are shown:
132
+ * `displayHz / renderHz − 1` display intervals, and the generation before the first of them. At
133
+ * the render rate nothing is generated and nothing is added. The rates must be a whole multiple
134
+ * apart, or the generated frames would fall unevenly between rendered ones and the motion judder.
135
+ *
136
+ * What would make it wrong: extrapolation — generating from the earlier frame alone, ahead of the
137
+ * later — adds no hold-back and fills no hole from a frame it has not got. That is a different
138
+ * trade, and this reference does not make it.
139
+ */
140
+ export function frameGenLatency(displayHz, renderHz, generationMs) {
141
+ const ratio = displayHz / renderHz;
142
+ const whole = Math.round(ratio);
143
+ if (!(whole >= 1) || Math.abs(ratio - whole) > 1e-9) {
144
+ throw new RangeError(`frame generation: a display at ${displayHz} Hz over a render at ${renderHz} Hz is not a ` +
145
+ 'whole multiple, so generated frames would fall unevenly between rendered ones');
146
+ }
147
+ if (whole === 1)
148
+ return 0;
149
+ return ((whole - 1) * 1000) / displayHz + generationMs;
150
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The two sizes a reconstructed frame has.
3
+ *
4
+ * **A frame with a reconstruction has a render size and an output size, and every texel size is
5
+ * taken from the target it belongs to.** The scene, its depth, the multisampled pair, decals,
6
+ * reflections, the translucent set, the medium and the motion target are the render size; the
7
+ * resolve, the history, bloom and the composite are the output size. The two are one number apart
8
+ * and confusing them does not fail — it draws a picture that is subtly the wrong shape.
9
+ *
10
+ * **The projection is built from the output's aspect and never from the render's.** Each axis is
11
+ * rounded up on its own, so a render size's aspect differs from its output's by up to a texel's
12
+ * worth: at 1280 by 720 and a ratio of 1.7 that is 753 by 424, an aspect of 1.7759 against 1.7778.
13
+ * A projection built from the render size stretches the picture by that much — a fraction of a per
14
+ * cent, invisible in a screenshot and visible as a wobble every time the drawing buffer resizes.
15
+ */
16
+ /**
17
+ * Why a multisampled frame is not reconstructed, in words, so both backends read the same sentence.
18
+ *
19
+ * **The motion pass is what forbids it.** That pass draws the frame's movers again with the depth
20
+ * the scene left, testing for equality so only the pixels the scene kept are written — and an
21
+ * attachment's sample count has to agree with every other attachment in its pass, so a
22
+ * multisampled depth wants a multisampled motion target, a resolve of it, and a second set of
23
+ * everything downstream.
24
+ *
25
+ * It is also a choice nobody should want. A reconstruction's own accumulation is what antialiases
26
+ * the picture; paying for a second antialiasing at four times the fragment work, and then throwing
27
+ * three quarters of it away in a resolve, is the cost this feature exists to avoid.
28
+ */
29
+ export declare const RECONSTRUCTION_MULTISAMPLE_REFUSAL: string;
30
+ /** The render size for an output size and a `quality.reconstruction` ratio; 0 is off. */
31
+ export declare function reconRenderSize(outputWidth: number, outputHeight: number, ratio: number): {
32
+ width: number;
33
+ height: number;
34
+ };