@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
@@ -1,4 +1,5 @@
1
1
  import { resolveConditionals } from './conditionals.ts';
2
+ import { SUN_STATIC_LAYER } from '../shadowMap.ts';
2
3
  import { CUTOUT_COVERAGE_GLSL } from './cutoutCoverage.ts';
3
4
  import { SKINNING_GLSL } from './skinning.ts';
4
5
  import { CHANNEL_ATTRIBUTE, CHANNEL_BEND } from './vertexChannel.ts';
@@ -63,16 +64,22 @@ ${CHANNEL_BEND}
63
64
  * uniforms declared after every other, so no field of the plain variant moves and a binder written
64
65
  * against it stays right for this one; and two outputs after vLightPosition, which keeps location 0.
65
66
  */
66
- layout(location = 5) in vec2 aUv;
67
+ layout(location = 5) in vec3 aUv;
67
68
  uniform vec2 uUvScale;
68
69
  uniform float uAlphaCutout;
69
70
  #endif
70
71
 
71
72
  out vec4 vLightPosition;
72
73
  #if CUTOUT
73
- out vec2 vUv;
74
+ /* The texture coordinate and, in z, the texture-array layer the face wears. */
75
+ out vec3 vUv;
74
76
  flat out float vAlphaCutout;
75
77
  #endif
78
+ #if GLASS
79
+ /* Where on the pane this is, for the tint's own normal and its angle to the light. Last, so the
80
+ outputs before it keep the locations the plain variants give them. */
81
+ out vec3 vGlassWorld;
82
+ #endif
76
83
 
