@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
@@ -1,4 +1,5 @@
1
1
  import { FrameBudget } from '../budget.js';
2
+ import { MaterialChanges, ownsMaterial } from '../materialChanges.js';
2
3
  import { mat4 } from 'gl-matrix';
3
4
  import { DEPTH_CLEAR, DEPTH_OFFSET_SIGN, GL_DEPTH_REMAP, MAX_DEPTH_LAYER, depthOffsetForLayer, GL_SHADOW_REMAP, REVERSED_DEPTH, SHADOW_DEPTH_CLEAR, glDepthFuncEqual, glShadowDepthFunc, } from '../../depthConvention.js';
4
5
  import { PickableSet } from '../../pickable.js';
@@ -11,6 +12,7 @@ import { REFLECTION_EDGE_FADE, ReflectionQueue } from '../../screenSpaceReflecti
11
12
  import { DecalQueue } from '../../decalQueue.js';
12
13
  import { OitPass } from '../../oitPass.js';
13
14
  import { OIT_MULTISAMPLE_REFUSAL } from '../../orderIndependent.js';
15
+ import { INDIRECT_LIGHT_WEBGL2_REFUSAL } from '../../gi/probeTrace.js';
14
16
  import { TranslucentQueue } from '../../translucentQueue.js';
15
17
  import { createFrustum, frustumFromViewProjection } from '../../../math/frustum.js';
16
18
  import { OcclusionBuffer } from '../../occlusion.js';
@@ -34,7 +36,7 @@ import { SkinPaletteTexture } from './skinPaletteTexture.js';
34
36
  /* The codes the shader reads, stated once in `vertexDefaults.ts` for both backends. */
35
37
  import { LIGHT_VOLUME_VERT, lightVolumeFrag } from '../../shaders/lightVolume.js';
36
38
  import { PANEL_FRAG, PANEL_VERT } from '../../shaders/panel.js';
37
- import { ReflectionProbe } from '../../reflectionProbe.js';
39
+ import { ReflectionProbe, cubeFaceProjection } from '../../reflectionProbe.js';
38
40
  import { EnvProbeArray } from '../../envProbeArray.js';
39
41
  import { ProbeGrid, SINGLE_PROBE, UNIT_STEP, WORLD_ORIGIN, sameGrid } from '../../probeGrid.js';
40
42
  import { octahedralEdgeFor } from '../../prefilterEnvMap.js';
