@driftengine/core 4.4.2 → 4.6.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 (339) hide show
  1. package/CHANGELOG.json +97 -0
  2. package/README.md +1 -1
  3. package/dist/geometry/boxCsg.d.ts +28 -0
  4. package/dist/geometry/boxCsg.js +139 -0
  5. package/dist/geometry/csg.d.ts +36 -0
  6. package/dist/geometry/csg.js +329 -0
  7. package/dist/geometry/meshBuilder.js +13 -0
  8. package/dist/geometry/meshConcat.js +1 -0
  9. package/dist/geometry/pixelFont.js +2 -0
  10. package/dist/geometry/solid.d.ts +61 -0
  11. package/dist/geometry/solid.js +152 -0
  12. package/dist/geometry/solidFlat.d.ts +35 -0
  13. package/dist/geometry/solidFlat.js +428 -0
  14. package/dist/geometry/solidHarness.d.ts +19 -0
  15. package/dist/geometry/solidHarness.js +66 -0
  16. package/dist/geometry/solidNormals.d.ts +17 -0
  17. package/dist/geometry/solidNormals.js +86 -0
  18. package/dist/geometry/solidRound.d.ts +41 -0
  19. package/dist/geometry/solidRound.js +323 -0
  20. package/dist/geometry/solidWriter.d.ts +16 -0
  21. package/dist/geometry/solidWriter.js +42 -0
  22. package/dist/index.d.ts +28 -3
  23. package/dist/index.js +20 -1
  24. package/dist/render/backend/api.d.ts +34 -14
  25. package/dist/render/backend/drawFog.d.ts +26 -0
  26. package/dist/render/backend/drawFog.js +30 -0
  27. package/dist/render/backend/materialChanges.d.ts +2 -1
  28. package/dist/render/backend/materialChanges.js +6 -1
  29. package/dist/render/backend/webgl2/glassTintPrograms.d.ts +13 -0
  30. package/dist/render/backend/webgl2/glassTintPrograms.js +38 -0
  31. package/dist/render/backend/webgl2/instanced.d.ts +24 -5
  32. package/dist/render/backend/webgl2/instanced.js +72 -15
  33. package/dist/render/backend/webgl2/renderer.d.ts +201 -16
  34. package/dist/render/backend/webgl2/renderer.js +596 -224
  35. package/dist/render/backend/webgpu/buffers.d.ts +29 -1
  36. package/dist/render/backend/webgpu/buffers.js +61 -4
  37. package/dist/render/backend/webgpu/depthPass.d.ts +1 -1
  38. package/dist/render/backend/webgpu/depthPass.js +7 -2
  39. package/dist/render/backend/webgpu/drawCommand.d.ts +5 -0
  40. package/dist/render/backend/webgpu/drawCommand.js +1 -0
  41. package/dist/render/backend/webgpu/flatPass.d.ts +6 -1
  42. package/dist/render/backend/webgpu/flatPass.js +57 -9
  43. package/dist/render/backend/webgpu/glassTintPass.d.ts +28 -0
  44. package/dist/render/backend/webgpu/glassTintPass.js +206 -0
  45. package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +60 -1
  46. package/dist/render/backend/webgpu/gpuDrivenPass.js +305 -5
  47. package/dist/render/backend/webgpu/instanceCullPass.d.ts +34 -0
  48. package/dist/render/backend/webgpu/instanceCullPass.js +144 -0
  49. package/dist/render/backend/webgpu/instanced.d.ts +23 -2
  50. package/dist/render/backend/webgpu/instanced.js +41 -4
  51. package/dist/render/backend/webgpu/latePass.d.ts +30 -0
  52. package/dist/render/backend/webgpu/latePass.js +140 -0
  53. package/dist/render/backend/webgpu/lightVolumePass.js +5 -1
  54. package/dist/render/backend/webgpu/motionPass.d.ts +95 -0
  55. package/dist/render/backend/webgpu/motionPass.js +491 -0
  56. package/dist/render/backend/webgpu/pipelineCache.d.ts +10 -1
  57. package/dist/render/backend/webgpu/pipelineCache.js +11 -1
  58. package/dist/render/backend/webgpu/pointGlassTintPass.d.ts +32 -0
  59. package/dist/render/backend/webgpu/pointGlassTintPass.js +193 -0
  60. package/dist/render/backend/webgpu/pointShadowPass.d.ts +35 -6
  61. package/dist/render/backend/webgpu/pointShadowPass.js +105 -20
  62. package/dist/render/backend/webgpu/postPass.d.ts +3 -13
  63. package/dist/render/backend/webgpu/renderer.d.ts +271 -64
  64. package/dist/render/backend/webgpu/renderer.js +1395 -580
  65. package/dist/render/backend/webgpu/scatterPass.js +2 -1
  66. package/dist/render/backend/webgpu/sdfTextPass.js +6 -1
  67. package/dist/render/backend/webgpu/shaders/instanceCull.wgsl.d.ts +18 -0
  68. package/dist/render/backend/webgpu/shaders/instanceCull.wgsl.js +59 -0
  69. package/dist/render/backend/webgpu/skinPaletteRing.d.ts +4 -0
  70. package/dist/render/backend/webgpu/skinPaletteRing.js +4 -0
  71. package/dist/render/backend/webgpu/snapshotMips.d.ts +29 -0
  72. package/dist/render/backend/webgpu/snapshotMips.js +52 -0
  73. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +22 -3
  74. package/dist/render/backend/webgpu/surfaceTexturePass.js +78 -39
  75. package/dist/render/driftLight/bake.d.ts +7 -0
  76. package/dist/render/driftLight/bake.js +61 -56
  77. package/dist/render/driftLight/denseField.d.ts +46 -0
  78. package/dist/render/driftLight/denseField.js +109 -0
  79. package/dist/render/driftLight/lightField.d.ts +10 -5
  80. package/dist/render/driftLight/lightField.js +25 -19
  81. package/dist/render/driftLight/presence.d.ts +50 -0
  82. package/dist/render/driftLight/presence.js +43 -0
  83. package/dist/render/driftLight/uniforms.d.ts +3 -3
  84. package/dist/render/driftLight/uniforms.js +5 -6
  85. package/dist/render/driftLight/worldLightField.d.ts +41 -0
  86. package/dist/render/driftLight/worldLightField.js +66 -0
  87. package/dist/render/fixtureAtlas.d.ts +20 -0
  88. package/dist/render/fixtureAtlas.js +49 -0
  89. package/dist/render/glass.d.ts +45 -0
  90. package/dist/render/glass.js +39 -0
  91. package/dist/render/glassCasters.d.ts +40 -0
  92. package/dist/render/glassCasters.js +84 -0
  93. package/dist/render/glassShadow.d.ts +78 -0
  94. package/dist/render/glassShadow.js +125 -0
  95. package/dist/render/globalMediumPass.d.ts +2 -3
  96. package/dist/render/globalMediumPass.js +2 -8
  97. package/dist/render/gpudriven/lit.d.ts +12 -0
  98. package/dist/render/gpudriven/lit.js +23 -0
  99. package/dist/render/gpudriven/materialTable.d.ts +15 -5
  100. package/dist/render/gpudriven/materialTable.js +26 -6
  101. package/dist/render/gpudriven/pipeline.d.ts +1 -1
  102. package/dist/render/gpudriven/pipeline.js +4 -3
  103. package/dist/render/gpudriven/sunGlass.d.ts +35 -0
  104. package/dist/render/gpudriven/sunGlass.js +89 -0
  105. package/dist/render/instanceCull.d.ts +63 -0
  106. package/dist/render/instanceCull.js +160 -0
  107. package/dist/render/instances.d.ts +15 -0
  108. package/dist/render/lightBudget.d.ts +36 -35
  109. package/dist/render/lightBudget.js +38 -37
  110. package/dist/render/lightGrid.d.ts +42 -0
  111. package/dist/render/lightGrid.js +87 -0
  112. package/dist/render/mesh.d.ts +18 -24
  113. package/dist/render/mesh.js +51 -68
  114. package/dist/render/occlusion.d.ts +10 -0
  115. package/dist/render/occlusion.js +36 -7
  116. package/dist/render/pointGlassTint.d.ts +59 -0
  117. package/dist/render/pointGlassTint.js +198 -0
  118. package/dist/render/pointLightSelection.d.ts +7 -0
  119. package/dist/render/pointLightSelection.js +29 -4
  120. package/dist/render/pointShadowArray.d.ts +56 -3
  121. package/dist/render/pointShadowArray.js +127 -16
  122. package/dist/render/pointShadowMap.d.ts +23 -1
  123. package/dist/render/pointShadowMap.js +27 -1
  124. package/dist/render/rainField.d.ts +13 -0
  125. package/dist/render/rainField.js +27 -5
  126. package/dist/render/recon/changeFrames.d.ts +15 -0
  127. package/dist/render/recon/changeFrames.js +21 -0
  128. package/dist/render/recon/lateDepth.d.ts +11 -0
  129. package/dist/render/recon/lateDepth.js +70 -0
  130. package/dist/render/recon/lateRouting.d.ts +14 -0
  131. package/dist/render/recon/lateRouting.js +18 -0
  132. package/dist/render/recon/mover.d.ts +57 -0
  133. package/dist/render/recon/mover.js +86 -0
  134. package/dist/render/recon/resolve.d.ts +34 -4
  135. package/dist/render/recon/resolve.js +161 -20
  136. package/dist/render/renderQuality.d.ts +35 -0
  137. package/dist/render/renderQuality.js +7 -0
  138. package/dist/render/rendererHarness.js +16 -0
  139. package/dist/render/sceneTarget.d.ts +9 -1
  140. package/dist/render/sceneTarget.js +60 -12
  141. package/dist/render/shaders/depth.d.ts +16 -1
  142. package/dist/render/shaders/depth.js +94 -15
  143. package/dist/render/shaders/flat/directionalShadow.js +91 -6
  144. package/dist/render/shaders/flat/driftLight.d.ts +1 -1
  145. package/dist/render/shaders/flat/driftLight.js +32 -7
  146. package/dist/render/shaders/flat/glassTint.d.ts +6 -0
  147. package/dist/render/shaders/flat/glassTint.js +25 -0
  148. package/dist/render/shaders/flat/index.d.ts +13 -0
  149. package/dist/render/shaders/flat/index.js +9 -3
  150. package/dist/render/shaders/flat/lampGlass.d.ts +1 -0
  151. package/dist/render/shaders/flat/lampGlass.js +183 -0
  152. package/dist/render/shaders/flat/main.d.ts +1 -1
  153. package/dist/render/shaders/flat/main.js +190 -38
  154. package/dist/render/shaders/flat/pointShadow.d.ts +1 -1
  155. package/dist/render/shaders/flat/pointShadow.js +2 -0
  156. package/dist/render/shaders/flat/preamble.js +96 -26
  157. package/dist/render/shaders/flat/surfaceEffects.d.ts +29 -0
  158. package/dist/render/shaders/flat/surfaceEffects.js +152 -0
  159. package/dist/render/shaders/generated/depth.wgsl.d.ts +230 -7
  160. package/dist/render/shaders/generated/depth.wgsl.js +230 -7
  161. package/dist/render/shaders/generated/flat.wgsl.d.ts +1644 -1596
  162. package/dist/render/shaders/generated/flat.wgsl.js +1683 -1621
  163. package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +3 -13
  164. package/dist/render/shaders/generated/globalMedium.wgsl.js +3 -13
  165. package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +3 -13
  166. package/dist/render/shaders/generated/lightVolume.wgsl.js +21 -17
  167. package/dist/render/shaders/generated/octahedralResolve.wgsl.d.ts +29 -0
  168. package/dist/render/shaders/generated/octahedralResolve.wgsl.js +29 -0
  169. package/dist/render/shaders/generated/rush.wgsl.d.ts +21 -16
  170. package/dist/render/shaders/generated/rush.wgsl.js +21 -16
  171. package/dist/render/shaders/generated/sdfText.wgsl.d.ts +2 -2
  172. package/dist/render/shaders/generated/sdfText.wgsl.js +2 -2
  173. package/dist/render/shaders/generated/text.wgsl.d.ts +1 -1
  174. package/dist/render/shaders/generated/text.wgsl.js +1 -1
  175. package/dist/render/shaders/gi/driftLight.wgsl.d.ts +1 -1
  176. package/dist/render/shaders/gi/driftLight.wgsl.js +27 -4
  177. package/dist/render/shaders/globalMedium.js +6 -6
  178. package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +7 -0
  179. package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +86 -1
  180. package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +1 -1
  181. package/dist/render/shaders/gpudriven/cull.wgsl.js +11 -2
  182. package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +1 -1
  183. package/dist/render/shaders/gpudriven/materialTable.wgsl.js +3 -1
  184. package/dist/render/shaders/gpudriven/shade.wgsl.js +50 -1
  185. package/dist/render/shaders/gpudriven/sunGlass.wgsl.d.ts +9 -0
  186. package/dist/render/shaders/gpudriven/sunGlass.wgsl.js +133 -0
  187. package/dist/render/shaders/lightVolume.js +6 -6
  188. package/dist/render/shaders/octahedralResolve.d.ts +8 -0
  189. package/dist/render/shaders/octahedralResolve.js +48 -17
  190. package/dist/render/shaders/recon/lateDepth.wgsl.d.ts +1 -0
  191. package/dist/render/shaders/recon/lateDepth.wgsl.js +69 -0
  192. package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
  193. package/dist/render/shaders/recon/motion.wgsl.js +84 -0
  194. package/dist/render/shaders/recon/resolve.wgsl.d.ts +8 -7
  195. package/dist/render/shaders/recon/resolve.wgsl.js +161 -27
  196. package/dist/render/shaders/rush.js +11 -1
  197. package/dist/render/shaders/sdfText.d.ts +1 -1
  198. package/dist/render/shaders/sdfText.js +3 -2
  199. package/dist/render/shaders/text.d.ts +1 -1
  200. package/dist/render/shaders/text.js +18 -9
  201. package/dist/render/shadowCasters.d.ts +20 -1
  202. package/dist/render/shadowCasters.js +15 -1
  203. package/dist/render/shadowMap.d.ts +54 -5
  204. package/dist/render/shadowMap.js +190 -36
  205. package/dist/render/sunGlassTint.d.ts +25 -0
  206. package/dist/render/sunGlassTint.js +79 -0
  207. package/dist/render/surfaceEffects.d.ts +83 -0
  208. package/dist/render/surfaceEffects.js +75 -0
  209. package/dist/render/surfaceScene.d.ts +8 -0
  210. package/dist/render/surfaceScene.js +8 -0
  211. package/dist/render/surfaceTexture.d.ts +18 -2
  212. package/dist/render/surfaceTexture.js +68 -15
  213. package/dist/render/temporalAa.d.ts +25 -6
  214. package/dist/render/temporalAa.js +45 -15
  215. package/dist/render/textureSource.d.ts +30 -0
  216. package/dist/render/textureSource.js +53 -0
  217. package/dist/render/translucentQueue.d.ts +6 -0
  218. package/dist/render/translucentQueue.js +15 -1
  219. package/dist/render/vertexDefaults.js +2 -0
  220. package/dist/world/hlod.d.ts +104 -0
  221. package/dist/world/hlod.js +214 -0
  222. package/package.json +6 -6
  223. package/src/geometry/boxCsg.ts +186 -0
  224. package/src/geometry/csg.ts +384 -0
  225. package/src/geometry/meshBuilder.ts +15 -0
  226. package/src/geometry/meshConcat.ts +1 -0
  227. package/src/geometry/pixelFont.ts +2 -0
  228. package/src/geometry/solid.ts +189 -0
  229. package/src/geometry/solidFlat.ts +522 -0
  230. package/src/geometry/solidHarness.ts +83 -0
  231. package/src/geometry/solidNormals.ts +103 -0
  232. package/src/geometry/solidRound.ts +443 -0
  233. package/src/geometry/solidWriter.ts +58 -0
  234. package/src/index.ts +61 -1
  235. package/src/render/backend/api.ts +36 -11
  236. package/src/render/backend/drawFog.ts +31 -0
  237. package/src/render/backend/materialChanges.ts +9 -2
  238. package/src/render/backend/webgl2/glassTintPrograms.ts +58 -0
  239. package/src/render/backend/webgl2/instanced.ts +80 -14
  240. package/src/render/backend/webgl2/renderer.ts +700 -250
  241. package/src/render/backend/webgpu/buffers.ts +92 -5
  242. package/src/render/backend/webgpu/depthPass.ts +7 -2
  243. package/src/render/backend/webgpu/drawCommand.ts +6 -0
  244. package/src/render/backend/webgpu/flatPass.ts +62 -11
  245. package/src/render/backend/webgpu/glassTintPass.ts +245 -0
  246. package/src/render/backend/webgpu/gpuDrivenPass.ts +349 -5
  247. package/src/render/backend/webgpu/instanceCullPass.ts +165 -0
  248. package/src/render/backend/webgpu/instanced.ts +42 -4
  249. package/src/render/backend/webgpu/latePass.ts +161 -0
  250. package/src/render/backend/webgpu/lightVolumePass.ts +5 -1
  251. package/src/render/backend/webgpu/motionPass.ts +535 -0
  252. package/src/render/backend/webgpu/pipelineCache.ts +12 -1
  253. package/src/render/backend/webgpu/pointGlassTintPass.ts +233 -0
  254. package/src/render/backend/webgpu/pointShadowPass.ts +158 -26
  255. package/src/render/backend/webgpu/renderer.ts +1671 -670
  256. package/src/render/backend/webgpu/scatterPass.ts +2 -1
  257. package/src/render/backend/webgpu/sdfTextPass.ts +6 -1
  258. package/src/render/backend/webgpu/shaders/instanceCull.wgsl.ts +61 -0
  259. package/src/render/backend/webgpu/skinPaletteRing.ts +4 -0
  260. package/src/render/backend/webgpu/snapshotMips.ts +80 -0
  261. package/src/render/backend/webgpu/surfaceTexturePass.ts +91 -51
  262. package/src/render/driftLight/bake.ts +85 -62
  263. package/src/render/driftLight/denseField.ts +149 -0
  264. package/src/render/driftLight/lightField.ts +33 -18
  265. package/src/render/driftLight/presence.ts +69 -0
  266. package/src/render/driftLight/uniforms.ts +8 -9
  267. package/src/render/driftLight/worldLightField.ts +83 -0
  268. package/src/render/fixtureAtlas.ts +63 -0
  269. package/src/render/glass.ts +74 -0
  270. package/src/render/glassCasters.ts +164 -0
  271. package/src/render/glassShadow.ts +153 -0
  272. package/src/render/globalMediumPass.ts +4 -11
  273. package/src/render/gpudriven/lit.ts +31 -0
  274. package/src/render/gpudriven/materialTable.ts +28 -6
  275. package/src/render/gpudriven/pipeline.ts +4 -3
  276. package/src/render/gpudriven/sunGlass.ts +117 -0
  277. package/src/render/instanceCull.ts +205 -0
  278. package/src/render/instances.ts +16 -0
  279. package/src/render/lightBudget.ts +41 -38
  280. package/src/render/lightGrid.ts +130 -0
  281. package/src/render/mesh.ts +59 -72
  282. package/src/render/occlusion.ts +51 -7
  283. package/src/render/pointGlassTint.ts +250 -0
  284. package/src/render/pointLightSelection.ts +72 -4
  285. package/src/render/pointShadowArray.ts +188 -22
  286. package/src/render/pointShadowMap.ts +41 -0
  287. package/src/render/rainField.ts +39 -5
  288. package/src/render/recon/changeFrames.ts +24 -0
  289. package/src/render/recon/lateDepth.ts +83 -0
  290. package/src/render/recon/lateRouting.ts +29 -0
  291. package/src/render/recon/mover.ts +118 -0
  292. package/src/render/recon/resolve.ts +206 -20
  293. package/src/render/renderQuality.ts +47 -0
  294. package/src/render/rendererHarness.ts +16 -0
  295. package/src/render/sceneTarget.ts +62 -11
  296. package/src/render/shaders/depth.ts +118 -15
  297. package/src/render/shaders/flat/directionalShadow.ts +97 -6
  298. package/src/render/shaders/flat/driftLight.ts +32 -7
  299. package/src/render/shaders/flat/glassTint.ts +25 -0
  300. package/src/render/shaders/flat/index.ts +22 -3
  301. package/src/render/shaders/flat/lampGlass.ts +185 -0
  302. package/src/render/shaders/flat/main.ts +190 -38
  303. package/src/render/shaders/flat/pointShadow.ts +2 -0
  304. package/src/render/shaders/flat/preamble.ts +96 -26
  305. package/src/render/shaders/flat/surfaceEffects.ts +152 -0
  306. package/src/render/shaders/generated/depth.wgsl.ts +237 -7
  307. package/src/render/shaders/generated/flat.wgsl.ts +1685 -1621
  308. package/src/render/shaders/generated/globalMedium.wgsl.ts +3 -13
  309. package/src/render/shaders/generated/lightVolume.wgsl.ts +23 -17
  310. package/src/render/shaders/generated/octahedralResolve.wgsl.ts +30 -0
  311. package/src/render/shaders/generated/rush.wgsl.ts +21 -16
  312. package/src/render/shaders/generated/sdfText.wgsl.ts +2 -2
  313. package/src/render/shaders/generated/text.wgsl.ts +1 -1
  314. package/src/render/shaders/gi/driftLight.wgsl.ts +27 -4
  315. package/src/render/shaders/globalMedium.ts +6 -6
  316. package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +88 -1
  317. package/src/render/shaders/gpudriven/cull.wgsl.ts +11 -2
  318. package/src/render/shaders/gpudriven/materialTable.wgsl.ts +3 -1
  319. package/src/render/shaders/gpudriven/shade.wgsl.ts +50 -1
  320. package/src/render/shaders/gpudriven/sunGlass.wgsl.ts +139 -0
  321. package/src/render/shaders/lightVolume.ts +6 -6
  322. package/src/render/shaders/octahedralResolve.ts +50 -17
  323. package/src/render/shaders/recon/lateDepth.wgsl.ts +72 -0
  324. package/src/render/shaders/recon/motion.wgsl.ts +84 -0
  325. package/src/render/shaders/recon/resolve.wgsl.ts +161 -27
  326. package/src/render/shaders/rush.ts +11 -1
  327. package/src/render/shaders/sdfText.ts +3 -2
  328. package/src/render/shaders/text.ts +18 -9
  329. package/src/render/shadowCasters.ts +28 -1
  330. package/src/render/shadowMap.ts +231 -37
  331. package/src/render/sunGlassTint.ts +86 -0
  332. package/src/render/surfaceEffects.ts +132 -0
  333. package/src/render/surfaceScene.ts +16 -0
  334. package/src/render/surfaceTexture.ts +110 -19
  335. package/src/render/temporalAa.ts +78 -14
  336. package/src/render/textureSource.ts +72 -0
  337. package/src/render/translucentQueue.ts +20 -1
  338. package/src/render/vertexDefaults.ts +2 -0
  339. package/src/world/hlod.ts +290 -0
