@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,113 @@
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
+
17
+ /** YCoCg from linear red, green and blue, into `out`. Dyadic, so it round-trips exactly. */
18
+ export function rgbToYCoCg(
19
+ out: Float32Array | Float64Array,
20
+ r: number,
21
+ g: number,
22
+ b: number,
23
+ ): void {
24
+ out[0] = r * 0.25 + g * 0.5 + b * 0.25;
25
+ out[1] = r * 0.5 - b * 0.5;
26
+ out[2] = -r * 0.25 + g * 0.5 - b * 0.25;
27
+ }
28
+
29
+ /** Linear red, green and blue from YCoCg, into `out`. */
30
+ export function yCoCgToRgb(
31
+ out: Float32Array | Float64Array,
32
+ y: number,
33
+ co: number,
34
+ cg: number,
35
+ ): void {
36
+ const base = y - cg;
37
+ out[0] = base + co;
38
+ out[1] = y + cg;
39
+ out[2] = base - co;
40
+ }
41
+
42
+ /**
43
+ * The box of `count` three-channel samples: each channel's mean plus or minus `gamma` of its
44
+ * standard deviation, into `outMin` and `outMax`.
45
+ *
46
+ * **A channel whose samples all agree has that value as its box, exactly.** A mean of nine equal
47
+ * numbers is not always that number in floating point, and a box a rounding wide around the current
48
+ * colour would let a history through by a rounding instead of collapsing it onto the colour.
49
+ */
50
+ export function varianceBox(
51
+ samples: ArrayLike<number>,
52
+ count: number,
53
+ gamma: number,
54
+ outMin: Float32Array | Float64Array,
55
+ outMax: Float32Array | Float64Array,
56
+ ): void {
57
+ for (let c = 0; c < 3; c += 1) {
58
+ const first = samples[c] as number;
59
+ let same = true;
60
+ let sum = 0;
61
+ for (let i = 0; i < count; i += 1) {
62
+ const value = samples[i * 3 + c] as number;
63
+ sum += value;
64
+ if (value !== first) same = false;
65
+ }
66
+ if (same) {
67
+ outMin[c] = first;
68
+ outMax[c] = first;
69
+ continue;
70
+ }
71
+ const mean = sum / count;
72
+ let spread = 0;
73
+ for (let i = 0; i < count; i += 1) {
74
+ const d = (samples[i * 3 + c] as number) - mean;
75
+ spread += d * d;
76
+ }
77
+ const deviation = Math.sqrt(spread / count);
78
+ outMin[c] = mean - gamma * deviation;
79
+ outMax[c] = mean + gamma * deviation;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * `history` pulled into the box `min`..`max`, along the line towards the box's centre, into `out`.
85
+ *
86
+ * Unchanged inside the box; on its boundary from outside it. A channel with no extent bounds any
87
+ * history that differs from it infinitely, so such a history collapses to the centre — the honest
88
+ * answer for a flat neighbourhood, and the alternative is a division by zero.
89
+ */
90
+ export function clipToBox(
91
+ out: Float32Array | Float64Array,
92
+ history: ArrayLike<number>,
93
+ min: ArrayLike<number>,
94
+ max: ArrayLike<number>,
95
+ ): void {
96
+ let ratio = 0;
97
+ for (let c = 0; c < 3; c += 1) {
98
+ const centre = ((min[c] as number) + (max[c] as number)) * 0.5;
99
+ const offset = (history[c] as number) - centre;
100
+ const extent = ((max[c] as number) - (min[c] as number)) * 0.5;
101
+ if (extent > 1e-7) ratio = Math.max(ratio, Math.abs(offset) / extent);
102
+ else if (Math.abs(offset) > 1e-7) ratio = Number.POSITIVE_INFINITY;
103
+ }
104
+ if (!(ratio > 1)) {
105
+ for (let c = 0; c < 3; c += 1) out[c] = history[c] as number;
106
+ return;
107
+ }
108
+ const scale = Number.isFinite(ratio) ? 1 / ratio : 0;
109
+ for (let c = 0; c < 3; c += 1) {
110
+ const centre = ((min[c] as number) + (max[c] as number)) * 0.5;
111
+ out[c] = centre + ((history[c] as number) - centre) * scale;
112
+ }
113
+ }
@@ -0,0 +1,143 @@
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
+ export interface DisocclusionParams {
28
+ /** The relative depth disagreement trusted fully; trust falls to zero at twice it. */
29
+ readonly depthTolerance: number;
30
+ /** How much the tolerance grows per unit of motion, in uv. */
31
+ readonly motionScale: number;
32
+ /** The cosine between the two normals at and below which nothing is trusted. */
33
+ readonly normalFloor: number;
34
+ /** The cosine at and above which the normals are trusted fully. */
35
+ readonly normalCeiling: number;
36
+ }
37
+
38
+ /**
39
+ * A percent of depth, growing by half a percent for every hundredth of the screen the surface moved;
40
+ * normals trusted fully within sixty degrees and not at all past ninety.
41
+ */
42
+ export const DEFAULT_DISOCCLUSION: DisocclusionParams = {
43
+ depthTolerance: 0.01,
44
+ motionScale: 0.5,
45
+ normalFloor: 0,
46
+ normalCeiling: 0.5,
47
+ };
48
+
49
+ function smoothstep(edge0: number, edge1: number, x: number): number {
50
+ const t = Math.min(1, Math.max(0, (x - edge0) / (edge1 - edge0)));
51
+ return t * t * (3 - 2 * t);
52
+ }
53
+
54
+ /**
55
+ * One where the history is trustworthy, zero where it is not, and continuous between.
56
+ *
57
+ * `currDepth` is the view depth this surface should have had last frame; `histDepth` the view depth
58
+ * last frame held where it lands, or zero where it landed off the screen; `motionLength` the motion's
59
+ * length in uv; `normalDot` the cosine between the two frames' world normals there.
60
+ */
61
+ export function disocclusionWeight(
62
+ currDepth: number,
63
+ histDepth: number,
64
+ motionLength: number,
65
+ normalDot: number,
66
+ params: DisocclusionParams,
67
+ ): number {
68
+ if (!(currDepth > 0) || !(histDepth > 0) || !(motionLength >= 0) || Number.isNaN(normalDot)) {
69
+ return 0;
70
+ }
71
+ const disagreement = Math.abs(currDepth - histDepth) / currDepth;
72
+ const tolerance = params.depthTolerance + params.motionScale * motionLength;
73
+ const depth = 1 - smoothstep(tolerance, 2 * tolerance, disagreement);
74
+ const normal = smoothstep(params.normalFloor, params.normalCeiling, normalDot);
75
+ return depth * normal;
76
+ }
77
+
78
+ /**
79
+ * The world position a depth stands for: `(u, v, clipDepth)` through the inverse view-projection,
80
+ * in whatever depth convention that matrix was built for. Returns false where the matrix has no
81
+ * answer there — singular, or the point at infinity.
82
+ */
83
+ export function worldPositionFromDepth(
84
+ inverseViewProj: ArrayLike<number>,
85
+ u: number,
86
+ v: number,
87
+ clipDepth: number,
88
+ out: Float64Array,
89
+ ): boolean {
90
+ const x = u * 2 - 1;
91
+ const y = v * 2 - 1;
92
+ const m = inverseViewProj;
93
+ const w =
94
+ (m[3] as number) * x + (m[7] as number) * y + (m[11] as number) * clipDepth + (m[15] as number);
95
+ if (!(Math.abs(w) > 1e-12)) return false;
96
+ for (let r = 0; r < 3; r += 1) {
97
+ out[r] =
98
+ ((m[r] as number) * x +
99
+ (m[4 + r] as number) * y +
100
+ (m[8 + r] as number) * clipDepth +
101
+ (m[12 + r] as number)) /
102
+ w;
103
+ }
104
+ return Number.isFinite(out[0]) && Number.isFinite(out[1]) && Number.isFinite(out[2]);
105
+ }
106
+
107
+ /**
108
+ * The unit normal of the surface through `centre` and its two screen neighbours, turned to face
109
+ * `eye` — so the answer is the same whichever way the target's rows run. Returns false where the
110
+ * three are in a line: there is no surface to have a normal.
111
+ */
112
+ export function normalFromPositions(
113
+ centre: ArrayLike<number>,
114
+ right: ArrayLike<number>,
115
+ up: ArrayLike<number>,
116
+ eye: ArrayLike<number>,
117
+ out: Float64Array,
118
+ ): boolean {
119
+ const ax = (right[0] as number) - (centre[0] as number);
120
+ const ay = (right[1] as number) - (centre[1] as number);
121
+ const az = (right[2] as number) - (centre[2] as number);
122
+ const bx = (up[0] as number) - (centre[0] as number);
123
+ const by = (up[1] as number) - (centre[1] as number);
124
+ const bz = (up[2] as number) - (centre[2] as number);
125
+ let nx = ay * bz - az * by;
126
+ let ny = az * bx - ax * bz;
127
+ let nz = ax * by - ay * bx;
128
+ const length2 = nx * nx + ny * ny + nz * nz;
129
+ const scale2 = (ax * ax + ay * ay + az * az) * (bx * bx + by * by + bz * bz);
130
+ if (!(length2 > 1e-12 * scale2)) return false;
131
+ const toEye =
132
+ nx * ((eye[0] as number) - (centre[0] as number)) +
133
+ ny * ((eye[1] as number) - (centre[1] as number)) +
134
+ nz * ((eye[2] as number) - (centre[2] as number));
135
+ const inverse = (toEye < 0 ? -1 : 1) / Math.sqrt(length2);
136
+ nx *= inverse;
137
+ ny *= inverse;
138
+ nz *= inverse;
139
+ out[0] = nx;
140
+ out[1] = ny;
141
+ out[2] = nz;
142
+ return true;
143
+ }
@@ -0,0 +1,191 @@
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
+ export interface FrameImage {
35
+ readonly width: number;
36
+ readonly height: number;
37
+ readonly colour: Float32Array;
38
+ readonly depth: Float32Array;
39
+ /** Where each pixel's surface was in the frame before, as an offset in pixels. */
40
+ readonly motion: Float32Array;
41
+ }
42
+
43
+ /** Which pixel of the later frame lands on each pixel at time `t`, and at what depth. */
44
+ export interface Projection {
45
+ readonly width: number;
46
+ readonly height: number;
47
+ /** The later frame's pixel landing here, or -1 where none does. */
48
+ readonly source: Int32Array;
49
+ readonly depth: Float32Array;
50
+ }
51
+
52
+ /**
53
+ * How far two depths may differ, as a fraction of the nearer, and still be one surface.
54
+ *
55
+ * What it gives up: a surface moving toward or away from the camera changes its own depth between
56
+ * frames, and one moving five per cent of its distance in a render interval reads as a different
57
+ * surface, so it takes the later frame's colour at small `t` too — its colour a render interval
58
+ * late, not wrong.
59
+ */
60
+ const SAME_SURFACE = 0.05;
61
+
62
+ export function createProjection(width: number, height: number): Projection {
63
+ const pixels = width * height;
64
+ return { width, height, source: new Int32Array(pixels), depth: new Float32Array(pixels) };
65
+ }
66
+
67
+ /**
68
+ * Scatter the later frame's pixels to where they stand at time `t`: 0 is the earlier frame and 1
69
+ * the later. The nearest surface wins a pixel two land on.
70
+ */
71
+ export function projectForward(
72
+ motion: Float32Array,
73
+ depth: Float32Array,
74
+ t: number,
75
+ out: Projection,
76
+ ): void {
77
+ const { width, height, source } = out;
78
+ source.fill(-1);
79
+ out.depth.fill(Infinity);
80
+ const back = 1 - t;
81
+ for (let y = 0; y < height; y += 1) {
82
+ for (let x = 0; x < width; x += 1) {
83
+ const from = y * width + x;
84
+ const tx = Math.round(x + back * (motion[from * 2] as number));
85
+ const ty = Math.round(y + back * (motion[from * 2 + 1] as number));
86
+ if (tx < 0 || tx >= width || ty < 0 || ty >= height) continue;
87
+ const at = ty * width + tx;
88
+ const z = depth[from] as number;
89
+ if (z < (out.depth[at] as number)) {
90
+ out.depth[at] = z;
91
+ source[at] = from;
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ function copyColour(out: Float32Array, at: number, from: Float32Array, index: number): void {
98
+ for (let c = 0; c < 4; c += 1) out[at * 4 + c] = from[index * 4 + c] as number;
99
+ }
100
+
101
+ /**
102
+ * Colour every projected pixel from the frame nearer in time, and mark every pixel nothing landed on
103
+ * — whose colour is left for `fillHoles`.
104
+ *
105
+ * The earlier frame is used only where it shows the same surface where the motion says it was: its
106
+ * depth there within `SAME_SURFACE` of the later frame's. Where it does not, the surface was hidden
107
+ * in it, and the later frame is the only one that saw it.
108
+ */
109
+ export function resolveGenerated(
110
+ projection: Projection,
111
+ before: FrameImage,
112
+ after: FrameImage,
113
+ t: number,
114
+ out: Float32Array,
115
+ mask: Uint8Array,
116
+ ): void {
117
+ const { width, height, source } = projection;
118
+ const early = t < 0.5;
119
+ for (let at = 0; at < source.length; at += 1) {
120
+ const from = source[at] as number;
121
+ if (from < 0) {
122
+ mask[at] = 1;
123
+ continue;
124
+ }
125
+ mask[at] = 0;
126
+ if (early) {
127
+ const x = Math.round((from % width) + (after.motion[from * 2] as number));
128
+ const y = Math.round(Math.floor(from / width) + (after.motion[from * 2 + 1] as number));
129
+ if (x >= 0 && x < width && y >= 0 && y < height) {
130
+ const was = y * width + x;
131
+ const then = before.depth[was] as number;
132
+ const now = after.depth[from] as number;
133
+ if (Math.abs(then - now) <= SAME_SURFACE * Math.min(then, now)) {
134
+ copyColour(out, at, before.colour, was);
135
+ continue;
136
+ }
137
+ }
138
+ }
139
+ copyColour(out, at, after.colour, from);
140
+ }
141
+ }
142
+
143
+ /** Fill every marked pixel from the farther of the two frames' surfaces there. The mark stays. */
144
+ export function fillHoles(
145
+ out: Float32Array,
146
+ before: FrameImage,
147
+ after: FrameImage,
148
+ mask: Uint8Array,
149
+ ): void {
150
+ for (let at = 0; at < mask.length; at += 1) {
151
+ if (mask[at] !== 1) continue;
152
+ const behind = (before.depth[at] as number) > (after.depth[at] as number) ? before : after;
153
+ copyColour(out, at, behind.colour, at);
154
+ }
155
+ }
156
+
157
+ /** The interface over the generated frame, premultiplied, from its own layer and never projected. */
158
+ export function composeInterface(out: Float32Array, overlay: Float32Array): void {
159
+ for (let i = 0; i < out.length; i += 4) {
160
+ const keep = 1 - (overlay[i + 3] as number);
161
+ for (let c = 0; c < 4; c += 1) {
162
+ out[i + c] = (overlay[i + c] as number) + (out[i + c] as number) * keep;
163
+ }
164
+ }
165
+ }
166
+
167
+ /**
168
+ * The milliseconds frame generation adds to every rendered frame, stated rather than hidden.
169
+ *
170
+ * **A generated frame sits between two rendered ones, so it cannot be shown until the later one
171
+ * exists**, and the later one is then held back while the frames generated before it are shown:
172
+ * `displayHz / renderHz − 1` display intervals, and the generation before the first of them. At
173
+ * the render rate nothing is generated and nothing is added. The rates must be a whole multiple
174
+ * apart, or the generated frames would fall unevenly between rendered ones and the motion judder.
175
+ *
176
+ * What would make it wrong: extrapolation — generating from the earlier frame alone, ahead of the
177
+ * later — adds no hold-back and fills no hole from a frame it has not got. That is a different
178
+ * trade, and this reference does not make it.
179
+ */
180
+ export function frameGenLatency(displayHz: number, renderHz: number, generationMs: number): number {
181
+ const ratio = displayHz / renderHz;
182
+ const whole = Math.round(ratio);
183
+ if (!(whole >= 1) || Math.abs(ratio - whole) > 1e-9) {
184
+ throw new RangeError(
185
+ `frame generation: a display at ${displayHz} Hz over a render at ${renderHz} Hz is not a ` +
186
+ 'whole multiple, so generated frames would fall unevenly between rendered ones',
187
+ );
188
+ }
189
+ if (whole === 1) return 0;
190
+ return ((whole - 1) * 1000) / displayHz + generationMs;
191
+ }
@@ -0,0 +1,64 @@
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
+ /**
18
+ * Why a multisampled frame is not reconstructed, in words, so both backends read the same sentence.
19
+ *
20
+ * **The motion pass is what forbids it.** That pass draws the frame's movers again with the depth
21
+ * the scene left, testing for equality so only the pixels the scene kept are written — and an
22
+ * attachment's sample count has to agree with every other attachment in its pass, so a
23
+ * multisampled depth wants a multisampled motion target, a resolve of it, and a second set of
24
+ * everything downstream.
25
+ *
26
+ * It is also a choice nobody should want. A reconstruction's own accumulation is what antialiases
27
+ * the picture; paying for a second antialiasing at four times the fragment work, and then throwing
28
+ * three quarters of it away in a resolve, is the cost this feature exists to avoid.
29
+ */
30
+ export const RECONSTRUCTION_MULTISAMPLE_REFUSAL =
31
+ 'driftengine: a reconstruction draws its movers again against the depth the scene left, and ' +
32
+ 'every attachment in a pass must agree about its sample count — so reconstruction is off ' +
33
+ 'wherever `sceneSamples` is above one. The accumulation is the antialiasing; the two are a ' +
34
+ 'choice of one.';
35
+
36
+ /** The render size for an output size and a `quality.reconstruction` ratio; 0 is off. */
37
+ export function reconRenderSize(
38
+ outputWidth: number,
39
+ outputHeight: number,
40
+ ratio: number,
41
+ ): { width: number; height: number } {
42
+ const width = Math.max(1, Math.floor(outputWidth));
43
+ const height = Math.max(1, Math.floor(outputHeight));
44
+ /*
45
+ * **Anything that is not a ratio above one draws at the output size**: off, a ratio of exactly
46
+ * one, and — the case that matters — a ratio *below* one, which divides the other way and would
47
+ * ask the renderer to draw more pixels than it shows. `resolveRenderQuality` never produces one,
48
+ * and this is a public function that a caller reaches with whatever number they have. `NaN`
49
+ * lands here too, which `ratio <= 0` would have sent through the divide to a size of `NaN`.
50
+ */
51
+ if (!(ratio > 1)) return { width, height };
52
+ /*
53
+ * Up, never down: rounding down draws fewer pixels than the ratio says, which is a frame-rate win
54
+ * nobody asked for and a softer picture they did not agree to.
55
+ *
56
+ * **The floor of one is not redundant**, which taking it out and watching nothing fail suggested
57
+ * it was. A ceiling of a positive quotient is at least one for every finite ratio — and an
58
+ * infinite one divides to zero, so the size comes back zero by zero, which a device refuses.
59
+ */
60
+ return {
61
+ width: Math.max(1, Math.ceil(width / ratio)),
62
+ height: Math.max(1, Math.ceil(height / ratio)),
63
+ };
64
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * The sub-pixel sequence a frame is rasterised along, for the temporal resolve and for
3
+ * reconstruction.
4
+ *
5
+ * **One sequence, two consumers.** `temporalAa.ts` jitters a frame at its output size along eight
6
+ * phases; DriftTR jitters a frame rendered below its output size, and needs more phases for the
7
+ * same reason a smaller render needs more frames to cover the output — each render pixel stands
8
+ * for several output pixels, and the sequence has to visit each of their positions before it
9
+ * repeats. The eight-phase sequence is the numbers the temporal resolve always used, so its
10
+ * captures do not move.
11
+ *
12
+ * **What is reused rather than rebuilt**, from `temporalAa.ts`: Halton in bases two and three, each
13
+ * period centred on its own mean, and `jitterProjection`, which puts the offset into clip space
14
+ * rather than into the projection's third column. See that function for why the third column is
15
+ * wrong for the combined view-projection this engine draws with.
16
+ */
17
+
18
+ /**
19
+ * The radical inverse of `index` in `base`: the digits of `index` mirrored about the point.
20
+ *
21
+ * Consecutive indices land as far from each other as the base allows, which is what lets eight of
22
+ * them cover a pixel evenly where eight random ones leave holes and pairs.
23
+ */
24
+ export function halton(index: number, base: number): number {
25
+ let result = 0;
26
+ let fraction = 1;
27
+ let i = index;
28
+ while (i > 0) {
29
+ fraction /= base;
30
+ result += fraction * (i % base);
31
+ i = Math.floor(i / base);
32
+ }
33
+ return result;
34
+ }
35
+
36
+ /* One table a phase count, built once: x then y a phase. */
37
+ const TABLES = new Map<number, Float64Array>();
38
+
39
+ /**
40
+ * The period's offsets, centred so they sum to zero.
41
+ *
42
+ * **Halton's own mean is not the middle of the pixel** — eight points in base two average 57/128 —
43
+ * and accumulating towards an off-centre mean resolves to a picture displaced from the depth
44
+ * buffer it is tested against and from every pass that did not jitter. Subtracting the period's
45
+ * own mean costs nothing and makes the property exact.
46
+ */
47
+ export function jitterTable(phases: number): Float64Array {
48
+ const count = Math.max(1, Math.floor(phases));
49
+ let table = TABLES.get(count);
50
+ if (table !== undefined) return table;
51
+ table = new Float64Array(count * 2);
52
+ let meanX = 0;
53
+ let meanY = 0;
54
+ for (let i = 0; i < count; i += 1) {
55
+ table[i * 2] = halton(i + 1, 2);
56
+ table[i * 2 + 1] = halton(i + 1, 3);
57
+ meanX += table[i * 2] as number;
58
+ meanY += table[i * 2 + 1] as number;
59
+ }
60
+ meanX /= count;
61
+ meanY /= count;
62
+ for (let i = 0; i < count; i += 1) {
63
+ table[i * 2] = (table[i * 2] as number) - meanX;
64
+ table[i * 2 + 1] = (table[i * 2 + 1] as number) - meanY;
65
+ }
66
+ TABLES.set(count, table);
67
+ return table;
68
+ }
69
+
70
+ /**
71
+ * Where in its pixel frame `frame` samples, in pixels and centred on zero, on a sequence of
72
+ * `phases` positions. Written into `out`, two floats.
73
+ */
74
+ export function jitterOffset(frame: number, phases: number, out: Float32Array): void {
75
+ const table = jitterTable(phases);
76
+ const count = table.length / 2;
77
+ const at = ((frame % count) + count) % count;
78
+ out[0] = table[at * 2] as number;
79
+ out[1] = table[at * 2 + 1] as number;
80
+ }
81
+
82
+ /** The temporal resolve's own count, and the fewest a reconstruction takes. */
83
+ const BASE_PHASES = 8;
84
+
85
+ /**
86
+ * How many phases a reconstruction from `renderWidth` to `outputWidth` takes: eight for every
87
+ * output pixel one render pixel covers, rounded up — and eight where the render is not smaller.
88
+ *
89
+ * The count the published temporal upscalers use, and the reason is coverage rather than taste: a
90
+ * render pixel two thirds of an output pixel wide stands for 2.25 output pixels, and eight positions
91
+ * an output pixel is what the temporal resolve already found enough.
92
+ */
93
+ export function reconJitterPhases(renderWidth: number, outputWidth: number): number {
94
+ if (!(renderWidth > 0) || !(outputWidth > renderWidth)) return BASE_PHASES;
95
+ const ratio = outputWidth / renderWidth;
96
+ return Math.ceil(BASE_PHASES * ratio * ratio);
97
+ }
98
+
99
+ /**
100
+ * `source` moved in clip space by `jitter`, which is what a contributed pass does with the frame's
101
+ * jitter (`PrepareContext.jitter`) to draw where the renderer's own verbs drew this frame.
102
+ *
103
+ * **In the camera's own convention, before any correction**: `jitter` is a fraction of the clip
104
+ * square, x rightward and y upward as `mat4.perspective` has them, so the matrix it applies to is
105
+ * the one the consumer built — a pass then multiplies by `clipCorrection` or `depthCorrection`
106
+ * exactly as it would have, and the offset arrives on screen where the renderer's did. Scaled by w,
107
+ * as `jitterProjection` is, so it is a constant screen offset at every depth.
108
+ *
109
+ * **A zero jitter leaves a finite matrix bit for bit** — each term gains a zero — so a frame that is
110
+ * not reconstructed draws exactly what it drew before this existed.
111
+ */
112
+ export function jitterClip(
113
+ out: Float32Array,
114
+ source: ArrayLike<number>,
115
+ jitter: ArrayLike<number>,
116
+ ): Float32Array {
117
+ for (let i = 0; i < 16; i += 1) out[i] = source[i] as number;
118
+ const x = jitter[0] as number;
119
+ const y = jitter[1] as number;
120
+ for (let column = 0; column < 4; column += 1) {
121
+ const w = source[column * 4 + 3] as number;
122
+ out[column * 4] = (out[column * 4] as number) + x * w;
123
+ out[column * 4 + 1] = (out[column * 4 + 1] as number) + y * w;
124
+ }
125
+ return out;
126
+ }