@@ -749,6 +751,13 @@ export class WebGL2Renderer {
749
751
  reversedDepth = false;
750
752
  /** `GL_DEPTH_REMAP * camera.viewProjection`, rebuilt once a frame. */
751
753
  sceneViewProj = new Float32Array(16);
754
+ /**
755
+ * The same matrix with clip y negated, for the six faces of a probe.
756
+ *
757
+ * Its own buffer rather than `sceneViewProj`, because `cubeFaceProjection` reads what
758
+ * `sceneMatrix` just wrote and the two would be the same array.
759
+ */
760
+ cubeFaceViewProj = new Float32Array(16);
752
761
  /**
753
762
  * One buffer per shadow matrix that outlives a call, and that is not fussiness.
754
763
  *
@@ -776,7 +785,9 @@ export class WebGL2Renderer {
776
785
  * the camera's matrix unchanged and multiplies nothing.
777
786
  */
778
787
  viewProjFor(camera) {
779
- const scene = this.sceneMatrix(camera.viewProjection);
788
+ const scene = this.probePassActive
789
+ ? cubeFaceProjection(this.cubeFaceViewProj, this.sceneMatrix(camera.viewProjection))
790
+ : this.sceneMatrix(camera.viewProjection);
780
791
  /*
781
792
  * **The jitter goes on here and nowhere else.** This is the one funnel every geometry upload
782
793
  * passes through, so one line covers the mesh passes, the sky, the water and the effects
@@ -865,6 +876,7 @@ export class WebGL2Renderer {
865
876
  */
866
877
  casterSink = {
867
878
  mesh: (mesh, model) => {
879
+ this.shadowDrawBudget.ask();
868
880
  const { gl } = this;
869
881
  gl.uniformMatrix4fv(this.depthUniforms['uModel'] ?? null, false, model);
870
882
  /*
@@ -886,6 +898,7 @@ export class WebGL2Renderer {
886
898
  const count = Math.min(data.count, gpuBatch.capacity);
887
899
  if (count === 0)
888
900
  return;
901
+ this.shadowDrawBudget.ask();
889
902
  const u = this.depthInstancedUniforms;
890
903
  gl.useProgram(this.depthInstancedProgram);
891
904
  gl.uniformMatrix4fv(u['uLightViewProj'] ?? null, false, this.activeDepthViewProj);
@@ -896,6 +909,7 @@ export class WebGL2Renderer {
896
909
  gl.useProgram(this.depthProgram);
897
910
  },
898
911
  skinnedMesh: (mesh, model, palette) => {
912
+ this.shadowDrawBudget.ask();
899
913
  const { gl } = this;
900
914
  const u = this.depthSkinnedUniforms;
901
915
  gl.useProgram(this.depthSkinnedProgram);
@@ -920,6 +934,7 @@ export class WebGL2Renderer {
920
934
  scatter: (scatter, data, windX, windZ, windGust, timeSeconds, trample = null) => {
921
935
  if (data.count === 0)
922
936
  return;
937
+ this.scatterDepthBudget.ask();
923
938
  const { gl } = this;
924
939
  const u = this.scatterDepthUniforms;
925
940
  gl.useProgram(this.scatterDepthProgram);
@@ -1035,6 +1050,39 @@ export class WebGL2Renderer {
1035
1050
  addOccluder(min, max, model) {
1036
1051
  this.occlusion?.addOccluder(min, max, model);
1037
1052
  }
1053
+ /**
1054
+ * Declare a baked distance field that indirect light may be traced against.
1055
+ *
1056
+ * **Recorded by nothing on this backend, and that is the refusal rather than an oversight.**
1057
+ * Composing the world's field and marching probes through it is compute, and WebGL2 has no
1058
+ * compute stage — `INDIRECT_LIGHT_WEBGL2_REFUSAL` says so once a frame-loop when
1059
+ * `quality.indirectLight` is on. The method exists here because `RendererApi` is this class's
1060
+ * shape, and a consumer that declares its fields unconditionally must not have to ask which
1061
+ * backend it got: this is a no-op for the same reason `addOccluder` is one when the profile
1062
+ * asked for no occlusion buffer.
1063
+ *
1064
+ * The field is in the model matrix's own space and the matrix must carry uniform scale only.
1065
+ * `composeGlobalField` gives the reason: a distance is not preserved by a non-uniform scale.
1066
+ */
1067
+ addDistanceField(_field, _model, _albedo) {
1068
+ /* Deliberately nothing. See the comment above. */
1069
+ }
1070
+ /** Forget the fields declared this frame. A no-op here, as `addDistanceField` is. */
1071
+ clearDistanceFields() {
1072
+ /* Deliberately nothing. See `addDistanceField`. */
1073
+ }
1074
+ /** Never measured here, because nothing is composed. See `addDistanceField`. */
1075
+ get distanceFieldMs() {
1076
+ return null;
1077
+ }
1078
+ /** Never traced here either, so there is no refresh to time. See `addDistanceField`. */
1079
+ get indirectBakeMs() {
1080
+ return null;
1081
+ }
1082
+ /** Nothing to read, for the same reason. A consumer may call it unconditionally. */
1083
+ readDistanceFieldTimings() {
1084
+ /* Deliberately nothing. See `addDistanceField`. */
1085
+ }
1038
1086
  /**
1039
1087
  * Whether a mesh is entirely behind the occluders declared this frame.
1040
1088
  *
@@ -1066,7 +1114,14 @@ export class WebGL2Renderer {
1066
1114
  registerPass(definition) {
1067
1115
  const handle = registerIn(this.passes, definition);
1068
1116
  /* Identity: this backend's clip space is the one the projections are built for. */
1069
- this.passDevice ??= { backend: 'webgl2', gl: this.gl, clipCorrection: IDENTITY_CLIP };
1117
+ /* Both are identity here: this backend runs the GLSL natively, so there is nothing to
1118
+ correct and nothing a generator has flipped. */
1119
+ this.passDevice ??= {
1120
+ backend: 'webgl2',
1121
+ gl: this.gl,
1122
+ clipCorrection: IDENTITY_CLIP,
1123
+ depthCorrection: IDENTITY_CLIP,
1124
+ };
1070
1125
  if (definition.prepare !== undefined)
1071
1126
  this.preparingPasses++;
1072
1127
  definition.init?.(this.passDevice);
@@ -2093,6 +2148,7 @@ export class WebGL2Renderer {
2093
2148
  setMaterial(material) {
2094
2149
  if (this.contextLost)
2095
2150
  return;
2151
+ this.materials.dirty();
2096
2152
  this.currentSurfaceTexture = material?.albedo ?? null;
2097
2153
  /*
2098
2154
  * Written to every flat program, because material state persists across draws and a skinned
@@ -2244,6 +2300,7 @@ export class WebGL2Renderer {
2244
2300
  setSurfaceReflectivity(amount) {
2245
2301
  if (this.contextLost)
2246
2302
  return;
2303
+ this.materials.dirty();
2247
2304
  this.useFlatProgram();
2248
2305
  this.gl.uniform1f(this.flatUniforms['uReflectivity'] ?? null, Math.min(1, Math.max(0, amount)));
2249
2306
  }
@@ -2262,6 +2319,7 @@ export class WebGL2Renderer {
2262
2319
  setEnvironmentGain(gain) {
2263
2320
  if (this.contextLost)
2264
2321
  return;
2322
+ this.materials.dirty();
2265
2323
  this.useFlatProgram();
2266
2324
  this.gl.uniform1f(this.flatUniforms['uEnvironmentGain'] ?? null, Math.max(0, gain));
2267
2325
  }
@@ -2289,6 +2347,7 @@ export class WebGL2Renderer {
2289
2347
  setSurfaceGrain(amount) {
2290
2348
  if (this.contextLost)
2291
2349
  return;
2350
+ this.materials.dirty();
2292
2351
  this.useFlatProgram();
2293
2352
  this.gl.uniform1f(this.flatUniforms['uGrain'] ?? null, Math.min(1, Math.max(0, amount)));
2294
2353
  }
@@ -2318,6 +2377,7 @@ export class WebGL2Renderer {
2318
2377
  setSurfaceRelief(amount, cyclesPerMetre = 60) {
2319
2378
  if (this.contextLost)
2320
2379
  return;
2380
+ this.materials.dirty();
2321
2381
  this.useFlatProgram();
2322
2382
  const u = this.flatUniforms;
2323
2383
  this.gl.uniform1f(u['uRelief'] ?? null, Math.min(1, Math.max(0, amount)));
@@ -2351,6 +2411,7 @@ export class WebGL2Renderer {
2351
2411
  setSurfaceTextureRelief(scale) {
2352
2412
  if (this.contextLost)
2353
2413
  return;
2414
+ this.materials.dirty();
2354
2415
  this.useFlatProgram();
2355
2416
  this.gl.uniform1f(this.flatUniforms['uTextureRelief'] ?? null, Number.isFinite(scale) ? scale : 0);
2356
2417
  }
@@ -2378,6 +2439,7 @@ export class WebGL2Renderer {
2378
2439
  setEmissiveGain(gain) {
2379
2440
  if (this.contextLost)
2380
2441
  return;
2442
+ this.materials.dirty();
2381
2443
  this.useFlatProgram();
2382
2444
  this.gl.uniform1f(this.flatUniforms['uEmissiveGain'] ?? null, gain);
2383
2445
  }
@@ -2482,6 +2544,11 @@ export class WebGL2Renderer {
2482
2544
  const lit = options.lit ?? true;
2483
2545
  const fog = options.fog ?? true;
2484
2546
  const toneMapped = options.toneMapped ?? true;
2547
+ /* An instanced draw does not refract. See `materialChanges.ts`. */
2548
+ const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting: false });
2549
+ if (own)
2550
+ this.materials.dirty();
2551
+ this.takeMaterial();
2485
2552
  const depthWrite = options.depthWrite ?? true;
2486
2553
  const layer = Math.min(Math.max(Math.round(options.depthLayer ?? 0), 0), MAX_DEPTH_LAYER);
2487
2554
  if (opacity < 1)
@@ -2559,6 +2626,8 @@ export class WebGL2Renderer {
2559
2626
  gl.uniform1i(u['uFogEnabled'] ?? null, 1);
2560
2627
  if (!toneMapped)
2561
2628
  gl.uniform1i(u['uOutputTransform'] ?? null, this.gradeCode());
2629
+ if (own)
2630
+ this.materials.dirty();
2562
2631
  this.useFlatProgram();
2563
2632
  }
2564
2633
  disposeMesh(mesh) {
@@ -2657,7 +2726,9 @@ export class WebGL2Renderer {
2657
2726
  // raining dust into the sea.
2658
2727
  const surface = env.underwater?.surfaceY;
2659
2728
  const submerged = surface !== undefined && (camera.position[1] ?? 0) < surface;
2660
- streaks.draw(this.gl, this.frameViewFor(camera), wind, timeSeconds, tint, submerged);
2729
+ if (streaks.draw(this.gl, this.frameViewFor(camera), wind, timeSeconds, tint, submerged)) {
2730
+ this.windStreakBudget.ask();
2731
+ }
2661
2732
  }
2662
2733
  /**
2663
2734
  * A 3D text object: one string, drawn as instanced glyph cubes over the
@@ -2682,7 +2753,9 @@ export class WebGL2Renderer {
2682
2753
  * whatever box the caller lays out in, and the game's own card is not always the canvas.
2683
2754
  */
2684
2755
  drawText(text, viewportWidth, viewportHeight, originX, originY, style, timeSec) {
2685
- text.draw(viewportWidth, viewportHeight, originX, originY, style, timeSec);
2756
+ if (text.draw(viewportWidth, viewportHeight, originX, originY, style, timeSec)) {
2757
+ this.textBudget.ask();
2758
+ }
2686
2759
  }
2687
2760
  /** Width of the string this handle currently holds, in pixels at a given cell size. */
2688
2761
  textWidth(text, cellSize) {
@@ -2757,6 +2830,7 @@ export class WebGL2Renderer {
2757
2830
  return;
2758
2831
  /* Geometry, so the remapped matrix: `frameViewProj` itself stays raw for the motion blur. */
2759
2832
  if (handle.draw(this.sceneMatrix(viewProj), model, color, opacity, this.gradeCode(), this.gradeExposure())) {
2833
+ this.sdfTextBudget.ask();
2760
2834
  this.restoreSurfaceTextureUnit();
2761
2835
  }
2762
2836
  }
@@ -2768,6 +2842,7 @@ export class WebGL2Renderer {
2768
2842
  return new FlockRenderer(this.gl, count);
2769
2843
  }
2770
2844
  drawFlock(flock, camera, timeSeconds, params, tint, windX = 0, windZ = 0) {
2845
+ this.flockBudget.ask();
2771
2846
  flock.draw(this.gl, this.frameViewFor(camera), timeSeconds, params, tint, windX, windZ);
2772
2847
  }
2773
2848
  /**
@@ -2864,8 +2939,11 @@ export class WebGL2Renderer {
2864
2939
  return;
2865
2940
  const { gl } = this;
2866
2941
  const u = batch.uniforms;
2867
- gl.useProgram(batch.program);
2868
2942
  const count = batch.upload(gl, data);
2943
+ if (count === 0)
2944
+ return;
2945
+ this.boltBudget.ask();
2946
+ gl.useProgram(batch.program);
2869
2947
  gl.uniformMatrix4fv(u['uViewProj'] ?? null, false, this.viewProjFor(camera));
2870
2948
  gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
2871
2949
  gl.uniform1f(u['uTime'] ?? null, timeSeconds);
@@ -2917,8 +2995,11 @@ export class WebGL2Renderer {
2917
2995
  return;
2918
2996
  const { gl } = this;
2919
2997
  const u = lines.uniforms;
2920
- gl.useProgram(lines.program);
2921
2998
  const count = lines.upload(gl, data);
2999
+ if (count === 0)
3000
+ return;
3001
+ this.lineBudget.ask();
3002
+ gl.useProgram(lines.program);
2922
3003
  gl.uniformMatrix4fv(u['uViewProj'] ?? null, false, this.viewProjFor(camera));
2923
3004
  gl.uniformMatrix4fv(u['uModel'] ?? null, false, model);
2924
3005
  gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
@@ -3093,6 +3174,7 @@ export class WebGL2Renderer {
3093
3174
  drawWater(water, camera, timeSeconds, settings, env, windX = 0, windZ = 0) {
3094
3175
  if (!this.quality.water)
3095
3176
  return;
3177
+ this.waterBudget.ask();
3096
3178
  water.draw(this.gl, this.frameViewFor(camera), timeSeconds, settings, env.directionalDir, env.directionalColor, env.ambient, env, this.quality.underwaterAtmosphere, this.reflectionReadyThisFrame ? this.planarReflection : null, env, this.quality.pointLightFalloff, windX, windZ);
3097
3179
  }
3098
3180
  /**
@@ -3102,7 +3184,9 @@ export class WebGL2Renderer {
3102
3184
  drawCaustics(caustics, camera, timeSeconds, env, windX = 0, windZ = 0, strength = 1) {
3103
3185
  if (caustics === null || !this.quality.water)
3104
3186
  return;
3105
- caustics.draw(this.gl, this.frameViewFor(camera), timeSeconds, env.directionalDir, env.directionalColor, env.ambient, env, this.quality.underwaterAtmosphere, windX, windZ, strength);
3187
+ const drew = caustics.draw(this.gl, this.frameViewFor(camera), timeSeconds, env.directionalDir, env.directionalColor, env.ambient, env, this.quality.underwaterAtmosphere, windX, windZ, strength);
3188
+ if (drew)
3189
+ this.causticsBudget.ask();
3106
3190
  }
3107
3191
  /**
3108
3192
  * Begin a scene render mirrored across a horizontal plane. Draw ordinary
@@ -3160,6 +3244,21 @@ export class WebGL2Renderer {
3160
3244
  get aspect() {
3161
3245
  return this.canvas.width / Math.max(this.canvas.height, 1);
3162
3246
  }
3247
+ /**
3248
+ * The size the world is drawn at, which on this backend is always the drawing buffer.
3249
+ *
3250
+ * **Here so that a contributed pass has one question to ask on both backends.** WebGPU can draw
3251
+ * the world smaller than the canvas and let its composite enlarge it — `quality.reconstruction`
3252
+ * — and a pass filling a target of its own has to follow that size or draw a picture the frame
3253
+ * pass clips. This backend has no compute stage and no reconstruction, so the answer never moves;
3254
+ * a pass that reads it is correct on both, and one that reads `canvas.width` is correct on one.
3255
+ */
3256
+ get sceneWidth() {
3257
+ return Math.max(1, this.canvas.width);
3258
+ }
3259
+ get sceneHeight() {
3260
+ return Math.max(1, this.canvas.height);
3261
+ }
3163
3262
  /**
3164
3263
  * Point rendering back at the frame's own target, whole.
3165
3264
  *
@@ -4001,6 +4100,9 @@ export class WebGL2Renderer {
4001
4100
  fillPanel(rect, color, alpha) {
4002
4101
  if (alpha <= 0 || rect.width <= 0 || rect.height <= 0)
4003
4102
  return;
4103
+ /* Counted against no ceiling: the other backend refuses past its own, and a consumer here
4104
+ should be able to see that coming. See `budget.ts`. */
4105
+ this.panelBudget.ask();
4004
4106
  const { gl } = this;
4005
4107
  gl.useProgram(this.panelProgram);
4006
4108
  gl.bindVertexArray(this.panelVao);
@@ -4271,6 +4373,25 @@ export class WebGL2Renderer {
4271
4373
  */
4272
4374
  budget = new FrameBudget();
4273
4375
  drawBudget = this.budget.line('draws', null);
4376
+ /**
4377
+ * Every line the other backend declares, in its order and with none of its ceilings.
4378
+ *
4379
+ * **Counted after the same guards**, so one scene reports one number on both: the verbs each
4380
+ * ask once they are past the checks that make them draw nothing on either backend — a panel
4381
+ * with no alpha, a string with no glyphs, a beam with no strength, a calm wind — and a material
4382
+ * change is counted by the rule both share (`materialChanges.ts`). `webgpu/renderer.test.ts`
4383
+ * runs one scene through both and compares every line.
4384
+ */
4385
+ materialBudget = this.budget.line('materials', null);
4386
+ /** Whether the next mesh draw shares the open material or opens one, by the rule both count. */
4387
+ materials = new MaterialChanges();
4388
+ /** A mesh draw: counted as a material change when something has changed the material since. */
4389
+ takeMaterial() {
4390
+ if (this.materials.open)
4391
+ return;
4392
+ this.materialBudget.ask();
4393
+ this.materials.slot = 0;
4394
+ }
4274
4395
  /**
4275
4396
  * Declared here and never asked, because this backend builds none.
4276
4397
  *
@@ -4282,6 +4403,19 @@ export class WebGL2Renderer {
4282
4403
  * being compared against should also be zero once the other backend's cache is warm.
4283
4404
  */
4284
4405
  bindGroupBudget = this.budget.line('bind groups', null);
4406
+ shadowDrawBudget = this.budget.line('shadow draws', null);
4407
+ scatterDepthBudget = this.budget.line('scatter shadow draws', null);
4408
+ waterBudget = this.budget.line('water bodies', null);
4409
+ lightVolumeBudget = this.budget.line('light volumes', null);
4410
+ windStreakBudget = this.budget.line('wind streak fields', null);
4411
+ flockBudget = this.budget.line('flocks', null);
4412
+ boltBudget = this.budget.line('bolt batches', null);
4413
+ causticsBudget = this.budget.line('caustics', null);
4414
+ textBudget = this.budget.line('text draws', null);
4415
+ sdfTextBudget = this.budget.line('sdf text draws', null);
4416
+ lineBudget = this.budget.line('line draws', null);
4417
+ /** The other backend's panel ceiling, reported here as a count with none. */
4418
+ panelBudget = this.budget.line('panels', null);
4285
4419
  /** What the frame just drawn asked for. See `budget.ts`, and the note on `budget` above. */
4286
4420
  get frameBudget() {
4287
4421
  return this.budget;
@@ -4372,6 +4506,8 @@ export class WebGL2Renderer {
4372
4506
  * from one `RenderQuality` — see `OIT_MULTISAMPLE_REFUSAL` for why it is a constant and not two
4373
4507
  * literals kept in step by hand.
4374
4508
  */
4509
+ /** Said once rather than every frame, as the translucent set's own refusal is. */
4510
+ indirectLightRefused = false;
4375
4511
  refuseOitMultisampled() {
4376
4512
  if (this.oitMultisampleRefused)
4377
4513
  return;
@@ -4382,6 +4518,15 @@ export class WebGL2Renderer {
4382
4518
  if (this.contextLost)
4383
4519
  return;
4384
4520
  this.budget.reset();
4521
+ this.materials.dirty();
4522
+ /*
4523
+ * Said once, for the reason `refuseOitMultisampled` gives: a quality setting that is enabled
4524
+ * and does nothing is the fault the capability clamp exists to prevent.
4525
+ */
4526
+ if (this.quality.indirectLight && !this.indirectLightRefused) {
4527
+ this.indirectLightRefused = true;
4528
+ console.warn(INDIRECT_LIGHT_WEBGL2_REFUSAL);
4529
+ }
4385
4530
  const { gl } = this;
4386
4531
  this.reflectionReadyThisFrame = false;
4387
4532
  /*
@@ -4624,6 +4769,16 @@ export class WebGL2Renderer {
4624
4769
  this.translucentQueue.length > 0) {
4625
4770
  const flat = this.flatUniforms;
4626
4771
  const options = this.oitReplayOptions;
4772
+ /*
4773
+ * **The copy a refracting pane reads is taken here, before the buffers are bound.** Taking
4774
+ * it puts the scene's framebuffer back as the one drawn into, so taken inside the replay —
4775
+ * at the first pane that refracts, which is where it was taken until 2026-09-19 — it sent
4776
+ * that pane into the scene instead of the accumulation, and every refracting pane came out
4777
+ * flat paint with the effect on. The opaque frame is finished here, which is what a pane
4778
+ * should show; the latch then serves every pane in the replay. Only when something refracts.
4779
+ */
4780
+ if (this.translucentQueue.refracts)
4781
+ this.sceneTarget?.snapshotColor();
4627
4782
  this.oit.accumulateOit(this.canvas.width, this.canvas.height, oitDepth, (weighted) => {
4628
4783
  this.oitReplaying = true;
4629
4784
  this.useFlatProgram();
@@ -4795,6 +4950,8 @@ export class WebGL2Renderer {
4795
4950
  }
4796
4951
  /** Bind the flat pass once per frame; then issue any number of drawMesh calls. */
4797
4952
  bindMeshPass(camera, env) {
4953
+ /* The pass's own material is reopened, so the next draw opens one. See `materialChanges.ts`. */
4954
+ this.materials.dirty();
4798
4955
  /*
4799
4956
  * Captured here rather than taken as an argument to `endFrame`, because this is the
4800
4957
  * camera the world was drawn with and a caller should not have to hand it over twice.
@@ -5121,6 +5278,8 @@ export class WebGL2Renderer {
5121
5278
  * are two numbers now.
5122
5279
  */
5123
5280
  gl.uniform1f(u['uEnvironmentEdge'] ?? null, array?.edge ?? 1);
5281
+ /* Never on this backend: what fills a visibility map is a compute dispatch. See `probeGrid.ts`. */
5282
+ gl.uniform1f(u['uProbeVisibilityEnabled'] ?? null, 0);
5124
5283
  gl.uniform1f(u['uEnvironmentIrradianceLevel'] ?? null, array?.irradianceLevel ?? 0);
5125
5284
  /*
5126
5285
  * Where the probes stand: four uniforms whatever the probe count, because this shader is
@@ -5249,7 +5408,15 @@ export class WebGL2Renderer {
5249
5408
  * rebuilding vertex data every frame. Reset to white after the call, so a caller that
5250
5409
  * passes one cannot leak it into the next draw.
5251
5410
  */
5252
- tint = null) {
5411
+ tint = null,
5412
+ /**
5413
+ * Where the mesh was last frame, which this backend takes and ignores.
5414
+ *
5415
+ * Accepted rather than absent so that one scene draws through both renderers unchanged — the
5416
+ * parity rule this repository is built on. Reconstruction is WebGPU's, having no compute stage
5417
+ * here, so there is no motion target for this to be written into.
5418
+ */
5419
+ _previousModel = null) {
5253
5420
  if (this.contextLost)
5254
5421
  return;
5255
5422
  /* Geometry that has not all arrived is not drawn. See `Mesh.complete`. */
@@ -5276,6 +5443,7 @@ export class WebGL2Renderer {
5276
5443
  if (this.quality.cullDraws && this.occluded(mesh.bounds, model))
5277
5444
  return;
5278
5445
  this.drawBudget.ask();
5446
+ this.takeMaterial();
5279
5447
  const { gl } = this;
5280
5448
  /*
5281
5449
  * A rigged mesh takes the skinned program, an unrigged one the plain program.
@@ -5439,7 +5607,6 @@ export class WebGL2Renderer {
5439
5607
  return;
5440
5608
  if (opacity <= 0)
5441
5609
  return;
5442
- this.drawBudget.ask();
5443
5610
  /*
5444
5611
  * **Recorded rather than drawn**, when the effect is on and this is not already the replay.
5445
5612
  * The two buffers are two blend states over the same geometry, so the set has to survive until
@@ -5449,6 +5616,9 @@ export class WebGL2Renderer {
5449
5616
  this.translucentQueue.record(mesh, model, opacity, options);
5450
5617
  return;
5451
5618
  }
5619
+ /* Counted where it is submitted, as the other backend counts it: once per replay pass under
5620
+ order-independent transparency, and not once more when it was recorded. */
5621
+ this.drawBudget.ask();
5452
5622
  const { gl } = this;
5453
5623
  const u = this.flatUniforms;
5454
5624
  this.useFlatProgram();
@@ -5509,6 +5679,12 @@ export class WebGL2Renderer {
5509
5679
  * or a multiplicative blend for the whole set and turned depth writes off for all of it. A
5510
5680
  * replayed draw that reset either would break the pass around it.
5511
5681
  */
5682
+ /* Taken for itself when any option differs from the pass, and put back below: the rule both
5683
+ backends count material changes by. See `materialChanges.ts`. */
5684
+ const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting });
5685
+ if (own)
5686
+ this.materials.dirty();
5687
+ this.takeMaterial();
5512
5688
  const ownsState = !this.oitReplaying;
5513
5689
  if (ownsState) {
5514
5690
  gl.enable(gl.BLEND);
@@ -5550,6 +5726,8 @@ export class WebGL2Renderer {
5550
5726
  gl.uniform1i(u['uFogEnabled'] ?? null, 1);
5551
5727
  if (!toneMapped)
5552
5728
  gl.uniform1i(u['uOutputTransform'] ?? null, this.gradeCode());
5729
+ if (own)
5730
+ this.materials.dirty();
5553
5731
  }
5554
5732
  /**
5555
5733
  * Capture the room into a cubemap, once, so reflective surfaces can mirror it.
@@ -5647,6 +5825,23 @@ export class WebGL2Renderer {
5647
5825
  this.useFlatProgram();
5648
5826
  this.gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, 0);
5649
5827
  this.gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, 1);
5828
+ this.materials.dirty();
5829
+ /*
5830
+ * **Clockwise for the duration, because a face is rendered mirrored.** `cubeFaceProjection`
5831
+ * negates clip y so the face is stored the way a cubemap reads it, and negating one axis
5832
+ * reverses every triangle's winding: without this the room is culled inside out and the cube
5833
+ * holds its own back faces.
5834
+ *
5835
+ * **A perturbation survives this line and it is kept anyway**, which is worth the sentence.
5836
+ * Deleting it moves `ibl-check.mjs`'s figures — 12.5 to 13.1 of 255 on the movement check and
5837
+ * 182.0 to 184.9 on the mirror rung — so it is not dead; but no check *fails*, because every
5838
+ * room this repository bakes into a probe is made of closed boxes whose two sides carry the
5839
+ * same colour, and looking at the far one's outside instead of the near one's inside draws
5840
+ * almost the same picture. What it actually decides is a scene with **one-sided** geometry: a
5841
+ * room built from single quads facing inward disappears from its own probe without it, and
5842
+ * there is no such scene here to fail on.
5843
+ */
5844
+ this.gl.frontFace(this.gl.CW);
5650
5845
  let baked = false;
5651
5846
  try {
5652
5847
  baked = probe.bake(this.gl, this.probeOrigin, clearColor, drawFace);
@@ -5660,9 +5855,11 @@ export class WebGL2Renderer {
5660
5855
  }
5661
5856
  }
5662
5857
  finally {
5858
+ this.gl.frontFace(this.gl.CCW);
5663
5859
  this.useFlatProgram();
5664
5860
  this.gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, this.gradeCode());
5665
5861
  this.gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, this.gradeExposure());
5862
+ this.materials.dirty();
5666
5863
  /*
5667
5864
  * Cleared even if a caller's own draw threw, because leaving this set would keep every
5668
5865
  * later frame reading the placeholder and quietly reflecting nothing.
@@ -5804,6 +6001,7 @@ export class WebGL2Renderer {
5804
6001
  where the beam has no medium to be seen in and skipping it is the whole saving. */
5805
6002
  if (shown <= 0)
5806
6003
  return;
6004
+ this.lightVolumeBudget.ask();
5807
6005
  const { gl } = this;
5808
6006
  const u = this.lightVolumeUniforms;
5809
6007
  gl.useProgram(this.lightVolumeProgram);
@@ -27,8 +27,27 @@ export interface VertexAttribute {
27
27
  export declare const VERTEX_LAYOUT: readonly VertexAttribute[];
28
28
  /** Geometry on the device, with the buffers bound in layout order. */
29
29
  export interface GpuMesh {
30
- /** One buffer per attribute, indexed by position in `VERTEX_LAYOUT`. */
30
+ /**
31
+ * The buffers a draw binds, in the order `vertexBufferLayouts` describes them.
32
+ *
33
+ * **Two, and the first is interleaved** — every attribute this mesh actually supplied, woven
34
+ * into one stride — while the second holds one value per *absent* optional attribute at a stride
35
+ * of zero. It is emphatically not one buffer per attribute, which this comment said until
36
+ * 2026-09-17 and which cost the motion pass an afternoon: a pipeline built to that description
37
+ * reads a position out of every twelve bytes of an interleaved vertex, draws geometry that is
38
+ * not the mesh, and fails no validation at all.
39
+ */
31
40
  readonly vertexBuffers: readonly GPUBuffer[];
41
+ /**
42
+ * Bytes a vertex takes in the first of those buffers.
43
+ *
44
+ * Kept because it is a function of which *optional* attributes this mesh supplied, so it differs
45
+ * between two meshes drawn by the same pipeline — and a pass that reads only the position still
46
+ * has to step by the whole of it. `submitMesh` never needs it, the generated pipelines being
47
+ * keyed by the same `present` map that decides it; anything drawing a mesh through a shader of
48
+ * its own does.
49
+ */
50
+ readonly vertexStride: number;
32
51
  readonly indexBuffer: GPUBuffer;
33
52
  readonly indexCount: number;
34
53
  /**