@@ -59,6 +59,8 @@
59
59
  * generated, so taking it mirrors the picture — and mirrors the winding with it, which is how it
60
60
  * reads as a culling problem. `PassDevice` carries both matrices and says which is which.
61
61
  */
62
+ import { type GlassOptions } from '../../glass.ts';
63
+ import type { GlassShadows } from '../../renderQuality.ts';
62
64
  import { type FogOptions } from '../../fog.ts';
63
65
  import { StreamingScene } from '../../gpudriven/streamScene.ts';
64
66
  import { type GpuDrivenTextures } from '../../gpudriven/materialTable.ts';
@@ -69,7 +71,7 @@ import type { PassContext, PassDefinition, PassDevice, PrepareContext } from '..
69
71
  * Five blocks since 2026-09-17 — the three texture programs, the UV scale and the map strengths
70
72
  * joined the eight — and `gpudriven/materialTable.ts` writes them.
71
73
  */
72
- export declare const MATERIAL_FLOATS = 24;
74
+ export declare const MATERIAL_FLOATS = 28;
73
75
  /** Floats a vertex in the one interleaved buffer: position, normal, colour, uv. */
74
76
  export declare const VERTEX_FLOATS = 12;
75
77
  /**
@@ -186,6 +188,14 @@ export interface GpuDrivenMaterial {
186
188
  * blend and said nothing else gets — visible, and therefore findable.
187
189
  */
