@driftengine/core 3.62.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (428) hide show
  1. package/CHANGELOG.json +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 +70 -4
  9. package/dist/index.js +123 -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 +47 -14
  42. package/dist/render/backend/webgpu/surfaceTexturePass.js +128 -80
  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 +261 -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 +158 -88
  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.ts';
2
+ import { MaterialChanges, ownsMaterial } from '../materialChanges.ts';
2
3
  import { mat4 } from 'gl-matrix';
3
4
  import {
4
5
  DEPTH_CLEAR,
@@ -40,6 +41,8 @@ import { DecalQueue } from '../../decalQueue.ts';
40
41
  import type { DecalProjector } from '../../decalProjector.ts';
41
42
  import { OitPass } from '../../oitPass.ts';
42
43
  import { OIT_MULTISAMPLE_REFUSAL } from '../../orderIndependent.ts';
44
+ import { INDIRECT_LIGHT_WEBGL2_REFUSAL } from '../../gi/probeTrace.ts';
45
+ import type { FieldSource } from '../../gi/globalField.ts';
43
46
  import { TranslucentQueue } from '../../translucentQueue.ts';
44
47
  import { createFrustum, frustumFromViewProjection } from '../../../math/frustum.ts';
45
48
  import type { Frustum } from '../../../math/frustum.ts';
@@ -110,7 +113,7 @@ import { SkinPaletteTexture } from './skinPaletteTexture.ts';
110
113
  /* The codes the shader reads, stated once in `vertexDefaults.ts` for both backends. */
111
114
  import { LIGHT_VOLUME_VERT, lightVolumeFrag } from '../../shaders/lightVolume.ts';
112
115
  import { PANEL_FRAG, PANEL_VERT } from '../../shaders/panel.ts';
113
- import { ReflectionProbe } from '../../reflectionProbe.ts';
116
+ import { ReflectionProbe, cubeFaceProjection } from '../../reflectionProbe.ts';
114
117
  import type { ProbeBakeOptions } from '../../reflectionProbe.ts';
115
118
  import { EnvProbeArray } from '../../envProbeArray.ts';
116
119
  import { ProbeGrid, SINGLE_PROBE, UNIT_STEP, WORLD_ORIGIN, sameGrid } from '../../probeGrid.ts';
@@ -1369,6 +1372,13 @@ export class WebGL2Renderer implements RendererApi {
1369
1372
  reversedDepth = false;
1370
1373
  /** `GL_DEPTH_REMAP * camera.viewProjection`, rebuilt once a frame. */
1371
1374
  private readonly sceneViewProj = new Float32Array(16);
1375
+ /**
1376
+ * The same matrix with clip y negated, for the six faces of a probe.
1377
+ *
1378
+ * Its own buffer rather than `sceneViewProj`, because `cubeFaceProjection` reads what
1379
+ * `sceneMatrix` just wrote and the two would be the same array.
1380
+ */
1381
+ private readonly cubeFaceViewProj = new Float32Array(16);
1372
1382
  /**
1373
1383
  * One buffer per shadow matrix that outlives a call, and that is not fussiness.
1374
1384
  *
@@ -1401,7 +1411,12 @@ export class WebGL2Renderer implements RendererApi {
1401
1411
  * the camera's matrix unchanged and multiplies nothing.
1402
1412
  */
1403
1413
  private viewProjFor(camera: { readonly viewProjection: ReadonlyMat4 }): ReadonlyMat4 {
1404
- const scene = this.sceneMatrix(camera.viewProjection);
1414
+ const scene = this.probePassActive
1415
+ ? (cubeFaceProjection(
1416
+ this.cubeFaceViewProj,
1417
+ this.sceneMatrix(camera.viewProjection) as unknown as ArrayLike<number>,
1418
+ ) as unknown as ReadonlyMat4)
1419
+ : this.sceneMatrix(camera.viewProjection);
1405
1420
  /*
1406
1421
  * **The jitter goes on here and nowhere else.** This is the one funnel every geometry upload
1407
1422
  * passes through, so one line covers the mesh passes, the sky, the water and the effects
@@ -1504,6 +1519,7 @@ export class WebGL2Renderer implements RendererApi {
1504
1519
  */
1505
1520
  private readonly casterSink: ShadowCasterSink = {
1506
1521
  mesh: (mesh, model) => {
1522
+ this.shadowDrawBudget.ask();
1507
1523
  const { gl } = this;
1508
1524
  gl.uniformMatrix4fv(this.depthUniforms['uModel'] ?? null, false, model);
1509
1525
  /*
@@ -1524,6 +1540,7 @@ export class WebGL2Renderer implements RendererApi {
1524
1540
  const gpuBatch = batch as InstancedBatch;
1525
1541
  const count = Math.min(data.count, gpuBatch.capacity);
1526
1542
  if (count === 0) return;
1543
+ this.shadowDrawBudget.ask();
1527
1544
  const u = this.depthInstancedUniforms;
1528
1545
  gl.useProgram(this.depthInstancedProgram);
1529
1546
  gl.uniformMatrix4fv(u['uLightViewProj'] ?? null, false, this.activeDepthViewProj);
@@ -1533,6 +1550,7 @@ export class WebGL2Renderer implements RendererApi {
1533
1550
  gl.useProgram(this.depthProgram);
1534
1551
  },
1535
1552
  skinnedMesh: (mesh, model, palette) => {
1553
+ this.shadowDrawBudget.ask();
1536
1554
  const { gl } = this;
1537
1555
  const u = this.depthSkinnedUniforms;
1538
1556
  gl.useProgram(this.depthSkinnedProgram);
@@ -1555,6 +1573,7 @@ export class WebGL2Renderer implements RendererApi {
1555
1573
  },
1556
1574
  scatter: (scatter, data, windX, windZ, windGust, timeSeconds, trample = null) => {
1557
1575
  if (data.count === 0) return;
1576
+ this.scatterDepthBudget.ask();
1558
1577
  const { gl } = this;
1559
1578
  const u = this.scatterDepthUniforms;
1560
1579
  gl.useProgram(this.scatterDepthProgram);
@@ -1680,6 +1699,44 @@ export class WebGL2Renderer implements RendererApi {
1680
1699
  this.occlusion?.addOccluder(min as Float32Array, max as Float32Array, model);
1681
1700
  }
1682
1701
 
1702
+ /**
1703
+ * Declare a baked distance field that indirect light may be traced against.
1704
+ *
1705
+ * **Recorded by nothing on this backend, and that is the refusal rather than an oversight.**
1706
+ * Composing the world's field and marching probes through it is compute, and WebGL2 has no
1707
+ * compute stage — `INDIRECT_LIGHT_WEBGL2_REFUSAL` says so once a frame-loop when
1708
+ * `quality.indirectLight` is on. The method exists here because `RendererApi` is this class's
1709
+ * shape, and a consumer that declares its fields unconditionally must not have to ask which
1710
+ * backend it got: this is a no-op for the same reason `addOccluder` is one when the profile
1711
+ * asked for no occlusion buffer.
1712
+ *
1713
+ * The field is in the model matrix's own space and the matrix must carry uniform scale only.
1714
+ * `composeGlobalField` gives the reason: a distance is not preserved by a non-uniform scale.
1715
+ */
1716
+ addDistanceField(_field: FieldSource, _model: ReadonlyMat4, _albedo?: ArrayLike<number>): void {
1717
+ /* Deliberately nothing. See the comment above. */
1718
+ }
1719
+
1720
+ /** Forget the fields declared this frame. A no-op here, as `addDistanceField` is. */
1721
+ clearDistanceFields(): void {
1722
+ /* Deliberately nothing. See `addDistanceField`. */
1723
+ }
1724
+
1725
+ /** Never measured here, because nothing is composed. See `addDistanceField`. */
1726
+ get distanceFieldMs(): number | null {
1727
+ return null;
1728
+ }
1729
+
1730
+ /** Never traced here either, so there is no refresh to time. See `addDistanceField`. */
1731
+ get indirectBakeMs(): number | null {
1732
+ return null;
1733
+ }
1734
+
1735
+ /** Nothing to read, for the same reason. A consumer may call it unconditionally. */
1736
+ readDistanceFieldTimings(): void {
1737
+ /* Deliberately nothing. See `addDistanceField`. */
1738
+ }
1739
+
1683
1740
  /**
1684
1741
  * Whether a mesh is entirely behind the occluders declared this frame.
1685
1742
  *
@@ -1719,7 +1776,14 @@ export class WebGL2Renderer implements RendererApi {
1719
1776
  registerPass(definition: PassDefinition): PassHandle {
1720
1777
  const handle = registerIn(this.passes, definition);
1721
1778
  /* Identity: this backend's clip space is the one the projections are built for. */
1722
- this.passDevice ??= { backend: 'webgl2', gl: this.gl, clipCorrection: IDENTITY_CLIP };
1779
+ /* Both are identity here: this backend runs the GLSL natively, so there is nothing to
1780
+ correct and nothing a generator has flipped. */
1781
+ this.passDevice ??= {
1782
+ backend: 'webgl2',
1783
+ gl: this.gl,
1784
+ clipCorrection: IDENTITY_CLIP,
1785
+ depthCorrection: IDENTITY_CLIP,
1786
+ };
1723
1787
  if (definition.prepare !== undefined) this.preparingPasses++;
1724
1788
  definition.init?.(this.passDevice);
1725
1789
  return handle;
@@ -2900,6 +2964,7 @@ export class WebGL2Renderer implements RendererApi {
2900
2964
 
2901
2965
  setMaterial(material: SurfaceMaterial | null): void {
2902
2966
  if (this.contextLost) return;
2967
+ this.materials.dirty();
2903
2968
  this.currentSurfaceTexture = material?.albedo ?? null;
2904
2969
  /*
2905
2970
  * Written to every flat program, because material state persists across draws and a skinned
@@ -3072,6 +3137,7 @@ export class WebGL2Renderer implements RendererApi {
3072
3137
  */
3073
3138
  setSurfaceReflectivity(amount: number): void {
3074
3139
  if (this.contextLost) return;
3140
+ this.materials.dirty();
3075
3141
  this.useFlatProgram();
3076
3142
  this.gl.uniform1f(this.flatUniforms['uReflectivity'] ?? null, Math.min(1, Math.max(0, amount)));
3077
3143
  }
@@ -3090,6 +3156,7 @@ export class WebGL2Renderer implements RendererApi {
3090
3156
  */
3091
3157
  setEnvironmentGain(gain: number): void {
3092
3158
  if (this.contextLost) return;
3159
+ this.materials.dirty();
3093
3160
  this.useFlatProgram();
3094
3161
  this.gl.uniform1f(this.flatUniforms['uEnvironmentGain'] ?? null, Math.max(0, gain));
3095
3162
  }
@@ -3119,6 +3186,7 @@ export class WebGL2Renderer implements RendererApi {
3119
3186
 
3120
3187
  setSurfaceGrain(amount: number): void {
3121
3188
  if (this.contextLost) return;
3189
+ this.materials.dirty();
3122
3190
  this.useFlatProgram();
3123
3191
  this.gl.uniform1f(this.flatUniforms['uGrain'] ?? null, Math.min(1, Math.max(0, amount)));
3124
3192
  }
@@ -3148,6 +3216,7 @@ export class WebGL2Renderer implements RendererApi {
3148
3216
  */
3149
3217
  setSurfaceRelief(amount: number, cyclesPerMetre = 60): void {
3150
3218
  if (this.contextLost) return;
3219
+ this.materials.dirty();
3151
3220
  this.useFlatProgram();
3152
3221
  const u = this.flatUniforms;
3153
3222
  this.gl.uniform1f(u['uRelief'] ?? null, Math.min(1, Math.max(0, amount)));
@@ -3181,6 +3250,7 @@ export class WebGL2Renderer implements RendererApi {
3181
3250
  */
3182
3251
  setSurfaceTextureRelief(scale: number): void {
3183
3252
  if (this.contextLost) return;
3253
+ this.materials.dirty();
3184
3254
  this.useFlatProgram();
3185
3255
  this.gl.uniform1f(
3186
3256
  this.flatUniforms['uTextureRelief'] ?? null,
@@ -3211,6 +3281,7 @@ export class WebGL2Renderer implements RendererApi {
3211
3281
  */
3212
3282
  setEmissiveGain(gain: number): void {
3213
3283
  if (this.contextLost) return;
3284
+ this.materials.dirty();
3214
3285
  this.useFlatProgram();
3215
3286
  this.gl.uniform1f(this.flatUniforms['uEmissiveGain'] ?? null, gain);
3216
3287
  }
@@ -3338,6 +3409,10 @@ export class WebGL2Renderer implements RendererApi {
3338
3409
  const lit = options.lit ?? true;
3339
3410
  const fog = options.fog ?? true;
3340
3411
  const toneMapped = options.toneMapped ?? true;
3412
+ /* An instanced draw does not refract. See `materialChanges.ts`. */
3413
+ const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting: false });
3414
+ if (own) this.materials.dirty();
3415
+ this.takeMaterial();
3341
3416
  const depthWrite = options.depthWrite ?? true;
3342
3417
  const layer = Math.min(Math.max(Math.round(options.depthLayer ?? 0), 0), MAX_DEPTH_LAYER);
3343
3418
 
@@ -3409,6 +3484,7 @@ export class WebGL2Renderer implements RendererApi {
3409
3484
  if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 1);
3410
3485
  if (!fog) gl.uniform1i(u['uFogEnabled'] ?? null, 1);
3411
3486
  if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, this.gradeCode());
3487
+ if (own) this.materials.dirty();
3412
3488
  this.useFlatProgram();
3413
3489
  }
3414
3490
 
@@ -3517,7 +3593,9 @@ export class WebGL2Renderer implements RendererApi {
3517
3593
  // raining dust into the sea.
3518
3594
  const surface = env.underwater?.surfaceY;
3519
3595
  const submerged = surface !== undefined && (camera.position[1] ?? 0) < surface;
3520
- streaks.draw(this.gl, this.frameViewFor(camera), wind, timeSeconds, tint, submerged);
3596
+ if (streaks.draw(this.gl, this.frameViewFor(camera), wind, timeSeconds, tint, submerged)) {
3597
+ this.windStreakBudget.ask();
3598
+ }
3521
3599
  }
3522
3600
 
3523
3601
  /**
@@ -3554,7 +3632,9 @@ export class WebGL2Renderer implements RendererApi {
3554
3632
  style: TextStyle,
3555
3633
  timeSec: number,
3556
3634
  ): void {
3557
- text.draw(viewportWidth, viewportHeight, originX, originY, style, timeSec);
3635
+ if (text.draw(viewportWidth, viewportHeight, originX, originY, style, timeSec)) {
3636
+ this.textBudget.ask();
3637
+ }
3558
3638
  }
3559
3639
 
3560
3640
  /** Width of the string this handle currently holds, in pixels at a given cell size. */
@@ -3649,6 +3729,7 @@ export class WebGL2Renderer implements RendererApi {
3649
3729
  this.gradeExposure(),
3650
3730
  )
3651
3731
  ) {
3732
+ this.sdfTextBudget.ask();
3652
3733
  this.restoreSurfaceTextureUnit();
3653
3734
  }
3654
3735
  }
@@ -3671,6 +3752,7 @@ export class WebGL2Renderer implements RendererApi {
3671
3752
  windX = 0,
3672
3753
  windZ = 0,
3673
3754
  ): void {
3755
+ this.flockBudget.ask();
3674
3756
  flock.draw(this.gl, this.frameViewFor(camera), timeSeconds, params, tint, windX, windZ);
3675
3757
  }
3676
3758
 
@@ -3794,8 +3876,10 @@ export class WebGL2Renderer implements RendererApi {
3794
3876
  if (data.count === 0) return;
3795
3877
  const { gl } = this;
3796
3878
  const u = batch.uniforms;
3797
- gl.useProgram(batch.program);
3798
3879
  const count = batch.upload(gl, data);
3880
+ if (count === 0) return;
3881
+ this.boltBudget.ask();
3882
+ gl.useProgram(batch.program);
3799
3883
  gl.uniformMatrix4fv(u['uViewProj'] ?? null, false, this.viewProjFor(camera));
3800
3884
  gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
3801
3885
  gl.uniform1f(u['uTime'] ?? null, timeSeconds);
@@ -3866,8 +3950,10 @@ export class WebGL2Renderer implements RendererApi {
3866
3950
  if (data.count === 0) return;
3867
3951
  const { gl } = this;
3868
3952
  const u = lines.uniforms;
3869
- gl.useProgram(lines.program);
3870
3953
  const count = lines.upload(gl, data);
3954
+ if (count === 0) return;
3955
+ this.lineBudget.ask();
3956
+ gl.useProgram(lines.program);
3871
3957
  gl.uniformMatrix4fv(u['uViewProj'] ?? null, false, this.viewProjFor(camera));
3872
3958
  gl.uniformMatrix4fv(u['uModel'] ?? null, false, model);
3873
3959
  gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
@@ -4124,6 +4210,7 @@ export class WebGL2Renderer implements RendererApi {
4124
4210
  windZ = 0,
4125
4211
  ): void {
4126
4212
  if (!this.quality.water) return;
4213
+ this.waterBudget.ask();
4127
4214
  water.draw(
4128
4215
  this.gl,
4129
4216
  this.frameViewFor(camera),
@@ -4156,7 +4243,7 @@ export class WebGL2Renderer implements RendererApi {
4156
4243
  strength = 1,
4157
4244
  ): void {
4158
4245
  if (caustics === null || !this.quality.water) return;
4159
- caustics.draw(
4246
+ const drew = caustics.draw(
4160
4247
  this.gl,
4161
4248
  this.frameViewFor(camera),
4162
4249
  timeSeconds,
@@ -4169,6 +4256,7 @@ export class WebGL2Renderer implements RendererApi {
4169
4256
  windZ,
4170
4257
  strength,
4171
4258
  );
4259
+ if (drew) this.causticsBudget.ask();
4172
4260
  }
4173
4261
 
4174
4262
  /**
@@ -4234,6 +4322,23 @@ export class WebGL2Renderer implements RendererApi {
4234
4322
  return this.canvas.width / Math.max(this.canvas.height, 1);
4235
4323
  }
4236
4324
 
4325
+ /**
4326
+ * The size the world is drawn at, which on this backend is always the drawing buffer.
4327
+ *
4328
+ * **Here so that a contributed pass has one question to ask on both backends.** WebGPU can draw
4329
+ * the world smaller than the canvas and let its composite enlarge it — `quality.reconstruction`
4330
+ * — and a pass filling a target of its own has to follow that size or draw a picture the frame
4331
+ * pass clips. This backend has no compute stage and no reconstruction, so the answer never moves;
4332
+ * a pass that reads it is correct on both, and one that reads `canvas.width` is correct on one.
4333
+ */
4334
+ get sceneWidth(): number {
4335
+ return Math.max(1, this.canvas.width);
4336
+ }
4337
+
4338
+ get sceneHeight(): number {
4339
+ return Math.max(1, this.canvas.height);
4340
+ }
4341
+
4237
4342
  /**
4238
4343
  * Point rendering back at the frame's own target, whole.
4239
4344
  *
@@ -5212,6 +5317,9 @@ export class WebGL2Renderer implements RendererApi {
5212
5317
  */
5213
5318
  fillPanel(rect: InsetRect, color: Vec3, alpha: number): void {
5214
5319
  if (alpha <= 0 || rect.width <= 0 || rect.height <= 0) return;
5320
+ /* Counted against no ceiling: the other backend refuses past its own, and a consumer here
5321
+ should be able to see that coming. See `budget.ts`. */
5322
+ this.panelBudget.ask();
5215
5323
  const { gl } = this;
5216
5324
 
5217
5325
  gl.useProgram(this.panelProgram);
@@ -5508,6 +5616,25 @@ export class WebGL2Renderer implements RendererApi {
5508
5616
  */
5509
5617
  private readonly budget = new FrameBudget();
5510
5618
  private readonly drawBudget = this.budget.line('draws', null);
5619
+ /**
5620
+ * Every line the other backend declares, in its order and with none of its ceilings.
5621
+ *
5622
+ * **Counted after the same guards**, so one scene reports one number on both: the verbs each
5623
+ * ask once they are past the checks that make them draw nothing on either backend — a panel
5624
+ * with no alpha, a string with no glyphs, a beam with no strength, a calm wind — and a material
5625
+ * change is counted by the rule both share (`materialChanges.ts`). `webgpu/renderer.test.ts`
5626
+ * runs one scene through both and compares every line.
5627
+ */
5628
+ private readonly materialBudget = this.budget.line('materials', null);
5629
+ /** Whether the next mesh draw shares the open material or opens one, by the rule both count. */
5630
+ private readonly materials = new MaterialChanges();
5631
+
5632
+ /** A mesh draw: counted as a material change when something has changed the material since. */
5633
+ private takeMaterial(): void {
5634
+ if (this.materials.open) return;
5635
+ this.materialBudget.ask();
5636
+ this.materials.slot = 0;
5637
+ }
5511
5638
  /**
5512
5639
  * Declared here and never asked, because this backend builds none.
5513
5640
  *
@@ -5519,6 +5646,19 @@ export class WebGL2Renderer implements RendererApi {
5519
5646
  * being compared against should also be zero once the other backend's cache is warm.
5520
5647
  */
5521
5648
  private readonly bindGroupBudget = this.budget.line('bind groups', null);
5649
+ private readonly shadowDrawBudget = this.budget.line('shadow draws', null);
5650
+ private readonly scatterDepthBudget = this.budget.line('scatter shadow draws', null);
5651
+ private readonly waterBudget = this.budget.line('water bodies', null);
5652
+ private readonly lightVolumeBudget = this.budget.line('light volumes', null);
5653
+ private readonly windStreakBudget = this.budget.line('wind streak fields', null);
5654
+ private readonly flockBudget = this.budget.line('flocks', null);
5655
+ private readonly boltBudget = this.budget.line('bolt batches', null);
5656
+ private readonly causticsBudget = this.budget.line('caustics', null);
5657
+ private readonly textBudget = this.budget.line('text draws', null);
5658
+ private readonly sdfTextBudget = this.budget.line('sdf text draws', null);
5659
+ private readonly lineBudget = this.budget.line('line draws', null);
5660
+ /** The other backend's panel ceiling, reported here as a count with none. */
5661
+ private readonly panelBudget = this.budget.line('panels', null);
5522
5662
 
5523
5663
  /** What the frame just drawn asked for. See `budget.ts`, and the note on `budget` above. */
5524
5664
  get frameBudget(): FrameBudget {
@@ -5617,6 +5757,9 @@ export class WebGL2Renderer implements RendererApi {
5617
5757
  * from one `RenderQuality` — see `OIT_MULTISAMPLE_REFUSAL` for why it is a constant and not two
5618
5758
  * literals kept in step by hand.
5619
5759
  */
5760
+ /** Said once rather than every frame, as the translucent set's own refusal is. */
5761
+ private indirectLightRefused = false;
5762
+
5620
5763
  private refuseOitMultisampled(): void {
5621
5764
  if (this.oitMultisampleRefused) return;
5622
5765
  this.oitMultisampleRefused = true;
@@ -5626,6 +5769,15 @@ export class WebGL2Renderer implements RendererApi {
5626
5769
  beginFrame(clearColor: Vec3): void {
5627
5770
  if (this.contextLost) return;
5628
5771
  this.budget.reset();
5772
+ this.materials.dirty();
5773
+ /*
5774
+ * Said once, for the reason `refuseOitMultisampled` gives: a quality setting that is enabled
5775
+ * and does nothing is the fault the capability clamp exists to prevent.
5776
+ */
5777
+ if (this.quality.indirectLight && !this.indirectLightRefused) {
5778
+ this.indirectLightRefused = true;
5779
+ console.warn(INDIRECT_LIGHT_WEBGL2_REFUSAL);
5780
+ }
5629
5781
 
5630
5782
  const { gl } = this;
5631
5783
  this.reflectionReadyThisFrame = false;
@@ -5908,6 +6060,15 @@ export class WebGL2Renderer implements RendererApi {
5908
6060
  ) {
5909
6061
  const flat = this.flatUniforms;
5910
6062
  const options = this.oitReplayOptions;
6063
+ /*
6064
+ * **The copy a refracting pane reads is taken here, before the buffers are bound.** Taking
6065
+ * it puts the scene's framebuffer back as the one drawn into, so taken inside the replay —
6066
+ * at the first pane that refracts, which is where it was taken until 2026-09-19 — it sent
6067
+ * that pane into the scene instead of the accumulation, and every refracting pane came out
6068
+ * flat paint with the effect on. The opaque frame is finished here, which is what a pane
6069
+ * should show; the latch then serves every pane in the replay. Only when something refracts.
6070
+ */
6071
+ if (this.translucentQueue.refracts) this.sceneTarget?.snapshotColor();
5911
6072
  this.oit.accumulateOit(this.canvas.width, this.canvas.height, oitDepth, (weighted) => {
5912
6073
  this.oitReplaying = true;
5913
6074
  this.useFlatProgram();
@@ -6106,6 +6267,8 @@ export class WebGL2Renderer implements RendererApi {
6106
6267
 
6107
6268
  /** Bind the flat pass once per frame; then issue any number of drawMesh calls. */
6108
6269
  bindMeshPass(camera: Camera, env: Environment): void {
6270
+ /* The pass's own material is reopened, so the next draw opens one. See `materialChanges.ts`. */
6271
+ this.materials.dirty();
6109
6272
  /*
6110
6273
  * Captured here rather than taken as an argument to `endFrame`, because this is the
6111
6274
  * camera the world was drawn with and a caller should not have to hand it over twice.
@@ -6451,6 +6614,8 @@ export class WebGL2Renderer implements RendererApi {
6451
6614
  * are two numbers now.
6452
6615
  */
6453
6616
  gl.uniform1f(u['uEnvironmentEdge'] ?? null, array?.edge ?? 1);
6617
+ /* Never on this backend: what fills a visibility map is a compute dispatch. See `probeGrid.ts`. */
6618
+ gl.uniform1f(u['uProbeVisibilityEnabled'] ?? null, 0);
6454
6619
  gl.uniform1f(u['uEnvironmentIrradianceLevel'] ?? null, array?.irradianceLevel ?? 0);
6455
6620
  /*
6456
6621
  * Where the probes stand: four uniforms whatever the probe count, because this shader is
@@ -6589,6 +6754,14 @@ export class WebGL2Renderer implements RendererApi {
6589
6754
  * passes one cannot leak it into the next draw.
6590
6755
  */
6591
6756
  tint: Vec3 | null = null,
6757
+ /**
6758
+ * Where the mesh was last frame, which this backend takes and ignores.
6759
+ *
6760
+ * Accepted rather than absent so that one scene draws through both renderers unchanged — the
6761
+ * parity rule this repository is built on. Reconstruction is WebGPU's, having no compute stage
6762
+ * here, so there is no motion target for this to be written into.
6763
+ */
6764
+ _previousModel: ReadonlyMat4 | null = null,
6592
6765
  ): void {
6593
6766
  if (this.contextLost) return;
6594
6767
  /* Geometry that has not all arrived is not drawn. See `Mesh.complete`. */
@@ -6613,6 +6786,7 @@ export class WebGL2Renderer implements RendererApi {
6613
6786
  */
6614
6787
  if (this.quality.cullDraws && this.occluded(mesh.bounds, model)) return;
6615
6788
  this.drawBudget.ask();
6789
+ this.takeMaterial();
6616
6790
  const { gl } = this;
6617
6791
  /*
6618
6792
  * A rigged mesh takes the skinned program, an unrigged one the plain program.
@@ -6777,7 +6951,6 @@ export class WebGL2Renderer implements RendererApi {
6777
6951
  if (!mesh.complete) return;
6778
6952
 
6779
6953
  if (opacity <= 0) return;
6780
- this.drawBudget.ask();
6781
6954
 
6782
6955
  /*
6783
6956
  * **Recorded rather than drawn**, when the effect is on and this is not already the replay.
@@ -6788,6 +6961,9 @@ export class WebGL2Renderer implements RendererApi {
6788
6961
  this.translucentQueue.record(mesh, model, opacity, options);
6789
6962
  return;
6790
6963
  }
6964
+ /* Counted where it is submitted, as the other backend counts it: once per replay pass under
6965
+ order-independent transparency, and not once more when it was recorded. */
6966
+ this.drawBudget.ask();
6791
6967
 
6792
6968
  const { gl } = this;
6793
6969
  const u = this.flatUniforms;
@@ -6845,6 +7021,11 @@ export class WebGL2Renderer implements RendererApi {
6845
7021
  * or a multiplicative blend for the whole set and turned depth writes off for all of it. A
6846
7022
  * replayed draw that reset either would break the pass around it.
6847
7023
  */
7024
+ /* Taken for itself when any option differs from the pass, and put back below: the rule both
7025
+ backends count material changes by. See `materialChanges.ts`. */
7026
+ const own = ownsMaterial({ opacity, lit, fog, toneMapped, refracting });
7027
+ if (own) this.materials.dirty();
7028
+ this.takeMaterial();
6848
7029
  const ownsState = !this.oitReplaying;
6849
7030
  if (ownsState) {
6850
7031
  gl.enable(gl.BLEND);
@@ -6879,6 +7060,7 @@ export class WebGL2Renderer implements RendererApi {
6879
7060
  if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 1);
6880
7061
  if (!fog) gl.uniform1i(u['uFogEnabled'] ?? null, 1);
6881
7062
  if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, this.gradeCode());
7063
+ if (own) this.materials.dirty();
6882
7064
  }
6883
7065
 
6884
7066
  /**
@@ -6991,6 +7173,23 @@ export class WebGL2Renderer implements RendererApi {
6991
7173
  this.useFlatProgram();
6992
7174
  this.gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, 0);
6993
7175
  this.gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, 1);
7176
+ this.materials.dirty();
7177
+ /*
7178
+ * **Clockwise for the duration, because a face is rendered mirrored.** `cubeFaceProjection`
7179
+ * negates clip y so the face is stored the way a cubemap reads it, and negating one axis
7180
+ * reverses every triangle's winding: without this the room is culled inside out and the cube
7181
+ * holds its own back faces.
7182
+ *
7183
+ * **A perturbation survives this line and it is kept anyway**, which is worth the sentence.
7184
+ * Deleting it moves `ibl-check.mjs`'s figures — 12.5 to 13.1 of 255 on the movement check and
7185
+ * 182.0 to 184.9 on the mirror rung — so it is not dead; but no check *fails*, because every
7186
+ * room this repository bakes into a probe is made of closed boxes whose two sides carry the
7187
+ * same colour, and looking at the far one's outside instead of the near one's inside draws
7188
+ * almost the same picture. What it actually decides is a scene with **one-sided** geometry: a
7189
+ * room built from single quads facing inward disappears from its own probe without it, and
7190
+ * there is no such scene here to fail on.
7191
+ */
7192
+ this.gl.frontFace(this.gl.CW);
6994
7193
  let baked = false;
6995
7194
  try {
6996
7195
  baked = probe.bake(this.gl, this.probeOrigin, clearColor, drawFace);
@@ -7011,9 +7210,11 @@ export class WebGL2Renderer implements RendererApi {
7011
7210
  );
7012
7211
  }
7013
7212
  } finally {
7213
+ this.gl.frontFace(this.gl.CCW);
7014
7214
  this.useFlatProgram();
7015
7215
  this.gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, this.gradeCode());
7016
7216
  this.gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, this.gradeExposure());
7217
+ this.materials.dirty();
7017
7218
  /*
7018
7219
  * Cleared even if a caller's own draw threw, because leaving this set would keep every
7019
7220
  * later frame reading the placeholder and quietly reflecting nothing.
@@ -7180,6 +7381,7 @@ export class WebGL2Renderer implements RendererApi {
7180
7381
  /* At zero it draws nothing rather than adding black — which now also covers a clear night,
7181
7382
  where the beam has no medium to be seen in and skipping it is the whole saving. */
7182
7383
  if (shown <= 0) return;
7384
+ this.lightVolumeBudget.ask();
7183
7385
  const { gl } = this;
7184
7386
  const u = this.lightVolumeUniforms;
7185
7387
  gl.useProgram(this.lightVolumeProgram);