77
84
  void main() {
78
85
  #if SKINNED
@@ -97,23 +104,26 @@ void main() {
97
104
  vLightPosition = uLightViewProj * vec4(bent, world.w);
98
105
  gl_Position = vLightPosition;
99
106
  #if CUTOUT
100
- vUv = aUv * uUvScale;
107
+ vUv = vec3(aUv.xy * uUvScale, aUv.z);
101
108
  vAlphaCutout = uAlphaCutout;
102
109
  #endif
110
+ #if GLASS
111
+ vGlassWorld = bent;
112
+ #endif
103
113
  }
104
114
  `;
105
115
 
106
116
  /** The rigid variant: the world, a prop, a mesh with no rig behind it. */
107
117
  export const DEPTH_VERT = resolveConditionals(
108
118
  DEPTH_VERT_SOURCE,
109
- { SKINNED: false, INSTANCED: false, CUTOUT: false },
119
+ { SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: false },
110
120
  'depth',
111
121
  );
112
122
 
113
123
  /** The skinned variant, which reads a joint palette and moves the vertex by it. */
114
124
  export const DEPTH_SKINNED_VERT = resolveConditionals(
115
125
  DEPTH_VERT_SOURCE,
116
- { SKINNED: true, INSTANCED: false, CUTOUT: false },
126
+ { SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: false },
117
127
  'depth-skinned',
118
128
  );
119
129
 
@@ -127,7 +137,7 @@ export const DEPTH_SKINNED_VERT = resolveConditionals(
127
137
  */
128
138
  export const DEPTH_INSTANCED_VERT = resolveConditionals(
129
139
  DEPTH_VERT_SOURCE,
130
- { SKINNED: false, INSTANCED: true, CUTOUT: false },
140
+ { SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: false },
131
141
  'depth-instanced',
132
142
  );
133
143
 
@@ -143,13 +153,13 @@ export const DEPTH_INSTANCED_VERT = resolveConditionals(
143
153
  */
144
154
  export const DEPTH_CUTOUT_VERT = resolveConditionals(
145
155
  DEPTH_VERT_SOURCE,
146
- { SKINNED: false, INSTANCED: false, CUTOUT: true },
156
+ { SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: false },
147
157
  'depth-cutout',
148
158
  );
149
159
 
150
160
  export const DEPTH_INSTANCED_CUTOUT_VERT = resolveConditionals(
151
161
  DEPTH_VERT_SOURCE,
152
- { SKINNED: false, INSTANCED: true, CUTOUT: true },
162
+ { SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: false },
153
163
  'depth-instanced-cutout',
154
164
  );
155
165
 
@@ -157,14 +167,14 @@ export const DEPTH_FRAG = `#version 300 es
157
167
  precision highp float;
158
168
  in vec4 vLightPosition;
159
169
 
160
- uniform highp sampler2D uPreviousShadowMap;
170
+ uniform highp sampler2DArray uPreviousShadowMap;
161
171
  uniform int uPeelShadowLayer;
162
172
 
163
173
  void main() {
164
174
  if (uPeelShadowLayer != 0) {
165
175
  vec3 p = vLightPosition.xyz / vLightPosition.w;
166
176
  vec2 uv = p.xy * 0.5 + 0.5;
167
- float previousDepth = texture(uPreviousShadowMap, uv).r;
177
+ float previousDepth = texture(uPreviousShadowMap, vec3(uv, ${SUN_STATIC_LAYER}.0)).r;
168
178
  // Discard the already-recorded surface and everything in front of it. The
169
179
  // ordinary depth test then stores the next independently fading occluder.
170
180
  if (gl_FragCoord.z <= previousDepth + 0.00001) discard;
@@ -187,22 +197,115 @@ void main() {
187
197
  export const DEPTH_CUTOUT_FRAG = `#version 300 es
188
198
  precision highp float;
189
199
  in vec4 vLightPosition;
190
- in vec2 vUv;
200
+ in vec3 vUv;
191
201
  flat in float vAlphaCutout;
192
202
 
193
- uniform highp sampler2D uPreviousShadowMap;
203
+ uniform highp sampler2DArray uPreviousShadowMap;
194
204
  uniform int uPeelShadowLayer;
195
- uniform highp sampler2D uCutoutMap;
205
+ uniform highp sampler2DArray uCutoutMap;
196
206
  ${CUTOUT_COVERAGE_GLSL}
197
207
  void main() {
198
208
  /* Credited for its mip level as the surface's own test is, so a leaf casts the shape it draws. */
199
- float alpha = cutoutAlpha(texture(uCutoutMap, vUv).a, vUv * vec2(textureSize(uCutoutMap, 0)));
209
+ vec3 at = vec3(vUv.xy, floor(vUv.z + 0.5));
210
+ float alpha = cutoutAlpha(texture(uCutoutMap, at).a, vUv.xy * vec2(textureSize(uCutoutMap, 0).xy));
200
211
  if (uPeelShadowLayer != 0) {
201
212
  vec3 p = vLightPosition.xyz / vLightPosition.w;
202
213
  vec2 uv = p.xy * 0.5 + 0.5;
203
- float previousDepth = textureLod(uPreviousShadowMap, uv, 0.0).r;
214
+ float previousDepth = textureLod(uPreviousShadowMap, vec3(uv, ${SUN_STATIC_LAYER}.0), 0.0).r;
204
215
  if (gl_FragCoord.z <= previousDepth + 0.00001) discard;
205
216
  }
206
217
  if (alpha < vAlphaCutout) discard;
207
218
  }
208
219
  `;
220
+
221
+ /**
222
+ * The glass tint's vertex stages: every way a caster is drawn, with the world position handed on.
223
+ *
224
+ * **The same five as the depth pass, and for the same reason**: a pane must cast its colour from
225
+ * exactly where it casts its depth, deformed and placed the same way, or the coloured patch parts
226
+ * from the pane's own shadow edge. The only addition is `vGlassWorld`.
227
+ */
228
+ export const GLASS_TINT_VERT = resolveConditionals(
229
+ DEPTH_VERT_SOURCE,
230
+ { SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: true },
231
+ 'glass-tint',
232
+ );
233
+ export const GLASS_TINT_SKINNED_VERT = resolveConditionals(
234
+ DEPTH_VERT_SOURCE,
235
+ { SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: true },
236
+ 'glass-tint-skinned',
237
+ );
238
+ export const GLASS_TINT_INSTANCED_VERT = resolveConditionals(
239
+ DEPTH_VERT_SOURCE,
240
+ { SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: true },
241
+ 'glass-tint-instanced',
242
+ );
243
+ export const GLASS_TINT_CUTOUT_VERT = resolveConditionals(
244
+ DEPTH_VERT_SOURCE,
245
+ { SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: true },
246
+ 'glass-tint-cutout',
247
+ );
248
+ export const GLASS_TINT_INSTANCED_CUTOUT_VERT = resolveConditionals(
249
+ DEPTH_VERT_SOURCE,
250
+ { SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: true },
251
+ 'glass-tint-instanced-cutout',
252
+ );
253
+
254
+ /**
255
+ * What a pane lets through: its transmission and colour, less what it reflects toward the light,
256
+ * and how clear it is — `glassShadow.ts`'s `paneTexel`, stated for the device. Drawn with a
257
+ * multiplying blend and no depth test, so every pane on a ray contributes whatever order they
258
+ * come in.
259
+ *
260
+ * **The pane's normal is its triangle's**, from the derivatives of its world position, first and in
261
+ * uniform control flow: a pane is flat, a sign does not matter to a cosine taken absolutely, and it
262
+ * spares the five vertex stages a normal they would carry for this alone. What it gives up is a
263
+ * curved pane, whose Fresnel steps per triangle; what would change it is glass that is mostly bulbs.
264
+ */
265
+ const GLASS_TINT_BODY = /* glsl */ `
266
+ vec3 n = normalize(cross(dFdx(vGlassWorld), dFdy(vGlassWorld)));
267
+ vec3 toLight = uGlassLight.w > 0.5 ? normalize(uGlassLight.xyz - vGlassWorld) : uGlassLight.xyz;
268
+ float cosLight = abs(dot(n, toLight));
269
+ float reflected = 0.04 + 0.96 * pow(1.0 - cosLight, 5.0);
270
+ outTint = vec4(uGlassPane.rgb * (1.0 - reflected), uGlassPane.a);
271
+ `;
272
+
273
+ export const GLASS_TINT_FRAG = `#version 300 es
274
+ precision highp float;
275
+ in vec4 vLightPosition;
276
+ in vec3 vGlassWorld;
277
+
278
+ /* rgb: transmission times tint; a: clarity, one less the frost. */
279
+ uniform vec4 uGlassPane;
280
+ /* xyz: the light's position (w 1) or the direction toward it (w 0). */
281
+ uniform vec4 uGlassLight;
282
+
283
+ out vec4 outTint;
284
+
285
+ void main() {
286
+ ${GLASS_TINT_BODY}
287
+ }
288
+ `;
289
+
290
+ /** A cut-out pane: its colour lands only where its depth does, by the depth cutout's own test. */
291
+ export const GLASS_TINT_CUTOUT_FRAG = `#version 300 es
292
+ precision highp float;
293
+ in vec4 vLightPosition;
294
+ in vec3 vUv;
295
+ flat in float vAlphaCutout;
296
+ in vec3 vGlassWorld;
297
+
298
+ uniform vec4 uGlassPane;
299
+ uniform vec4 uGlassLight;
300
+ uniform highp sampler2DArray uCutoutMap;
301
+ ${CUTOUT_COVERAGE_GLSL}
302
+ out vec4 outTint;
303
+
304
+ void main() {
305
+ /* First, in uniform control flow, as the depth cutout samples it. */
306
+ vec3 at = vec3(vUv.xy, floor(vUv.z + 0.5));
307
+ float alpha = cutoutAlpha(texture(uCutoutMap, at).a, vUv.xy * vec2(textureSize(uCutoutMap, 0).xy));
308
+ ${GLASS_TINT_BODY}
309
+ if (alpha < vAlphaCutout) discard;
310
+ }
311
+ `;
@@ -1,5 +1,13 @@
1
1
  /** Filtering the directional cascade, with receiver-plane depth gradient compensation. */
2
2
  import { DIRECTIONAL_SHADOW_FADE_START, MAX_SHADOW_FILTER_TAPS } from '../../renderQuality.ts';
3
+ import {
4
+ SUN_DYNAMIC_LAYER,
5
+ SUN_GLASS_MOVING_LAYER,
6
+ SUN_GLASS_STATIC_LAYER,
7
+ SUN_PEELED_LAYER,
8
+ SUN_STATIC_LAYER,
9
+ } from '../../shadowMap.ts';
10
+ import { FROST_RADIUS_CAP, FROST_SPREAD } from '../../glassShadow.ts';
3
11
 
4
12
  export const DIRECTIONALSHADOW_GLSL = `vec2 receiverPlaneDepthGradient(vec3 p) {
5
13
  vec3 dx = dFdx(p);
@@ -127,10 +135,10 @@ float shadowFactor(float directionalNdl) {
127
135
  */
128
136
  float coarseCompare = p.z - 1.0 / uShadowDepthSpan;
129
137
  float coarse =
130
- directionalVisibility(p.z, coarseCompare, textureLod(uStaticShadowMap, p.xy, 0.0).r) *
131
- directionalVisibility(p.z, coarseCompare, textureLod(uDynamicShadowMap, p.xy, 0.0).r);
138
+ directionalVisibility(p.z, coarseCompare, textureLod(uSunShadows, vec3(p.xy, ${SUN_STATIC_LAYER}.0), 0.0).r) *
139
+ directionalVisibility(p.z, coarseCompare, textureLod(uSunShadows, vec3(p.xy, ${SUN_DYNAMIC_LAYER}.0), 0.0).r);
132
140
  if (uPeeledShadowEnabled != 0) {
133
- coarse *= directionalVisibility(p.z, coarseCompare, textureLod(uPeeledShadowMap, p.xy, 0.0).r);
141
+ coarse *= directionalVisibility(p.z, coarseCompare, textureLod(uSunShadows, vec3(p.xy, ${SUN_PEELED_LAYER}.0), 0.0).r);
134
142
  }
135
143
  float strength = uShadowStrength * edgeFade * lowElevationFade;
136
144
  if (receiverFade <= 0.0) return mix(1.0, coarse, strength);
@@ -191,11 +199,11 @@ float shadowFactor(float directionalNdl) {
191
199
  * \`shadowMap.ts\` allocates these with one storage level and \`NEAREST\` filtering, so
192
200
  * there is no mip to select and level zero is the only thing \`texture\` could have read.
193
201
  */
194
- float staticDepth = textureLod(uStaticShadowMap, sampleUv, 0.0).r;
195
- float dynamicDepth = textureLod(uDynamicShadowMap, sampleUv, 0.0).r;
202
+ float staticDepth = textureLod(uSunShadows, vec3(sampleUv, ${SUN_STATIC_LAYER}.0), 0.0).r;
203
+ float dynamicDepth = textureLod(uSunShadows, vec3(sampleUv, ${SUN_DYNAMIC_LAYER}.0), 0.0).r;
196
204
  staticLit += directionalVisibility(tapReceiverDepth, compare, staticDepth);
197
205
  if (uPeeledShadowEnabled != 0) {
198
- float peeledDepth = textureLod(uPeeledShadowMap, sampleUv, 0.0).r;
206
+ float peeledDepth = textureLod(uSunShadows, vec3(sampleUv, ${SUN_PEELED_LAYER}.0), 0.0).r;
199
207
  peeledLit += directionalVisibility(tapReceiverDepth, compare, peeledDepth);
200
208
  } else {
201
209
  peeledLit += 1.0;
@@ -215,6 +223,89 @@ float shadowFactor(float directionalNdl) {
215
223
 
216
224
  return mix(1.0, mix(coarse, lit, receiverFade), strength);
217
225
  }
226
+
227
+ /*
228
+ * One of the sun's two glass layers at receiver p: how milky the nearest pane is and how far behind
229
+ * it this receiver stands, the spread that follows (glassShadow.ts's frostRadius, capped), and the
230
+ * tint's level for that spread. Then glassShadow.ts's spreadTint: the outline from taps at the base
231
+ * radius — where the clear pane's patch ends — and the colour from the spread taps, each read coarse,
232
+ * unmixed from the ground around it and weighed by the pane's share of it, so a frosted patch mixes
233
+ * its panes' colours and keeps the light the clear one lets through. What it gives up is a pane lying
234
+ * behind the receiver lending it colour within the spread, which only a receiver between two panes
235
+ * meets. One function for both layers, because two copies were most of the lit shaders' growth.
236
+ */
237
+ vec3 sunGlassLayer(vec3 p, float paneLayer, float tintLayer, float bias, float texel, float uvPerMetre) {
238
+ float tintSize = float(textureSize(uSunGlassTints, 0).x);
239
+ float clarity = textureLod(uSunGlassTints, vec3(p.xy, tintLayer), 0.0).a;
240
+ float behind =
241
+ max(p.z - textureLod(uSunShadows, vec3(p.xy, paneLayer), 0.0).r, 0.0) * uShadowDepthSpan;
242
+ float radius = clamp(
243
+ (1.0 - clarity) * ${FROST_SPREAD.toFixed(6)} * behind * uvPerMetre,
244
+ texel,
245
+ texel * ${FROST_RADIUS_CAP.toFixed(1)}
246
+ );
247
+ float lod = log2(max(radius * tintSize, 1.0));
248
+ float cover = 0.0;
249
+ vec3 colour = vec3(0.0);
250
+ float found = 0.0;
251
+ for (int i = 0; i < ${MAX_SHADOW_FILTER_TAPS}; i++) {
252
+ if (i >= uShadowFilterTaps) break;
253
+ vec2 offset = DIRECTIONAL_PCF_OFFSETS[i];
254
+ vec2 edgeUv = p.xy + offset * texel;
255
+ cover += p.z > textureLod(uSunShadows, vec3(edgeUv, paneLayer), 0.0).r + bias ? 1.0 : 0.0;
256
+ /* The spread taps weigh by the pane's unmixed share rather than a depth test: continuous, so a
257
+ colour crossing between two panes blends rather than stepping through sixteen bands. */
258
+ vec4 pane = glassUnmix(textureLod(uSunGlassTints, vec3(p.xy + offset * radius, tintLayer), lod), clarity);
259
+ colour += pane.rgb * pane.a;
260
+ found += pane.a;
261
+ }
262
+ float taps = float(max(uShadowFilterTaps, 1));
263
+ return mix(vec3(1.0), found > 0.0 ? colour / found : vec3(1.0), cover / taps);
264
+ }
265
+
266
+ /*
267
+ * What the sun's light keeps of itself through glass at this receiver: glassShadow.ts's tap rule
268
+ * and frost spread, over shadowFactor's own taps. A tap counts a pane only when the receiver is
269
+ * farther from the sun than that pane (the glass depth layers), so a surface on the sun's side of a
270
+ * pane, and the pane itself, keep the sun's own colour; the taps average with equal weight, so the
271
+ * spread moves light rather than losing it. Frost widens the taps by how far behind the nearest pane
272
+ * the receiver is, capped, with the tap count unchanged. What it gives up is spread past the edge of
273
+ * an opaque frame's shadow, which this lookup never sees. Faded with the opaque shadow's own fades.
274
+ */
275
+ vec3 sunGlassLookup(float directionalNdl) {
276
+ vec3 p = vLightPos.xyz / vLightPos.w;
277
+ p = p * 0.5 + 0.5;
278
+ /* Map units per metre along the receiver, from derivatives taken first in uniform control flow,
279
+ so a frost spread stated in metres lands the same whatever size of light matrix a consumer built. */
280
+ float uvPerMetre = length(dFdx(p.xy)) / max(length(dFdx(vWorldPos)), 1e-6);
281
+ if (uShadowStrength <= 0.0 || textureSize(uSunGlassTints, 0).x <= 1) return vec3(1.0);
282
+ if (directionalNdl <= 0.0) return vec3(1.0);
283
+ if (p.z > 1.0 || p.x < 0.0 || p.x > 1.0 || p.y < 0.0 || p.y > 1.0) return vec3(1.0);
284
+ vec2 fromCentre = abs(p.xy - 0.5) * 2.0;
285
+ float edgeFade = 1.0 - smoothstep(0.72, 0.98, max(fromCentre.x, fromCentre.y));
286
+ edgeFade *= 1.0 - smoothstep(0.90, 1.0, p.z);
287
+ float shadowSlope = length(uDirectionalDir.xz) / max(uDirectionalDir.y, 0.001);
288
+ float lowElevationFade = 1.0 - smoothstep(
289
+ uShadowMaxSlope * ${DIRECTIONAL_SHADOW_FADE_START.toFixed(2)},
290
+ uShadowMaxSlope,
291
+ shadowSlope
292
+ );
293
+ float strength = uShadowStrength * edgeFade * lowElevationFade;
294
+ if (strength <= 0.0) return vec3(1.0);
295
+
296
+ float bias = 0.14 / uShadowDepthSpan;
297
+ float texel = 1.35 / uShadowMapSize;
298
+ vec3 staticTint = sunGlassLayer(p, ${SUN_GLASS_STATIC_LAYER}.0, 0.0, bias, texel, uvPerMetre);
299
+ vec3 movingTint = sunGlassLayer(p, ${SUN_GLASS_MOVING_LAYER}.0, 1.0, bias, texel, uvPerMetre);
300
+ return mix(vec3(1.0), staticTint * movingTint, strength);
301
+ }
302
+
303
+ /* The way in, asking first whether this build reads glass at all (GLASS_SHADOWS). A constant, so
304
+ the lookup's derivatives are still taken in uniform control flow. */
305
+ vec3 sunGlassTint(float directionalNdl) {
306
+ if (GLASS_SHADOWS) return sunGlassLookup(directionalNdl);
307
+ return vec3(1.0);
308
+ }
218
309
  #endif
219
310
 
220
311
  /**
@@ -29,7 +29,7 @@
29
29
  export const DRIFT_LIGHT_GLSL = /* glsl */ `
30
30
  /** x how much of the summed light is in the frame (0 off), y the radius, z the band, w the scale. */
31
31
  uniform vec4 uDriftLight;
32
- /** xyz the first brick's first sample; w metres between samples, a third of a brick. */
32
+ /** xyz the first sample; w metres between samples — a third of a brick, or negated for a dense volume. */
33
33
  uniform vec4 uDriftLightOrigin;
34
34
  uniform highp usampler3D uDriftLightIndex; // wgsl:share shadow
35
35
  uniform highp sampler3D uDriftLightAtlas;
@@ -41,9 +41,38 @@ float driftLightShare(vec3 world) {
41
41
  return smoothstep(uDriftLight.y - uDriftLight.z, uDriftLight.y, away) * uDriftLight.x;
42
42
  }
43
43
 
44
- /** The summed light arriving on a surface at \`world\` facing \`n\`. */
44
+ /**
45
+ * A sample's light and direction turned into the light on a surface facing \`n\`: Lambert for a
46
+ * single light, a quarter for light arriving from everywhere (see \`bake.ts\`). One statement for
47
+ * both kinds of volume.
48
+ */
49
+ vec3 driftLightFacing(vec4 light, vec4 toward, vec3 n) {
50
+ vec3 arriving = light.rgb / light.a;
51
+ vec3 from = toward.xyz / light.a;
52
+ float facing = max(dot(n, from), 0.0) + (1.0 - min(length(from), 1.0)) * 0.25;
53
+ return arriving * facing;
54
+ }
55
+
56
+ /**
57
+ * The same from a dense volume: one sample a texel, the light in the lower half of y and its
58
+ * direction in the upper. A lookup kept inside the samples never filters across the halves.
59
+ */
60
+ vec3 driftLightDense(vec3 world, vec3 n, float spacing) {
61
+ ivec3 size = textureSize(uDriftLightAtlas, 0);
62
+ vec3 dims = vec3(float(size.x), float(size.y / 2), float(size.z));
63
+ vec3 at = (world + n * (0.5 * spacing) - uDriftLightOrigin.xyz) / spacing;
64
+ if (any(lessThan(at, vec3(0.0))) || any(greaterThan(at, dims - 1.0))) return vec3(0.0);
65
+ vec3 uvw = (at + 0.5) / vec3(dims.x, dims.y * 2.0, dims.z);
66
+ vec4 light = textureLod(uDriftLightAtlas, uvw, 0.0);
67
+ if (light.a < 1e-3) return vec3(0.0);
68
+ vec4 toward = textureLod(uDriftLightAtlas, uvw + vec3(0.0, 0.5, 0.0), 0.0);
69
+ return driftLightFacing(light, toward, n);
70
+ }
71
+
72
+ /** The summed light arriving on a surface at \`world\` facing \`n\`. A negative spacing is dense. */
45
73
  vec3 driftLightIrradiance(vec3 world, vec3 n) {
46
74
  float spacing = uDriftLightOrigin.w;
75
+ if (spacing < 0.0) return driftLightDense(world, n, -spacing);
47
76
  vec3 at = (world + n * (0.5 * spacing) - uDriftLightOrigin.xyz) / (3.0 * spacing);
48
77
  ivec3 cell = ivec3(floor(at));
49
78
  if (any(lessThan(cell, ivec3(0))) || any(greaterThanEqual(cell, textureSize(uDriftLightIndex, 0)))) {
@@ -66,10 +95,6 @@ vec3 driftLightIrradiance(vec3 world, vec3 n) {
66
95
  vec4 light = textureLod(uDriftLightAtlas, (corner + inside) * texel, 0.0);
67
96
  if (light.a < 1e-3) return vec3(0.0);
68
97
  vec4 toward = textureLod(uDriftLightAtlas, (corner + vec3(4.0, 0.0, 0.0) + inside) * texel, 0.0);
69
- vec3 arriving = light.rgb / light.a;
70
- vec3 from = toward.xyz / light.a;
71
- /* Lambert for a single light, a quarter for light arriving from everywhere: see \`bake.ts\`. */
72
- float facing = max(dot(n, from), 0.0) + (1.0 - min(length(from), 1.0)) * 0.25;
73
- return arriving * facing;
98
+ return driftLightFacing(light, toward, n);
74
99
  }
75
100
  `;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * What the lit stage shares between every glass tint it reads: whether it reads any, and
3
+ * `glassShadow.ts`'s `unmixTint`, stated once for the sun's lookup and the lamps'. At depth zero,
4
+ * outside every conditional, so each lookup can call it whichever shadows a permutation compiles.
5
+ */
6
+ export function glassTintGlsl(glassShadows: boolean): string {
7
+ return /* glsl */ `
8
+ /*
9
+ * Whether this build reads glass at all, which every way into the lookups asks first — and as a
10
+ * branch's own condition, never negated: see \`overridableConstants\` in scripts/wgsl/transform.mjs.
11
+ */
12
+ const bool GLASS_SHADOWS = ${glassShadows ? 'true' : 'false'}; // wgsl:override
13
+ /*
14
+ * A coarse level of a glass tint with the open ground's white taken back out, by how milky the pane
15
+ * at the centre is: rgb the pane's colour, a its share of the texel (glassShadow.ts's unmixTint).
16
+ * A clear centre is never read coarse, so it is returned as it stands.
17
+ */
18
+ vec4 glassUnmix(vec4 mip, float centreClarity) {
19
+ if (centreClarity >= 1.0) return vec4(mip.rgb, 1.0);
20
+ float share = clamp((1.0 - mip.a) / (1.0 - centreClarity), 0.0, 1.0);
21
+ if (share <= 0.0) return vec4(1.0, 1.0, 1.0, 0.0);
22
+ return vec4(clamp((mip.rgb - vec3(1.0 - share)) / share, 0.0, 1.0), share);
23
+ }
24
+ `;
25
+ }
@@ -7,11 +7,13 @@ import { preambleGlsl } from './preamble.ts';
7
7
  import { LOBES_GLSL } from './lobes.ts';
8
8
  import { POINTSHADOW_GLSL } from './pointShadow.ts';
9
9
  import { DIRECTIONALSHADOW_GLSL } from './directionalShadow.ts';
10
+ import { glassTintGlsl } from './glassTint.ts';
10
11
  import { MORPH_GLSL } from '../morph.ts';
11
12
  import { SKINNING_GLSL } from '../skinning.ts';
12
13
  import { SURFACE_GLSL } from './surface.ts';
13
14
  import { MAIN_GLSL } from './main.ts';
14
15
  import { DRIFT_LIGHT_GLSL } from './driftLight.ts';
16
+ import { SURFACE_EFFECTS_GLSL } from './surfaceEffects.ts';
15
17
  import { CHANNEL_ATTRIBUTE, CHANNEL_BEND } from '../vertexChannel.ts';
16
18
  import { FULL_LIGHT_BUDGET, type LightBudget } from '../../uniformVectorBudget.ts';
17
19
 
@@ -27,7 +29,7 @@ layout(location = 1) in vec3 aNormal;
27
29
  layout(location = 2) in vec3 aColor;
28
30
  layout(location = 3) in float aEmissive;
29
31
  layout(location = 4) in float aSpecular;
30
- layout(location = 5) in vec2 aUv;
32
+ layout(location = 5) in vec3 aUv;
31
33
  layout(location = 6) in vec3 aEmissiveColor;
32
34
  layout(location = 7) in float aRoughness;
33
35
  layout(location = 8) in float aGrain;
@@ -145,7 +147,7 @@ out vec3 vWorldPos;
145
147
  out float vEmissive;
146
148
  out float vSpecular;
147
149
  out vec4 vLightPos;
148
- out vec2 vUv;
150
+ out vec3 vUv;
149
151
  out vec3 vEmissiveColor;
150
152
  out float vRoughness;
151
153
  out float vGrain;
@@ -242,7 +244,7 @@ void main() {
242
244
  vColor = aColor * tint;
243
245
  vEmissive = aEmissive;
244
246
  vSpecular = aSpecular;
245
- vUv = aUv * uUvScale;
247
+ vUv = vec3(aUv.xy * uUvScale, aUv.z);
246
248
  vEmissiveColor = aEmissiveColor;
247
249
  vRoughness = aRoughness;
248
250
  vGrain = aGrain;
@@ -364,6 +366,19 @@ export interface FlatShaderOptions {
364
366
  * for its instructions not to be there.
365
367
  */
366
368
  readonly nightEmissive: boolean;
369
+ /**
370
+ * Whether this build reads glass in its shadows at all: `glassShadows` other than `'off'`. True
371
+ * when absent, which is what the generated WGSL is built with.
372
+ *
373
+ * **Not a permutation axis, and the payload is why.** Every lit permutation carries the glass
374
+ * lookups, and a second copy of each without them would be most of the generated file again. So
375
+ * it is one switch, `GLASS_SHADOWS`, that every way into the lookups branches on first: written
376
+ * into this source for WebGL2, and a pipeline-overridable constant on the generated WGSL, which
377
+ * the device compiles away as it would under `#if`. That matters because the lookups returning
378
+ * at their first line still cost the lit pass its registers — 0.42 ms at 720p on WebGL2 on the
379
+ * courtyard at night, measured, and nothing once compiled out.
380
+ */
381
+ readonly glassShadows?: boolean;
367
382
  /**
368
383
  * How many point lights this build declares room for. `MAX_POINT_LIGHTS` when absent.
369
384
  *
@@ -466,6 +481,9 @@ export function flatFrag(options: FlatShaderOptions): string {
466
481
  * is at depth zero, and it is still declared before `pointShadow` uses it.
467
482
  */
468
483
  OCTAHEDRAL_GLSL,
484
+ /* Depth zero as well: both glass lookups, sun and lamps, call it, and every permutation
485
+ declares its switch, which the pipelines set whether the permutation reads it or not. */
486
+ glassTintGlsl(options.glassShadows ?? true),
469
487
  LOBES_GLSL,
470
488
  POINTSHADOW_GLSL,
471
489
  DIRECTIONALSHADOW_GLSL,
@@ -494,6 +512,7 @@ export function flatFrag(options: FlatShaderOptions): string {
494
512
  /* Unconditional for the same reason, and called only where a cutoff was asked for. */
495
513
  CUTOUT_COVERAGE_GLSL,
496
514
  DRIFT_LIGHT_GLSL,
515
+ SURFACE_EFFECTS_GLSL,
497
516
  MAIN_GLSL,
498
517
  ].join('\n'),
499
518
  {