188
190
  readonly opacity?: number;
191
+ /**
192
+ * Glass: how much light passes, how milky it is, and the colour it takes — `GlassOptions`, as the
193
+ * forward path's `drawTranslucentMesh` takes it. Absent, or letting nothing through, is not glass.
194
+ *
195
+ * **A glass material is drawn in the blended half whatever `blend` says**, because a visibility
196
+ * buffer holds one surface a pixel and glass is the pane and what is behind it.
197
+ */
198
+ readonly glass?: GlassOptions;
189
199
  }
190
200
  /** What the pass needs told once a frame, before `beginFrame`. */
191
201
  export interface GpuDrivenView {
@@ -288,6 +298,12 @@ export interface GpuDrivenShadowOptions {
288
298
  * texels, and reaches toward the sun as far as the scene does.
289
299
  */
290
300
  readonly followRadius?: number;
301
+ /**
302
+ * What the sun keeps through glass: `RenderQualityOptions.glassShadows`, which a contributed pass
303
+ * is not handed and so takes here. `'full'` by default, as there; `'half'` halves the tint and
304
+ * `'off'` draws a glass material's shadow as nothing, which is what it cast before.
305
+ */
306
+ readonly glass?: GlassShadows;
291
307
  }
292
308
  export declare class GpuDrivenPass implements PassDefinition {
293
309
  readonly label = "driftengine.gpu-driven";
@@ -410,6 +426,30 @@ export declare class GpuDrivenPass implements PassDefinition {
410
426
  private latentClamp;
411
427
  private latentRepeat;
412
428
  private shadowView;
429
+ /** The nearest pane's depth from the sun: the shadow texture's second layer, where glass casts. */
430
+ private glassDepthView;
431
+ /** What the panes let through, as the sun sees them, with the chain frost reads. */
432
+ private glassTintTexture;
433
+ private glassTintTarget;
434
+ private glassTintSampled;
435
+ private glassTintMips;
436
+ /** One white texel, bound where no glass casts, which the lookup reads as none. */
437
+ private glassTintNone;
438
+ private readonly glassMode;
439
+ /** Whether the sun's glass pass runs at all: a glass material, and glass shadows not off. */
440
+ private readonly castsGlass;
441
+ private glassList;
442
+ private glassArgs;
443
+ private glassLodBuffer;
444
+ private readonly lodParamsGlass;
445
+ private shadowCullSettingsGlass;
446
+ private glassLodGroup;
447
+ private glassCullGroup;
448
+ private glassCompactGroup;
449
+ private glassDepthPipeline;
450
+ private glassDepthGroup;
451
+ private glassTintPipeline;
452
+ private glassTintGroup;
413
453
  /**
414
454
  * What is bound as the probe where the frame has none.
415
455
  *
@@ -521,7 +561,18 @@ export declare class GpuDrivenPass implements PassDefinition {
521
561
  private visibilityTexture;
522
562
  private depthTexture;
523
563
  private colourTexture;
564
+ /** Level 0: what the shading writes, the resolve lays over and the blit presents. */
524
565
  private colourView;
566
+ /** Every level, for glass to read at the level its frost picks. Level 0 alone with no glass. */
567
+ private colourSampledView;
568
+ /** The chain glass reads, filled from the shaded picture each frame; null in a scene with none. */
569
+ private colourMips;
570
+ /** Whether any material is glass, which is what earns the colour its chain: see `buildTargets`. */
571
+ private readonly hasGlass;
572
+ /** The pipelines the chain draws with, one a format. */
573
+ private readonly mipPipelineCache;
574
+ private readonly mipPipelines;
575
+ private glassSampler;
525
576
  private visibility;
526
577
  private hzb;
527
578
  private levelStart;
@@ -794,8 +845,16 @@ export declare class GpuDrivenPass implements PassDefinition {
794
845
  * second render pass where it ended, so `shadow` in the stage times is all of it.
795
846
  */
796
847
  private drawShadow;
848
+ /**
849
+ * The sun's glass, after its opaque map: the glass cut from the light, then the panes drawn
850
+ * twice — where the nearest one is, and what they let through, multiplied — and the tint's
851
+ * chain filled for frost to read. The forward path's `flushSunGlass`, in this pipeline's terms.
852
+ */
853
+ private drawShadowGlass;
797
854
  /** One half of the map: the first clears it, the second draws over it and closes the stage's time. */
798
855
  private drawShadowHalf;
856
+ /** The linear sampler glass reads the colour's and the tint's chains through, made once. */
857
+ private glassSamplerFor;
799
858
  private drawPhase;
800
859
  draw(ctx: PassContext): void;
801
860
  dispose(device: PassDevice): void;
@@ -70,6 +70,9 @@ import { FRUSTUM_FLOATS, frustumPlanes } from '../../gpudriven/frustum.js';
70
70
  import { VIS_EMPTY } from '../../gpudriven/visbuffer.js';
71
71
  import { jitterClip } from '../../recon/jitter.js';
72
72
  import { GPU_DRIVEN_ORDERED, GPU_DRIVEN_PASSES, GPU_DRIVEN_RESOURCES, gpuDrivenLive, gpuDrivenRefusal, gpuDrivenSupported, recordGpuDrivenStages, } from '../../gpudriven/pipeline.js';
73
+ import { resolveGlass } from '../../glass.js';
74
+ import { GLASS_TINT_BLEND } from './glassTintPass.js';
75
+ import { SnapshotMips } from './snapshotMips.js';
73
76
  import { createDeps, resetDeps } from '../../frame/deps.js';
74
77
  import { createGraphPasses, createGraphScratch, scheduleGraph } from '../../frame/graphSchedule.js';
75
78
  import { hzbMipCount, hzbMipSize } from '../../gpudriven/hzb.js';
@@ -384,6 +387,30 @@ export class GpuDrivenPass {
384
387
  latentClamp = null;
385
388
  latentRepeat = null;
386
389
  shadowView = null;
390
+ /** The nearest pane's depth from the sun: the shadow texture's second layer, where glass casts. */
391
+ glassDepthView = null;
392
+ /** What the panes let through, as the sun sees them, with the chain frost reads. */
393
+ glassTintTexture = null;
394
+ glassTintTarget = null;
395
+ glassTintSampled = null;
396
+ glassTintMips = null;
397
+ /** One white texel, bound where no glass casts, which the lookup reads as none. */
398
+ glassTintNone = null;
399
+ glassMode;
400
+ /** Whether the sun's glass pass runs at all: a glass material, and glass shadows not off. */
401
+ castsGlass;
402
+ glassList = null;
403
+ glassArgs = null;
404
+ glassLodBuffer = null;
405
+ lodParamsGlass = new Float32Array(8);
406
+ shadowCullSettingsGlass = null;
407
+ glassLodGroup = null;
408
+ glassCullGroup = null;
409
+ glassCompactGroup = null;
410
+ glassDepthPipeline = null;
411
+ glassDepthGroup = null;
412
+ glassTintPipeline = null;
413
+ glassTintGroup = null;
387
414
  /**
388
415
  * What is bound as the probe where the frame has none.
389
416
  *
@@ -497,7 +524,27 @@ export class GpuDrivenPass {
497
524
  visibilityTexture = null;
498
525
  depthTexture = null;
499
526
  colourTexture = null;
527
+ /** Level 0: what the shading writes, the resolve lays over and the blit presents. */
500
528
  colourView = null;
529
+ /** Every level, for glass to read at the level its frost picks. Level 0 alone with no glass. */
530
+ colourSampledView = null;
531
+ /** The chain glass reads, filled from the shaded picture each frame; null in a scene with none. */
532
+ colourMips = null;
533
+ /** Whether any material is glass, which is what earns the colour its chain: see `buildTargets`. */
534
+ hasGlass;
535
+ /** The pipelines the chain draws with, one a format. */
536
+ mipPipelineCache = new Map();
537
+ mipPipelines = {
538
+ get: (key, describe) => {
539
+ const held = this.mipPipelineCache.get(key);
540
+ if (held !== undefined)
541
+ return held;
542
+ const made = this.device.createRenderPipeline(describe());
543
+ this.mipPipelineCache.set(key, made);
544
+ return made;
545
+ },
546
+ };
547
+ glassSampler = null;
501
548
  visibility = null;
502
549
  hzb = null;
503
550
  levelStart = null;
@@ -613,7 +660,10 @@ export class GpuDrivenPass {
613
660
  this.decode = packDecodeTables(this.programs.programs);
614
661
  this.scene = scene;
615
662
  this.materials = materials;
663
+ this.hasGlass = materials.some((material) => resolveGlass(material.glass, glassProbe));
616
664
  this.shadowSize = shadow.mapSize ?? DEFAULT_RENDER_QUALITY.directionalShadowMapSize;
665
+ this.glassMode = shadow.glass ?? DEFAULT_RENDER_QUALITY.glassShadows;
666
+ this.castsGlass = this.hasGlass && this.glassMode !== 'off';
617
667
  this.shadowMaxDistance =
618
668
  shadow.maxDistance ?? DEFAULT_RENDER_QUALITY.directionalShadowMaxDistance;
619
669
  this.shadowMaxSlope = shadow.maxSlope ?? DEFAULT_RENDER_QUALITY.directionalShadowMaxSlope;
@@ -840,6 +890,10 @@ export class GpuDrivenPass {
840
890
  this.shadowArgs = this.storage(device, 'draw shadow', shadowArgs, INDIRECT | COPY_SRC);
841
891
  this.shadowArgsTwo = this.storage(device, 'draw shadow two', shadowArgs, INDIRECT | COPY_SRC);
842
892
  this.shadowSelected = this.empty(device, 'shadow selected', count * 4);
893
+ /* The sun's glass: its own list and arguments, over the light's selection once the map is done. */
894
+ this.glassList = this.empty(device, 'shadow glass list', count * 4);
895
+ this.glassArgs = this.storage(device, 'draw shadow glass', shadowArgs, INDIRECT | COPY_SRC);
896
+ this.glassLodBuffer = this.empty(device, 'lod params glass', 8 * 4);
843
897
  this.shadowKeep = this.empty(device, 'shadow keep', count * 4);
844
898
  this.shadowPlanes = this.empty(device, 'shadow planes', FRUSTUM_FLOATS * 4);
845
899
  this.shadowHistories = [
@@ -862,6 +916,8 @@ export class GpuDrivenPass {
862
916
  this.shadowCullValues[CULL_CONES] = 1;
863
917
  this.shadowCullSettings = this.storage(device, 'cull settings, shadow', this.shadowCullValues);
864
918
  this.shadowCullSettingsTwo = this.storage(device, 'cull settings, shadow two', this.shadowCullValues);
919
+ /* The glass pass's: no pyramid and no cones, since a pane casts from either side. */
920
+ this.shadowCullSettingsGlass = this.storage(device, 'cull settings, shadow glass', this.shadowCullValues);
865
921
  this.shadowCompactSettings = this.storage(device, 'phase shadow', Uint32Array.from([PHASE_ONE, count]));
866
922
  this.shadowCompactSettingsTwo = this.storage(device, 'phase shadow two', Uint32Array.from([PHASE_TWO, count]));
867
923
  /* Nonzero is hidden, and the light hides nothing: see `CULL_INSTANCES_WGSL`. */
@@ -875,11 +931,47 @@ export class GpuDrivenPass {
875
931
  */
876
932
  this.shadowTexture = device.createTexture({
877
933
  label: 'gpu-driven shadow',
878
- size: { width: this.shadowSize, height: this.shadowSize },
934
+ /* A second layer for the nearest pane where a material is glass, and none where none is. */
935
+ size: {
936
+ width: this.shadowSize,
937
+ height: this.shadowSize,
938
+ depthOrArrayLayers: this.castsGlass ? 2 : 1,
939
+ },
879
940
  format: SHADOW_FORMAT,
880
941
  usage: RENDER_ATTACHMENT | TEXTURE_BINDING,
881
942
  });
882
- this.shadowView = this.shadowTexture.createView();
943
+ const layer = (at) => this.shadowTexture.createView({
944
+ dimension: '2d',
945
+ baseArrayLayer: at,
946
+ arrayLayerCount: 1,
947
+ });
948
+ this.shadowView = layer(0);
949
+ this.glassDepthView = this.castsGlass ? layer(1) : null;
950
+ const tintSize = this.glassMode === 'half' ? Math.max(1, this.shadowSize >> 1) : this.shadowSize;
951
+ this.glassTintTexture = this.castsGlass
952
+ ? device.createTexture({
953
+ label: 'gpu-driven glass tint',
954
+ size: { width: tintSize, height: tintSize },
955
+ format: 'rgba8unorm',
956
+ mipLevelCount: Math.floor(Math.log2(tintSize)) + 1,
957
+ usage: RENDER_ATTACHMENT | TEXTURE_BINDING,
958
+ })
959
+ : null;
960
+ if (this.glassTintTexture !== null) {
961
+ this.glassTintTarget = this.glassTintTexture.createView({
962
+ baseMipLevel: 0,
963
+ mipLevelCount: 1,
964
+ });
965
+ this.glassTintSampled = this.glassTintTexture.createView();
966
+ this.glassTintMips = new SnapshotMips(device, this.mipPipelines, this.glassTintTexture, 'rgba8unorm', null, 'gpu-driven glass tint mips');
967
+ }
968
+ this.glassTintNone = device.createTexture({
969
+ label: 'gpu-driven no glass',
970
+ size: { width: 1, height: 1 },
971
+ format: 'rgba8unorm',
972
+ usage: TEXTURE_BINDING | TEXTURE_COPY_DST,
973
+ });
974
+ device.queue.writeTexture({ texture: this.glassTintNone }, new Uint8Array([255, 255, 255, 255]), { bytesPerRow: 4 }, { width: 1, height: 1 });
883
975
  this.emptyEnvironment = device.createTexture({
884
976
  label: 'gpu-driven no environment',
885
977
  size: { width: 1, height: 1, depthOrArrayLayers: 1 },
@@ -1171,6 +1263,37 @@ export class GpuDrivenPass {
1171
1263
  });
1172
1264
  this.shadowGroup = shadowRasterFor(this.shadowList);
1173
1265
  this.shadowGroupTwo = shadowRasterFor(this.shadowListTwo);
1266
+ /*
1267
+ * **The nearest pane, from the sun: the same raster, culling nothing**, since a pane casts from
1268
+ * either side; into the shadow texture's second layer. Built only where glass casts.
1269
+ */
1270
+ if (this.castsGlass) {
1271
+ this.glassDepthPipeline = device.createRenderPipeline({
1272
+ label: 'gpu-driven shadow glass',
1273
+ layout: 'auto',
1274
+ vertex: { module: raster, entryPoint: 'vertexMain' },
1275
+ primitive: { topology: 'triangle-list', cullMode: 'none', frontFace: 'cw' },
1276
+ depthStencil: {
1277
+ format: SHADOW_FORMAT,
1278
+ depthWriteEnabled: true,
1279
+ depthCompare: 'less',
1280
+ depthBias: 4,
1281
+ depthBiasSlopeScale: 1.1,
1282
+ },
1283
+ });
1284
+ this.glassDepthGroup = device.createBindGroup({
1285
+ layout: this.glassDepthPipeline.getBindGroupLayout(0),
1286
+ entries: [
1287
+ { binding: 0, resource: { buffer: this.shadowMatrix } },
1288
+ { binding: 1, resource: { buffer: this.glassList } },
1289
+ { binding: 2, resource: { buffer: this.clusterMeta } },
1290
+ { binding: 3, resource: { buffer: this.indices } },
1291
+ { binding: 4, resource: { buffer: this.vertices } },
1292
+ { binding: 5, resource: { buffer: this.transformBuffer } },
1293
+ { binding: 6, resource: { buffer: this.materialOf } },
1294
+ ],
1295
+ });
1296
+ }
1174
1297
  /*
1175
1298
  * **The transparent half's raster: one indirect draw into two targets at once.**
1176
1299
  *
@@ -1236,6 +1359,38 @@ export class GpuDrivenPass {
1236
1359
  },
1237
1360
  });
1238
1361
  this.watchBlendPipeline(device);
1362
+ /*
1363
+ * **What a pane lets through, from the sun**: the blended raster's vertex stage handed the
1364
+ * light's matrix and the glass list, and \`glassTintFrag\` for the colour — white target, a
1365
+ * multiplying blend, no depth, so every pane on a ray counts in any order.
1366
+ */
1367
+ if (this.castsGlass) {
1368
+ this.glassTintPipeline = device.createRenderPipeline({
1369
+ label: 'gpu-driven shadow tint',
1370
+ layout: 'auto',
1371
+ vertex: { module: blend, entryPoint: 'blendVert' },
1372
+ fragment: {
1373
+ module: blend,
1374
+ entryPoint: 'glassTintFrag',
1375
+ targets: [{ format: 'rgba8unorm', blend: GLASS_TINT_BLEND }],
1376
+ },
1377
+ primitive: { topology: 'triangle-list', cullMode: 'none' },
1378
+ });
1379
+ this.glassTintGroup = device.createBindGroup({
1380
+ layout: this.glassTintPipeline.getBindGroupLayout(0),
1381
+ entries: [
1382
+ { binding: 0, resource: { buffer: this.shadowMatrix } },
1383
+ { binding: 1, resource: { buffer: this.glassList } },
1384
+ { binding: 2, resource: { buffer: this.clusterMeta } },
1385
+ { binding: 3, resource: { buffer: this.indices } },
1386
+ { binding: 4, resource: { buffer: this.vertices } },
1387
+ { binding: 5, resource: { buffer: this.transformBuffer } },
1388
+ { binding: 6, resource: { buffer: this.materialOf } },
1389
+ { binding: 7, resource: { buffer: this.materialTable } },
1390
+ { binding: 8, resource: { buffer: this.frameBuffer } },
1391
+ ],
1392
+ });
1393
+ }
1239
1394
  /*
1240
1395
  * **Premultiplied over, where `renderer.ts`'s composite is a lerp**, and `blendRaster.wgsl.ts`
1241
1396
  * carries why: this pipeline's colour target has a coverage mask in its alpha, which the blit
@@ -1402,6 +1557,39 @@ export class GpuDrivenPass {
1402
1557
  shadowCullFor(this.shadowCullSettings),
1403
1558
  shadowCullFor(this.shadowCullSettingsTwo),
1404
1559
  ];
1560
+ /*
1561
+ * **The sun's glass cut: the light's selection again, of the glass alone**, once the map is
1562
+ * drawn and those buffers are free. The camera's level of detail, as the map's; every pane in
1563
+ * the light's frustum kept, as the blended half keeps every pane — so compacted as phase two
1564
+ * against a history of zeros, exactly as that half is.
1565
+ */
1566
+ if (this.castsGlass) {
1567
+ this.glassLodGroup = device.createBindGroup({
1568
+ layout: this.lodPipeline.getBindGroupLayout(0),
1569
+ entries: [
1570
+ { binding: 0, resource: { buffer: this.glassLodBuffer } },
1571
+ { binding: 1, resource: { buffer: this.clusterLod } },
1572
+ { binding: 2, resource: { buffer: this.shadowSelected } },
1573
+ { binding: 3, resource: { buffer: this.clusterMeta } },
1574
+ { binding: 4, resource: { buffer: this.instanceNone } },
1575
+ { binding: 5, resource: { buffer: this.materialOf } },
1576
+ { binding: 6, resource: { buffer: this.materialTable } },
1577
+ ],
1578
+ });
1579
+ this.glassCullGroup = shadowCullFor(this.shadowCullSettingsGlass);
1580
+ this.glassCompactGroup = device.createBindGroup({
1581
+ layout: this.compactPipeline.getBindGroupLayout(0),
1582
+ entries: [
1583
+ { binding: 0, resource: { buffer: this.blendCompactSettings } },
1584
+ { binding: 1, resource: { buffer: this.shadowSelected } },
1585
+ { binding: 2, resource: { buffer: this.shadowKeep } },
1586
+ { binding: 3, resource: { buffer: this.zeroHistory } },
1587
+ { binding: 4, resource: { buffer: this.glassList } },
1588
+ { binding: 5, resource: { buffer: this.historySink } },
1589
+ { binding: 6, resource: { buffer: this.glassArgs } },
1590
+ ],
1591
+ });
1592
+ }
1405
1593
  this.shadowSeedGroup = device.createBindGroup({
1406
1594
  layout: this.shadowSeedPipeline.getBindGroupLayout(0),
1407
1595
  entries: [
@@ -1582,11 +1770,22 @@ export class GpuDrivenPass {
1582
1770
  label: 'gpu-driven colour',
1583
1771
  size: { width: stride, height },
1584
1772
  format: 'rgba16float',
1773
+ /*
1774
+ * **A chain only where a material is glass**, which a frosted pane reads a coarser level of,
1775
+ * as the forward path's refraction copy does. A scene with no glass allocates exactly the one
1776
+ * level it always did.
1777
+ */
1778
+ mipLevelCount: this.hasGlass ? Math.floor(Math.log2(Math.max(stride, height))) + 1 : 1,
1585
1779
  /* `RENDER_ATTACHMENT` only so a clear-only render pass can empty it each frame: a storage
1586
1780
  texture has no clear, and the alternative is a dispatch over every pixel. */
1587
1781
  usage: STORAGE_BINDING | TEXTURE_BINDING | RENDER_ATTACHMENT,
1588
1782
  });
1589
- this.colourView = this.colourTexture.createView();
1783
+ /* A storage binding takes one level, so everything that writes or presents reads level 0. */
1784
+ this.colourView = this.colourTexture.createView({ baseMipLevel: 0, mipLevelCount: 1 });
1785
+ this.colourSampledView = this.colourTexture.createView();
1786
+ this.colourMips = this.hasGlass
1787
+ ? new SnapshotMips(device, this.mipPipelines, this.colourTexture, 'rgba16float', null, 'gpu-driven colour mips')
1788
+ : null;
1590
1789
  this.oitAccum = device.createTexture({
1591
1790
  label: 'gpu-driven oit accum',
1592
1791
  size: { width: stride, height },
@@ -1726,12 +1925,22 @@ export class GpuDrivenPass {
1726
1925
  { binding: 16, resource: this.latentRepeat },
1727
1926
  { binding: 17, resource: { buffer: this.decodeNodes } },
1728
1927
  { binding: 18, resource: { buffer: this.decodeWeights } },
1928
+ /* The sun's glass, or the opaque map and a white texel where none casts. */
1929
+ {
1930
+ binding: 19,
1931
+ resource: this.glassDepthView ?? this.shadowView,
1932
+ },
1933
+ {
1934
+ binding: 20,
1935
+ resource: this.glassTintSampled ?? this.glassTintNone.createView(),
1936
+ },
1937
+ { binding: 21, resource: this.glassSamplerFor(device) },
1729
1938
  ],
1730
1939
  });
1731
1940
  this.blitGroup = device.createBindGroup({
1732
1941
  layout: this.blitPipeline.getBindGroupLayout(0),
1733
1942
  entries: [
1734
- { binding: 0, resource: this.colourTexture.createView() },
1943
+ { binding: 0, resource: this.colourView },
1735
1944
  /* The depth the raster wrote, sampled so the blit can hand it to the frame. */
1736
1945
  ...(this.presentDepth
1737
1946
  ? [
@@ -1774,6 +1983,12 @@ export class GpuDrivenPass {
1774
1983
  { binding: 13, resource: this.latentRepeat },
1775
1984
  { binding: 14, resource: { buffer: this.decodeNodes } },
1776
1985
  { binding: 15, resource: { buffer: this.decodeWeights } },
1986
+ /* What the opaque half drew, for glass to show: `blendRaster.wgsl.ts`. */
1987
+ { binding: 16, resource: this.colourSampledView },
1988
+ {
1989
+ binding: 17,
1990
+ resource: this.glassSamplerFor(device),
1991
+ },
1777
1992
  ],
1778
1993
  });
1779
1994
  /*
@@ -1979,6 +2194,16 @@ export class GpuDrivenPass {
1979
2194
  queue.writeBuffer(this.shadowCullSettings, 0, this.shadowCullValues);
1980
2195
  this.shadowCullValues[3] = this.occlusion ? 1 : 0;
1981
2196
  queue.writeBuffer(this.shadowCullSettingsTwo, 0, this.shadowCullValues);
2197
+ if (this.castsGlass) {
2198
+ /* No pyramid and no cones, and the cones put back for the next frame's first write. */
2199
+ this.shadowCullValues[3] = 0;
2200
+ this.shadowCullValues[CULL_CONES] = 0;
2201
+ queue.writeBuffer(this.shadowCullSettingsGlass, 0, this.shadowCullValues);
2202
+ this.shadowCullValues[CULL_CONES] = 1;
2203
+ this.lodParamsGlass.set(this.lodParamsBlend);
2204
+ this.lodParamsGlass[7] = 1;
2205
+ queue.writeBuffer(this.glassLodBuffer, 0, this.lodParamsGlass);
2206
+ }
1982
2207
  queue.writeBuffer(this.planesBuffer, 0, this.planes);
1983
2208
  queue.writeBuffer(this.frameBuffer, 0, params);
1984
2209
  queue.writeBuffer(this.lodBuffer, 0, this.lodParams);
@@ -2038,7 +2263,9 @@ export class GpuDrivenPass {
2038
2263
  * one: the table is written when the pass is built. A scene with nothing blended schedules the
2039
2264
  * three transparent stages away entirely and encodes the frame it encoded before they existed.
2040
2265
  */
2041
- this.shape.blended = this.materials.some((material) => material.blend === true);
2266
+ /* Glass is the blended half's whatever its flag says: a visibility buffer holds one surface. */
2267
+ this.shape.blended =
2268
+ this.hasGlass || this.materials.some((material) => material.blend === true);
2042
2269
  /* `instanceCount` is the one word the compaction touches; the other three never change. */
2043
2270
  encoder.clearBuffer(argsOne, 4, 4);
2044
2271
  encoder.clearBuffer(argsTwo, 4, 4);
@@ -2212,6 +2439,8 @@ export class GpuDrivenPass {
2212
2439
  */
2213
2440
  if (!this.blendUsable || this.blendPipeline === null || this.blendRasterGroup === null)
2214
2441
  return;
2442
+ /* The shaded picture's chain, which glass reads: after `shade`, before the panes. */
2443
+ this.colourMips?.record(encoder);
2215
2444
  const pass = encoder.beginRenderPass({
2216
2445
  label: 'gpu-driven blend draw',
2217
2446
  colorAttachments: [
@@ -2519,6 +2748,57 @@ export class GpuDrivenPass {
2519
2748
  second.end();
2520
2749
  this.drawShadowHalf(encoder, 1, writes);
2521
2750
  this.shadowFlipped = !this.shadowFlipped;
2751
+ if (this.castsGlass && this.blendUsable)
2752
+ this.drawShadowGlass(encoder, groups);
2753
+ }
2754
+ /**
2755
+ * The sun's glass, after its opaque map: the glass cut from the light, then the panes drawn
2756
+ * twice — where the nearest one is, and what they let through, multiplied — and the tint's
2757
+ * chain filled for frost to read. The forward path's `flushSunGlass`, in this pipeline's terms.
2758
+ */
2759
+ drawShadowGlass(encoder, groups) {
2760
+ encoder.clearBuffer(this.glassArgs, 4, 4);
2761
+ const cut = encoder.beginComputePass({ label: 'gpu-driven shadow glass cut' });
2762
+ cut.setPipeline(this.lodPipeline);
2763
+ cut.setBindGroup(0, this.glassLodGroup);
2764
+ cut.dispatchWorkgroups(groups);
2765
+ cut.setPipeline(this.cullPipeline);
2766
+ cut.setBindGroup(0, this.glassCullGroup);
2767
+ cut.dispatchWorkgroups(groups);
2768
+ cut.setPipeline(this.compactPipeline);
2769
+ cut.setBindGroup(0, this.glassCompactGroup);
2770
+ cut.dispatchWorkgroups(groups);
2771
+ cut.end();
2772
+ const depth = encoder.beginRenderPass({
2773
+ label: 'gpu-driven shadow glass',
2774
+ colorAttachments: [],
2775
+ depthStencilAttachment: {
2776
+ view: this.glassDepthView,
2777
+ depthClearValue: SHADOW_DEPTH_CLEAR,
2778
+ depthLoadOp: 'clear',
2779
+ depthStoreOp: 'store',
2780
+ },
2781
+ });
2782
+ depth.setPipeline(this.glassDepthPipeline);
2783
+ depth.setBindGroup(0, this.glassDepthGroup);
2784
+ depth.drawIndirect(this.glassArgs, 0);
2785
+ depth.end();
2786
+ const tint = encoder.beginRenderPass({
2787
+ label: 'gpu-driven shadow tint',
2788
+ colorAttachments: [
2789
+ {
2790
+ view: this.glassTintTarget,
2791
+ clearValue: { r: 1, g: 1, b: 1, a: 1 },
2792
+ loadOp: 'clear',
2793
+ storeOp: 'store',
2794
+ },
2795
+ ],
2796
+ });
2797
+ tint.setPipeline(this.glassTintPipeline);
2798
+ tint.setBindGroup(0, this.glassTintGroup);
2799
+ tint.drawIndirect(this.glassArgs, 0);
2800
+ tint.end();
2801
+ this.glassTintMips?.record(encoder);
2522
2802
  }
2523
2803
  /** One half of the map: the first clears it, the second draws over it and closes the stage's time. */
2524
2804
  drawShadowHalf(encoder, half, writes) {
@@ -2540,6 +2820,18 @@ export class GpuDrivenPass {
2540
2820
  pass.drawIndirect((half === 0 ? this.shadowArgs : this.shadowArgsTwo), 0);
2541
2821
  pass.end();
2542
2822
  }
2823
+ /** The linear sampler glass reads the colour's and the tint's chains through, made once. */
2824
+ glassSamplerFor(device) {
2825
+ this.glassSampler ??= device.createSampler({
2826
+ label: 'gpu-driven glass',
2827
+ magFilter: 'linear',
2828
+ minFilter: 'linear',
2829
+ mipmapFilter: 'linear',
2830
+ addressModeU: 'clamp-to-edge',
2831
+ addressModeV: 'clamp-to-edge',
2832
+ });
2833
+ return this.glassSampler;
2834
+ }
2543
2835
  drawPhase(encoder, phase, clear) {
2544
2836
  const pass = encoder.beginRenderPass({
2545
2837
  label: `gpu-driven phase ${phase + 1}`,
@@ -2597,6 +2889,8 @@ export class GpuDrivenPass {
2597
2889
  return;
2598
2890
  this.disposeTargets();
2599
2891
  this.shadowTexture?.destroy();
2892
+ this.glassTintTexture?.destroy();
2893
+ this.glassTintNone?.destroy();
2600
2894
  this.emptyEnvironment?.destroy();
2601
2895
  this.latents?.destroy();
2602
2896
  this.queries?.destroy();
@@ -2635,6 +2929,10 @@ export class GpuDrivenPass {
2635
2929
  this.shadowListTwo,
2636
2930
  this.shadowSelected,
2637
2931
  this.shadowKeep,
2932
+ this.glassList,
2933
+ this.glassArgs,
2934
+ this.glassLodBuffer,
2935
+ this.shadowCullSettingsGlass,
2638
2936
  this.shadowPlanes,
2639
2937
  this.shadowCullSettings,
2640
2938
  this.shadowCullSettingsTwo,
@@ -2678,3 +2976,5 @@ function multiply(out, a, b) {
2678
2976
  }
2679
2977
  }
2680
2978
  }
2979
+ /** Where `hasGlass` reads each material's glass through; only the answer is kept. */
2980
+ const glassProbe = { transmission: 0, frost: 0, tint: [1, 1, 1] };
@@ -0,0 +1,34 @@
1
+ /** Views a batch can be culled for in one frame. See the header. */
2
+ export declare const MAX_CULL_SLOTS = 4;
3
+ /** One set of survivors: the compacted instances, the indirect record, and what the cull reads. */
4
+ export interface CullSlot {
5
+ readonly instances: GPUBuffer;
6
+ readonly args: GPUBuffer;
7
+ readonly params: GPUBuffer;
8
+ readonly group: GPUBindGroup;
9
+ /** How many instances the last queued job tested, which sizes its dispatch. */
10
+ count: number;
11
+ }
12
+ export declare class InstanceCullPass {
13
+ private readonly device;
14
+ private readonly pipeline;
15
+ private readonly layout;
16
+ private readonly jobs;
17
+ private queued;
18
+ private readonly paramsStaging;
19
+ private readonly paramFloats;
20
+ private readonly paramWords;
21
+ private readonly argsStaging;
22
+ constructor(device: GPUDevice);
23
+ /** A slot reading `source`, a batch's full instance buffer of `capacity` instances. */
24
+ createSlot(source: GPUBuffer, capacity: number, label: string): CullSlot;
25
+ /**
26
+ * Queue a cull of `count` instances against six `planes`, the mesh's local sphere being
27
+ * (centre, radius). Returns false when the frame's job ring is full, and the caller draws uncut.
28
+ */
29
+ queue(slot: CullSlot, planes: Float32Array, centre: ArrayLike<number>, radius: number, count: number, indexCount: number): boolean;
30
+ /** Dispatch everything queued, in one compute pass and one submit. Nothing queued is nothing done. */
31
+ flush(): void;
32
+ }
33
+ /** Every buffer a slot owns, destroyed with its batch. */
34
+ export declare function destroySlot(slot: CullSlot): void;