@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
@@ -7,7 +7,7 @@
7
7
 
8
8
  export const TEXT_FRAG_WGSL = "struct Uniforms {\n uColor: vec3<f32>,\n uGlow: f32,\n uAlpha: f32,\n}\n\nvar<private> vNormal_1: vec3<f32>;\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\nvar<private> vChar_1: f32;\nvar<private> fragColor: vec4<f32>;\nvar<private> vDepth_1: f32;\n\nfn main_1() {\n var key: vec3<f32>;\n var lambert: f32;\n var lit: vec3<f32>;\n var emissive: vec3<f32>;\n\n key = vec3<f32>(-0.3549141f, 0.7098282f, 0.6084241f);\n let _e19 = vNormal_1;\n let _e21 = key;\n lambert = (0.55f + (0.45f * max(dot(normalize(_e19), _e21), 0f)));\n let _e27 = unnamed.uColor;\n let _e28 = lambert;\n lit = (_e27 * _e28);\n let _e31 = unnamed.uColor;\n let _e33 = unnamed.uGlow;\n let _e35 = vChar_1;\n emissive = ((_e31 * _e33) * (0.45f + (0.55f * _e35)));\n let _e39 = lit;\n let _e40 = emissive;\n let _e41 = (_e39 + _e40);\n let _e43 = unnamed.uAlpha;\n fragColor = vec4<f32>(_e41.x, _e41.y, _e41.z, _e43);\n return;\n}\n\n@fragment \nfn main(@location(0) vNormal: vec3<f32>, @location(2) vChar: f32, @location(1) vDepth: f32) -> @location(0) vec4<f32> {\n vNormal_1 = vNormal;\n vChar_1 = vChar;\n vDepth_1 = vDepth;\n main_1();\n let _e7 = fragColor;\n return _e7;\n}\n";
9
9
 
10
- export const TEXT_VERT_WGSL = "struct Uniforms {\n uViewport: vec2<f32>,\n uOrigin: vec2<f32>,\n uCellSize: f32,\n uDepth: f32,\n uReveal: f32,\n uCharCount: f32,\n uCharOffset: f32,\n uSpin: f32,\n uPunch: f32,\n uBob: f32,\n uTime: f32,\n uClipCorrection: mat4x4<f32>,\n}\n\nstruct gl_PerVertex {\n @builtin(position) gl_Position: vec4<f32>,\n gl_PointSize: f32,\n}\n\nstruct VertexOutput {\n @builtin(position) gl_Position: vec4<f32>,\n @location(0) member: vec3<f32>,\n @location(1) member_1: f32,\n @location(2) member_2: f32,\n}\n\n@group(0) @binding(0) \nvar<uniform> unnamed: Uniforms;\nvar<private> aCharIndex_1: f32;\nvar<private> aCorner_1: vec3<f32>;\nvar<private> aCell_1: vec2<f32>;\nvar<private> unnamed_1: gl_PerVertex = gl_PerVertex(vec4<f32>(0f, 0f, 0f, 1f), 1f);\nvar<private> aNormal_1: vec3<f32>;\nvar<private> vNormal: vec3<f32>;\nvar<private> vDepth: f32;\nvar<private> vChar: f32;\n\nfn rot_u0028_f1_u003b(a: ptr<function, f32>) -> mat2x2<f32> {\n var s: f32;\n var c: f32;\n\n let _e40 = (*a);\n s = sin(_e40);\n let _e42 = (*a);\n c = cos(_e42);\n let _e44 = c;\n let _e45 = s;\n let _e47 = s;\n let _e48 = c;\n return mat2x2<f32>(vec2<f32>(_e44, -(_e45)), vec2<f32>(_e47, _e48));\n}\n\nfn settle_u0028_f1_u003b(t: ptr<function, f32>) -> f32 {\n var d: f32;\n\n let _e39 = (*t);\n if (_e39 <= 0f) {\n return 0f;\n }\n let _e41 = (*t);\n if (_e41 >= 1f) {\n return 1f;\n }\n let _e43 = (*t);\n d = (1f - _e43);\n let _e45 = d;\n let _e46 = d;\n let _e48 = (*t);\n return (1f - ((_e45 * _e46) * cos((_e48 * 12f))));\n}\n\nfn main_1() {\n var span: f32;\n var start: f32;\n var local: f32;\n var eased: f32;\n var param: f32;\n var spin: f32;\n var rise: f32;\n var punch: f32;\n var local3_: vec3<f32>;\n var param_1: f32;\n var cell: vec2<f32>;\n var bob: f32;\n var screen: vec2<f32>;\n var view: vec3<f32>;\n var invDepth: f32;\n var ndc: vec2<f32>;\n var depth: f32;\n var n: vec3<f32>;\n var param_2: f32;\n\n let _e57 = unnamed.uCharCount;\n span = max(_e57, 1f);\n let _e59 = aCharIndex_1;\n let _e61 = unnamed.uCharOffset;\n let _e63 = span;\n start = (((_e59 + _e61) / _e63) * 0.55f);\n let _e67 = unnamed.uReveal;\n let _e68 = start;\n let _e70 = start;\n local = clamp(((_e67 - _e68) / max(0.45f, (1f - _e70))), 0f, 1f);\n let _e75 = local;\n param = _e75;\n let _e76 = settle_u0028_f1_u003b((&param));\n eased = _e76;\n let _e78 = unnamed.uSpin;\n let _e79 = eased;\n spin = (_e78 * (1f - _e79));\n let _e82 = eased;\n let _e85 = unnamed.uCellSize;\n rise = (((1f - _e82) * _e85) * 6f);\n let _e89 = unnamed.uPunch;\n let _e90 = eased;\n punch = (1f + (_e89 * (1f - abs(((_e90 * 2f) - 1f)))));\n let _e97 = aCorner_1;\n let _e99 = unnamed.uCellSize;\n let _e102 = punch;\n local3_ = (((_e97 * _e99) * 0.5f) * _e102);\n let _e104 = spin;\n param_1 = _e104;\n let _e105 = rot_u0028_f1_u003b((&param_1));\n let _e106 = local3_;\n let _e108 = (_e105 * _e106.yz);\n let _e109 = local3_;\n local3_ = vec3<f32>(_e109.x, _e108.x, _e108.y);\n let _e114 = aCell_1;\n let _e116 = unnamed.uCellSize;\n cell = (_e114 * _e116);\n let _e119 = unnamed.uTime;\n let _e121 = aCharIndex_1;\n let _e126 = unnamed.uBob;\n bob = (sin(((_e119 * 3.1f) + (_e121 * 0.7f))) * _e126);\n let _e129 = unnamed.uOrigin;\n let _e131 = cell[0u];\n let _e133 = cell[1u];\n let _e137 = rise;\n let _e138 = bob;\n screen = ((_e129 + vec2<f32>(_e131, -(_e133))) + vec2<f32>(0f, (_e137 - _e138)));\n let _e142 = screen;\n let _e143 = local3_;\n let _e145 = (_e142 + _e143.xy);\n let _e147 = unnamed.uDepth;\n let _e150 = local3_[2u];\n view = vec3<f32>(_e145.x, _e145.y, (-(_e147) + _e150));\n let _e156 = unnamed.uDepth;\n let _e158 = view[2u];\n invDepth = (_e156 / max(0.001f, -(_e158)));\n let _e162 = view;\n let _e164 = invDepth;\n let _e167 = unnamed.uViewport;\n ndc = ((((_e162.xy * _e164) / _e167) * 2f) - vec2(1f));\n let _e173 = local3_[2u];\n let _e176 = unnamed.uCellSize;\n depth = (clamp((-(_e173) / max(1f, (_e176 * 2f))), -1f, 1f) * 0.4f);\n let _e183 = unnamed.uClipCorrection;\n let _e185 = ndc[0u];\n let _e187 = ndc[1u];\n let _e189 = depth;\n unnamed_1.gl_Position = (_e183 * vec4<f32>(_e185, -(_e187), _e189, 1f));\n let _e193 = aNormal_1;\n n = _e193;\n let _e194 = spin;\n param_2 = _e194;\n let _e195 = rot_u0028_f1_u003b((&param_2));\n let _e196 = n;\n let _e198 = (_e195 * _e196.yz);\n let _e199 = n;\n n = vec3<f32>(_e199.x, _e198.x, _e198.y);\n let _e204 = n;\n vNormal = _e204;\n let _e206 = local3_[2u];\n vDepth = _e206;\n let _e207 = eased;\n vChar = _e207;\n return;\n}\n\n@vertex \nfn main(@location(3) aCharIndex: f32, @location(0) aCorner: vec3<f32>, @location(2) aCell: vec2<f32>, @location(1) aNormal: vec3<f32>) -> VertexOutput {\n aCharIndex_1 = aCharIndex;\n aCorner_1 = aCorner;\n aCell_1 = aCell;\n aNormal_1 = aNormal;\n main_1();\n let _e14 = unnamed_1.gl_Position.y;\n unnamed_1.gl_Position.y = -(_e14);\n let _e16 = unnamed_1.gl_Position;\n let _e17 = vNormal;\n let _e18 = vDepth;\n let _e19 = vChar;\n return VertexOutput(_e16, _e17, _e18, _e19);\n}\n";
10
+ export const TEXT_VERT_WGSL = "struct Uniforms {\n uViewport: vec2<f32>,\n uOrigin: vec2<f32>,\n uCellSize: f32,\n uDepth: f32,\n uReveal: f32,\n uCharCount: f32,\n uCharOffset: f32,\n uSpin: f32,\n uPunch: f32,\n uBob: f32,\n uTime: f32,\n uClipCorrection: mat4x4<f32>,\n}\n\nstruct gl_PerVertex {\n @builtin(position) gl_Position: vec4<f32>,\n gl_PointSize: f32,\n}\n\nstruct VertexOutput {\n @builtin(position) gl_Position: vec4<f32>,\n @location(0) member: vec3<f32>,\n @location(1) member_1: f32,\n @location(2) member_2: f32,\n}\n\n@group(0) @binding(0) \nvar<uniform> unnamed: Uniforms;\nvar<private> aCharIndex_1: f32;\nvar<private> aCorner_1: vec3<f32>;\nvar<private> aCell_1: vec2<f32>;\nvar<private> unnamed_1: gl_PerVertex = gl_PerVertex(vec4<f32>(0f, 0f, 0f, 1f), 1f);\nvar<private> aNormal_1: vec3<f32>;\nvar<private> vNormal: vec3<f32>;\nvar<private> vDepth: f32;\nvar<private> vChar: f32;\n\nfn rot_u0028_f1_u003b(a: ptr<function, f32>) -> mat2x2<f32> {\n var s: f32;\n var c: f32;\n\n let _e40 = (*a);\n s = sin(_e40);\n let _e42 = (*a);\n c = cos(_e42);\n let _e44 = c;\n let _e45 = s;\n let _e47 = s;\n let _e48 = c;\n return mat2x2<f32>(vec2<f32>(_e44, -(_e45)), vec2<f32>(_e47, _e48));\n}\n\nfn settle_u0028_f1_u003b(t: ptr<function, f32>) -> f32 {\n var d: f32;\n\n let _e39 = (*t);\n if (_e39 <= 0f) {\n return 0f;\n }\n let _e41 = (*t);\n if (_e41 >= 1f) {\n return 1f;\n }\n let _e43 = (*t);\n d = (1f - _e43);\n let _e45 = d;\n let _e46 = d;\n let _e48 = (*t);\n return (1f - ((_e45 * _e46) * cos((_e48 * 12f))));\n}\n\nfn main_1() {\n var span: f32;\n var start: f32;\n var local: f32;\n var eased: f32;\n var param: f32;\n var spin: f32;\n var rise: f32;\n var punch: f32;\n var local3_: vec3<f32>;\n var param_1: f32;\n var cell: vec2<f32>;\n var bob: f32;\n var centre: vec2<f32>;\n var invDepth: f32;\n var screen: vec2<f32>;\n var ndc: vec2<f32>;\n var depth: f32;\n var n: vec3<f32>;\n var param_2: f32;\n\n let _e57 = unnamed.uCharCount;\n span = max(_e57, 1f);\n let _e59 = aCharIndex_1;\n let _e61 = unnamed.uCharOffset;\n let _e63 = span;\n start = (((_e59 + _e61) / _e63) * 0.55f);\n let _e67 = unnamed.uReveal;\n let _e68 = start;\n let _e70 = start;\n local = clamp(((_e67 - _e68) / max(0.45f, (1f - _e70))), 0f, 1f);\n let _e75 = local;\n param = _e75;\n let _e76 = settle_u0028_f1_u003b((&param));\n eased = _e76;\n let _e78 = unnamed.uSpin;\n let _e79 = eased;\n spin = (_e78 * (1f - _e79));\n let _e82 = eased;\n let _e85 = unnamed.uCellSize;\n rise = (((1f - _e82) * _e85) * 6f);\n let _e89 = unnamed.uPunch;\n let _e90 = eased;\n punch = (1f + (_e89 * (1f - abs(((_e90 * 2f) - 1f)))));\n let _e97 = aCorner_1;\n let _e99 = unnamed.uCellSize;\n let _e102 = punch;\n local3_ = (((_e97 * _e99) * 0.5f) * _e102);\n let _e104 = spin;\n param_1 = _e104;\n let _e105 = rot_u0028_f1_u003b((&param_1));\n let _e106 = local3_;\n let _e108 = (_e105 * _e106.yz);\n let _e109 = local3_;\n local3_ = vec3<f32>(_e109.x, _e108.x, _e108.y);\n let _e114 = aCell_1;\n let _e116 = unnamed.uCellSize;\n cell = (_e114 * _e116);\n let _e119 = unnamed.uTime;\n let _e121 = aCharIndex_1;\n let _e126 = unnamed.uBob;\n bob = (sin(((_e119 * 3.1f) + (_e121 * 0.7f))) * _e126);\n let _e129 = unnamed.uOrigin;\n let _e131 = cell[0u];\n let _e133 = cell[1u];\n let _e137 = rise;\n let _e138 = bob;\n centre = ((_e129 + vec2<f32>(_e131, -(_e133))) + vec2<f32>(0f, (_e137 - _e138)));\n let _e143 = unnamed.uDepth;\n let _e145 = unnamed.uDepth;\n let _e147 = local3_[2u];\n invDepth = (_e143 / max(0.001f, (_e145 - _e147)));\n let _e151 = centre;\n let _e152 = local3_;\n let _e154 = invDepth;\n screen = (_e151 + (_e152.xy * _e154));\n let _e157 = screen;\n let _e159 = unnamed.uViewport;\n ndc = (((_e157 / _e159) * 2f) - vec2(1f));\n let _e165 = local3_[2u];\n let _e168 = unnamed.uCellSize;\n depth = (clamp((-(_e165) / max(1f, (_e168 * 2f))), -1f, 1f) * 0.4f);\n let _e175 = unnamed.uClipCorrection;\n let _e177 = ndc[0u];\n let _e179 = ndc[1u];\n let _e181 = depth;\n unnamed_1.gl_Position = (_e175 * vec4<f32>(_e177, -(_e179), _e181, 1f));\n let _e185 = aNormal_1;\n n = _e185;\n let _e186 = spin;\n param_2 = _e186;\n let _e187 = rot_u0028_f1_u003b((&param_2));\n let _e188 = n;\n let _e190 = (_e187 * _e188.yz);\n let _e191 = n;\n n = vec3<f32>(_e191.x, _e190.x, _e190.y);\n let _e196 = n;\n vNormal = _e196;\n let _e198 = local3_[2u];\n vDepth = _e198;\n let _e199 = eased;\n vChar = _e199;\n return;\n}\n\n@vertex \nfn main(@location(3) aCharIndex: f32, @location(0) aCorner: vec3<f32>, @location(2) aCell: vec2<f32>, @location(1) aNormal: vec3<f32>) -> VertexOutput {\n aCharIndex_1 = aCharIndex;\n aCorner_1 = aCorner;\n aCell_1 = aCell;\n aNormal_1 = aNormal;\n main_1();\n let _e14 = unnamed_1.gl_Position.y;\n unnamed_1.gl_Position.y = -(_e14);\n let _e16 = unnamed_1.gl_Position;\n let _e17 = vNormal;\n let _e18 = vDepth;\n let _e19 = vChar;\n return VertexOutput(_e16, _e17, _e18, _e19);\n}\n";
11
11
 
12
12
  /**
13
13
  * What the transform assigned, so the renderer binds the same numbers.
@@ -14,8 +14,34 @@
14
14
  * filtering `driftSampler`; `origin` is the field's first sample and, in `w`, the spacing.
15
15
  */
16
16
  export const DRIFT_LIGHT_WGSL = /* wgsl */ `
17
+ fn driftLightFacing(light: vec4<f32>, toward: vec4<f32>, n: vec3<f32>) -> vec3<f32> {
18
+ let arriving = light.rgb / light.a;
19
+ let towardLight = toward.xyz / light.a;
20
+ let facing = max(dot(n, towardLight), 0.0) + (1.0 - min(length(towardLight), 1.0)) * 0.25;
21
+ return arriving * facing;
22
+ }
23
+
24
+ fn driftLightDense(world: vec3<f32>, n: vec3<f32>, origin: vec4<f32>, spacing: f32) -> vec3<f32> {
25
+ let size = vec3<i32>(textureDimensions(driftAtlas, 0));
26
+ let dims = vec3<f32>(f32(size.x), f32(size.y / 2), f32(size.z));
27
+ let at = (world + n * (0.5 * spacing) - origin.xyz) / spacing;
28
+ if (any(at < vec3<f32>(0.0)) || any(at > dims - 1.0)) {
29
+ return vec3<f32>(0.0);
30
+ }
31
+ let uvw = (at + 0.5) / vec3<f32>(dims.x, dims.y * 2.0, dims.z);
32
+ let light = textureSampleLevel(driftAtlas, driftSampler, uvw, 0.0);
33
+ if (light.a < 1e-3) {
34
+ return vec3<f32>(0.0);
35
+ }
36
+ let toward = textureSampleLevel(driftAtlas, driftSampler, uvw + vec3<f32>(0.0, 0.5, 0.0), 0.0);
37
+ return driftLightFacing(light, toward, n);
38
+ }
39
+
17
40
  fn driftLightIrradiance(world: vec3<f32>, n: vec3<f32>, origin: vec4<f32>) -> vec3<f32> {
18
41
  let spacing = origin.w;
42
+ if (spacing < 0.0) {
43
+ return driftLightDense(world, n, origin, -spacing);
44
+ }
19
45
  let at = (world + n * (0.5 * spacing) - origin.xyz) / (3.0 * spacing);
20
46
  let cell = vec3<i32>(floor(at));
21
47
  if (any(cell < vec3<i32>(0)) || any(cell >= vec3<i32>(textureDimensions(driftIndex, 0)))) {
@@ -41,9 +67,6 @@ fn driftLightIrradiance(world: vec3<f32>, n: vec3<f32>, origin: vec4<f32>) -> ve
41
67
  return vec3<f32>(0.0);
42
68
  }
43
69
  let toward = textureSampleLevel(driftAtlas, driftSampler, (corner + vec3<f32>(4.0, 0.0, 0.0) + inside) * texel, 0.0);
44
- let arriving = light.rgb / light.a;
45
- let towardLight = toward.xyz / light.a;
46
- let facing = max(dot(n, towardLight), 0.0) + (1.0 - min(length(towardLight), 1.0)) * 0.25;
47
- return arriving * facing;
70
+ return driftLightFacing(light, toward, n);
48
71
  }
49
72
  `;
@@ -1,3 +1,4 @@
1
+ import { SUN_DYNAMIC_LAYER, SUN_PEELED_LAYER, SUN_STATIC_LAYER } from '../shadowMap.ts';
1
2
  import { glslIsFarDepth, glslSceneDepthToNdc } from '../depthConvention.ts';
2
3
  import { MAX_GLOBAL_MEDIUM_STEPS } from '../globalMedium.ts';
3
4
 
@@ -79,9 +80,8 @@ uniform int uSteps;
79
80
  /** How much of the medium the sun's own shadow map removes, 0 to 1. At 0 nothing is sampled. */
80
81
  uniform float uSunShadow;
81
82
  uniform mat4 uLightViewProj;
82
- uniform sampler2D uStaticShadowMap;
83
- uniform sampler2D uPeeledShadowMap;
84
- uniform sampler2D uDynamicShadowMap;
83
+ /* The sun's static, moving and peeled maps, as layers of one array: see shadowMap.ts. */
84
+ uniform highp sampler2DArray uSunShadows;
85
85
  uniform int uPeeledShadowEnabled;
86
86
 
87
87
  out vec4 fragColor;
@@ -150,11 +150,11 @@ float sunReach(vec3 worldPos) {
150
150
  if (edgeFade <= 0.0) return 1.0;
151
151
 
152
152
  float compare = p.z - SHADOW_BIAS;
153
- float blocked = occlusion(textureLod(uStaticShadowMap, p.xy, 0.0).r, compare);
153
+ float blocked = occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_STATIC_LAYER}.0), 0.0).r, compare);
154
154
  if (uPeeledShadowEnabled != 0) {
155
- blocked = max(blocked, occlusion(textureLod(uPeeledShadowMap, p.xy, 0.0).r, compare));
155
+ blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_PEELED_LAYER}.0), 0.0).r, compare));
156
156
  }
157
- blocked = max(blocked, occlusion(textureLod(uDynamicShadowMap, p.xy, 0.0).r, compare));
157
+ blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_DYNAMIC_LAYER}.0), 0.0).r, compare));
158
158
  return mix(1.0, 1.0 - blocked, uSunShadow * edgeFade);
159
159
  }
160
160
 
@@ -82,6 +82,28 @@ fn oitResolved(accum: vec4<f32>, reveal: f32) -> vec4<f32> {
82
82
  }
83
83
  `;
84
84
 
85
+ /**
86
+ * Glass over its own shading, as the forward path draws it: `gpudriven/lit.ts`'s `glassShade`,
87
+ * which `scripts/gpu-parity.mjs` holds this to. Schlick at 0.04 with the angle unsigned — a pane
88
+ * passes the same light seen from either side — and floored at the forward path's grazing 0.05.
89
+ */
90
+ const GLASS_SHADE_WGSL = /* wgsl */ `
91
+ fn glassShade(
92
+ own: vec3<f32>,
93
+ seen: vec3<f32>,
94
+ transmission: f32,
95
+ frost: f32,
96
+ tint: vec3<f32>,
97
+ cosView: f32,
98
+ sunGlow: vec3<f32>,
99
+ ) -> vec3<f32> {
100
+ let c = clamp(abs(cosView), 0.05, 1.0);
101
+ let fresnel = 0.04 + 0.96 * pow(1.0 - c, 5.0);
102
+ let shown = transmission * (1.0 - fresnel);
103
+ return own + (seen * tint - own) * shown + sunGlow * tint * (frost * transmission);
104
+ }
105
+ `;
106
+
85
107
  export const BLEND_RASTER_WGSL = /* wgsl */ `
86
108
  struct BlendVarying {
87
109
  @builtin(position) position: vec4<f32>,
@@ -108,6 +130,12 @@ ${FRAME_BLOCK_WGSL}
108
130
  @group(0) @binding(9) var environmentMap: texture_2d_array<f32>;
109
131
  @group(0) @binding(10) var environmentSampler: sampler;
110
132
  ${decodeResourcesWgsl({ group: 0, latents: 11, clampSampler: 12, repeatSampler: 13, nodes: 14, weights: 15 })}
133
+ /**
134
+ * What the opaque half drew, with a mip chain on a frame whose scene holds glass: a pane shows it,
135
+ * a frosted one a coarser level of it. Read only by a material whose transmission is not zero.
136
+ */
137
+ @group(0) @binding(16) var opaqueColour: texture_2d<f32>;
138
+ @group(0) @binding(17) var opaqueSampler: sampler;
111
139
  fn decodeLatentSize() -> f32 {
112
140
  return frame.size.w;
113
141
  }
@@ -126,6 +154,7 @@ ${MESH_TRANSFORM_WGSL}
126
154
  ${SHADE_LIGHTING_WGSL}
127
155
  ${FOG_WGSL}
128
156
  ${OIT_WGSL}
157
+ ${GLASS_SHADE_WGSL}
129
158
 
130
159
  const NO_PROGRAM_HERE: u32 = ${0xffffffff}u;
131
160
 
@@ -241,7 +270,25 @@ fn blendFrag(in: BlendVarying) -> BlendTargets {
241
270
  * distance — which is the whole reason this pipeline gained a fog.
242
271
  */
243
272
  let toward = distance(in.world, frame.eye.xyz);
244
- let colour = mix(litColour(surface, room), mediumColour(), mediumFog(toward, in.world.y));
273
+ let fog = mediumFog(toward, in.world.y);
274
+ var colour = mix(litColour(surface, room), mediumColour(), fog);
275
+ /*
276
+ * **Glass shows what is behind it**, as the forward path's glass branch does: the opaque half's
277
+ * picture at this pixel, at the level frost picks, two short of the chain's end so a fully frosted
278
+ * pane keeps the large light and dark behind it. The sun glows through from the pane's far side,
279
+ * after the haze as the forward path adds it. A pane is seen from both sides, so its facing is
280
+ * the side toward the eye.
281
+ */
282
+ let transmission = entry.extra.y;
283
+ if (transmission > 0.0) {
284
+ let size = vec2<f32>(textureDimensions(opaqueColour, 0));
285
+ let levels = max(floor(log2(max(size.x, size.y))) - 2.0, 0.0);
286
+ let seen = textureSampleLevel(opaqueColour, opaqueSampler, in.position.xy / size, entry.extra.z * levels).xyz;
287
+ let cosView = dot(surface.normal, toEye);
288
+ let facing = select(surface.normal, -surface.normal, cosView < 0.0);
289
+ let sunGlow = frame.lightColour.xyz * max(-dot(facing, frame.lightDir.xyz), 0.0) * (1.0 - fog);
290
+ colour = glassShade(colour, seen, transmission, entry.extra.z, entry.glassTint.xyz, cosView, sunGlow);
291
+ }
245
292
 
246
293
  /*
247
294
  * **The distance to the eye, not the clip-space depth**, because that is what oitWeight's falloff
@@ -255,6 +302,20 @@ fn blendFrag(in: BlendVarying) -> BlendTargets {
255
302
  out.reveal = vec4<f32>(alpha, 0.0, 0.0, alpha);
256
303
  return out;
257
304
  }
305
+
306
+ /*
307
+ * **What a pane lets through, drawn from the sun into the tint map**: \`blendVert\` again, handed
308
+ * the light's raster matrix and the glass list, and this for the colour — \`glassShadow.ts\`'s
309
+ * paneTexel, the forward path's GLASS_TINT_FRAG in this language. Written against a white target
310
+ * with a multiplying blend and no depth, so every pane on a ray counts in any order.
311
+ */
312
+ @fragment
313
+ fn glassTintFrag(in: BlendVarying) -> @location(0) vec4<f32> {
314
+ let entry = materials[min(in.material, ${MATERIAL_SLOTS - 1}u)];
315
+ let c = clamp(abs(dot(normalize(in.normal), frame.lightDir.xyz)), 0.05, 1.0);
316
+ let passes = entry.extra.y * (1.0 - (0.04 + 0.96 * pow(1.0 - c, 5.0)));
317
+ return vec4<f32>(passes * entry.glassTint.xyz, 1.0 - entry.extra.z);
318
+ }
258
319
  `;
259
320
 
260
321
  /**
@@ -341,3 +402,29 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
341
402
  results[out + 3u] = resolved.z;
342
403
  }
343
404
  `;
405
+
406
+ /**
407
+ * `glassShade` alone, as a dispatch, so it can be checked against `gpudriven/lit.ts`.
408
+ *
409
+ * Sixteen floats a case — own, seen, transmission, frost, tint, the view cosine, the glow, one
410
+ * spare — and four out, the colour and one spare.
411
+ */
412
+ export const GLASS_SHADE_PARITY_WGSL = /* wgsl */ `
413
+ @group(0) @binding(0) var<storage, read> cases: array<f32>;
414
+ @group(0) @binding(1) var<storage, read_write> results: array<f32>;
415
+ ${GLASS_SHADE_WGSL}
416
+ @compute @workgroup_size(64)
417
+ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
418
+ if (id.x * 16u + 15u >= arrayLength(&cases)) { return; }
419
+ let at = id.x * 16u;
420
+ let own = vec3<f32>(cases[at], cases[at + 1u], cases[at + 2u]);
421
+ let seen = vec3<f32>(cases[at + 3u], cases[at + 4u], cases[at + 5u]);
422
+ let tint = vec3<f32>(cases[at + 8u], cases[at + 9u], cases[at + 10u]);
423
+ let glow = vec3<f32>(cases[at + 12u], cases[at + 13u], cases[at + 14u]);
424
+ let shaded = glassShade(own, seen, cases[at + 6u], cases[at + 7u], tint, cases[at + 11u], glow);
425
+ let out = id.x * 4u;
426
+ results[out] = shaded.x;
427
+ results[out + 1u] = shaded.y;
428
+ results[out + 2u] = shaded.z;
429
+ }
430
+ `;
@@ -104,9 +104,11 @@ struct Params {
104
104
  eyeZ: f32,
105
105
  /** Non-zero to select the blended clusters, zero to select everything else. */
106
106
  wantBlend: f32,
107
+ /** Non-zero to keep, of those, only glass: what the light's glass pass draws. */
108
+ wantGlass: f32,
107
109
  };
108
110
  ${MATERIAL_TABLE_WGSL}
109
- @group(0) @binding(0) var<storage, read> params: array<f32, 7>;
111
+ @group(0) @binding(0) var<storage, read> params: array<f32, 8>;
110
112
  /** Six floats a cluster: centre, radius, own error, parent error. */
111
113
  @group(0) @binding(1) var<storage, read> clusters: array<f32>;
112
114
  @group(0) @binding(2) var<storage, read_write> selected: array<u32>;
@@ -139,11 +141,18 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
139
141
  * neither is drawn twice and neither is dropped. The flag is read through a uniform by an index
140
142
  * that is the same for every cluster of a mesh, so the branch is as coherent as this shader gets.
141
143
  */
142
- let blended = materials[min(materialOf[i], ${MATERIAL_SLOTS - 1}u)].orm.w != 0.0;
144
+ let material = materials[min(materialOf[i], ${MATERIAL_SLOTS - 1}u)];
145
+ let blended = material.orm.w != 0.0;
143
146
  if (blended != (params[6] != 0.0)) {
144
147
  selected[i] = 0u;
145
148
  return;
146
149
  }
150
+ /* The light's glass pass: a blended surface that is not glass casts nothing, as on the forward
151
+ path, so only a material letting light through is kept. */
152
+ if (params[7] != 0.0 && material.extra.y <= 0.0) {
153
+ selected[i] = 0u;
154
+ return;
155
+ }
147
156
  let screenHeight = params[0];
148
157
  let fovY = params[1];
149
158
  let threshold = params[2];
@@ -38,8 +38,10 @@ struct Material {
38
38
  maps: vec4<f32>,
39
39
  /** Roughness scale, metallic scale, the alpha cutoff, and non-zero where this one blends. */
40
40
  orm: vec4<f32>,
41
- /** The blended opacity, and three spare. */
41
+ /** The blended opacity, the glass's transmission and frost, and one spare. */
42
42
  extra: vec4<f32>,
43
+ /** The glass's tint, white where the material is not glass, and one spare. */
44
+ glassTint: vec4<f32>,
43
45
  }
44
46
 
45
47
  const NO_PROGRAM: u32 = ${DECODE_NO_PROGRAM}u;
@@ -8,6 +8,7 @@ import { MATERIAL_SLOTS, MATERIAL_TABLE_WGSL } from './materialTable.wgsl.ts';
8
8
  import { MESH_TRANSFORM_WGSL } from './meshTransform.wgsl.ts';
9
9
  import { ENVIRONMENT_WGSL } from './environment.wgsl.ts';
10
10
  import { SHADE_SHADOW_WGSL } from './shadow.wgsl.ts';
11
+ import { SUN_GLASS_WGSL } from './sunGlass.wgsl.ts';
11
12
 
12
13
  /**
13
14
  * Rebuilding a pixel's surface from the triangle it recorded, on the device.
@@ -514,6 +515,14 @@ struct Job {
514
515
  @group(0) @binding(12) var environmentMap: texture_2d_array<f32>;
515
516
  @group(0) @binding(13) var environmentSampler: sampler;
516
517
  ${decodeResourcesWgsl({ group: 0, latents: 14, clampSampler: 15, repeatSampler: 16, nodes: 17, weights: 18 })}
518
+ /*
519
+ * **What the sun keeps through glass: the nearest pane's depth and what the panes let through**,
520
+ * which the pass draws from the sun after its opaque map. Where no material is glass the depth is
521
+ * the opaque map again and the tint a single white texel, which sunGlassAt reads as none.
522
+ */
523
+ @group(0) @binding(19) var glassDepthMap: texture_depth_2d;
524
+ @group(0) @binding(20) var glassTints: texture_2d<f32>;
525
+ @group(0) @binding(21) var glassSampler: sampler;
517
526
 
518
527
  fn decodeLatentSize() -> f32 {
519
528
  return frame.size.w;
@@ -545,6 +554,45 @@ fn shadowDepthAt(u: f32, v: f32) -> f32 {
545
554
  return textureLoad(shadowMap, vec2<i32>(x, y), 0);
546
555
  }
547
556
  ${SHADE_SHADOW_WGSL}
557
+
558
+ /* sunGlass.wgsl.ts's three reads, as the opaque map is read: nearest by integer coordinate. */
559
+ fn glassDepthAt(u: f32, v: f32) -> f32 {
560
+ let size = frame.shadow.y;
561
+ let x = i32(clamp(floor(u * size), 0.0, size - 1.0));
562
+ let y = i32(clamp(floor(v * size), 0.0, size - 1.0));
563
+ return textureLoad(glassDepthMap, vec2<i32>(x, y), 0);
564
+ }
565
+
566
+ fn glassTintTexel(u: f32, v: f32) -> vec4<f32> {
567
+ let size = f32(textureDimensions(glassTints, 0).x);
568
+ let x = i32(clamp(floor(u * size), 0.0, size - 1.0));
569
+ let y = i32(clamp(floor(v * size), 0.0, size - 1.0));
570
+ return textureLoad(glassTints, vec2<i32>(x, y), 0);
571
+ }
572
+
573
+ /* The tint over a spread, from the chain: the level whose texel is the spread's width. */
574
+ fn glassTintAround(u: f32, v: f32, radius: f32) -> vec4<f32> {
575
+ let size = f32(textureDimensions(glassTints, 0).x);
576
+ return textureSampleLevel(glassTints, glassSampler, vec2<f32>(u, v), log2(max(radius * size, 1.0)));
577
+ }
578
+ ${SUN_GLASS_WGSL}
579
+
580
+ /*
581
+ * The sun's colour at this receiver after the panes between it and the sun: white where no glass
582
+ * cast, and faded with the opaque shadow's own strength. The map's scale in metres comes off the
583
+ * light's matrix, which is orthographic: a compute invocation has no derivatives to take it from.
584
+ */
585
+ fn sunGlassAt(lightPos: vec3<f32>) -> vec3<f32> {
586
+ if (textureDimensions(glassTints, 0).x <= 1u || frame.shadow.x <= 0.0) { return vec3<f32>(1.0); }
587
+ let m = frame.lightViewProj;
588
+ var settings: SunGlassSettings;
589
+ settings.mapSize = frame.shadow.y;
590
+ settings.depthSpan = frame.shadow.z;
591
+ settings.uvPerMetre = 0.5 * length(vec3<f32>(m[0][0], m[1][0], m[2][0]));
592
+ settings.taps = frame.shadowLimits.y;
593
+ let tint = sunGlass(lightPos.x * 0.5 + 0.5, lightPos.y * 0.5 + 0.5, lightPos.z, settings);
594
+ return mix(vec3<f32>(1.0), tint, frame.shadow.x);
595
+ }
548
596
  ${ENVIRONMENT_WGSL}
549
597
  ${FOG_WGSL}
550
598
 
@@ -737,7 +785,8 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
737
785
 
738
786
  var room: LitEnvironment;
739
787
  room.lightDir = frame.lightDir.xyz;
740
- room.lightColour = frame.lightColour.xyz;
788
+ /* The sun's colour through whatever glass stands between it and here, as flat/main.ts's is. */
789
+ room.lightColour = frame.lightColour.xyz * sunGlassAt(lightPos);
741
790
  room.sky = frame.sky.xyz;
742
791
  room.ground = frame.ground.xyz;
743
792
  /*
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The sun through glass for the device: `gpudriven/sunGlass.ts`'s `glassTintAt`, term for term, as
3
+ * the text the shading pass and the parity entry point both include.
4
+ *
5
+ * **The reads are the including module's**, as `SHADE_SHADOW_WGSL`'s are: `glassDepthAt(u, v)` the
6
+ * nearest pane's depth, `glassTintTexel(u, v)` the tint at the finest level, and
7
+ * `glassTintAround(u, v, radius)` the tint averaged over a spread of that radius. The shading pass
8
+ * answers the last from the tint's mip chain; the parity entry answers it with the reference's own
9
+ * box average, so everything around the reads is checked as it stands. Every constant is the
10
+ * reference's, interpolated rather than restated.
11
+ */
12
+ import { FROST_RADIUS_CAP, FROST_SPREAD } from '../../glassShadow.ts';
13
+ import {
14
+ SHADOW_DEPTH_BIAS,
15
+ SHADOW_PCF_OFFSETS,
16
+ SHADOW_TEXEL_SCALE,
17
+ } from '../../gpudriven/shadow.ts';
18
+ import { SHADE_SHADOW_WGSL } from './shadow.wgsl.ts';
19
+
20
+ export const SUN_GLASS_WGSL = /* wgsl */ `
21
+ struct SunGlassSettings {
22
+ mapSize: f32,
23
+ depthSpan: f32,
24
+ uvPerMetre: f32,
25
+ taps: f32,
26
+ }
27
+
28
+ /*
29
+ * A coarse texel with the open ground's white taken back out, by how milky the pane at the
30
+ * receiver is: the pane's colour and its share of the texel. glassShadow.ts's unmixTint.
31
+ */
32
+ fn sunGlassUnmix(mip: vec4<f32>, centreClarity: f32) -> vec4<f32> {
33
+ if (centreClarity >= 1.0) { return vec4<f32>(mip.xyz, 1.0); }
34
+ let share = clamp((1.0 - mip.w) / (1.0 - centreClarity), 0.0, 1.0);
35
+ if (share <= 0.0) { return vec4<f32>(1.0, 1.0, 1.0, 0.0); }
36
+ let colour = clamp((mip.xyz - vec3<f32>(1.0 - share)) / share, vec3<f32>(0.0), vec3<f32>(1.0));
37
+ return vec4<f32>(colour, share);
38
+ }
39
+
40
+ /* What the sun keeps through glass at map position (u, v) and light depth "depth". */
41
+ fn sunGlass(u: f32, v: f32, depth: f32, settings: SunGlassSettings) -> vec3<f32> {
42
+ if (u < 0.0 || u > 1.0 || v < 0.0 || v > 1.0) { return vec3<f32>(1.0); }
43
+ let texel = ${SHADOW_TEXEL_SCALE.toFixed(4)} / settings.mapSize;
44
+ let bias = ${SHADOW_DEPTH_BIAS.toFixed(4)} / settings.depthSpan;
45
+ let taps = min(u32(settings.taps), ${SHADOW_PCF_OFFSETS.length}u);
46
+ let clarity = glassTintTexel(u, v).w;
47
+ let behind = max(depth - glassDepthAt(u, v), 0.0) * settings.depthSpan;
48
+ let spread = (1.0 - clarity) * ${FROST_SPREAD.toFixed(6)} * behind * settings.uvPerMetre;
49
+ let radius = min(max(texel, spread), texel * ${FROST_RADIUS_CAP.toFixed(1)});
50
+
51
+ var cover = 0.0;
52
+ var colour = vec3<f32>(0.0);
53
+ var found = 0.0;
54
+ for (var i = 0u; i < taps; i = i + 1u) {
55
+ let offset = SHADOW_TAPS[i];
56
+ /* The outline: a tap counts the pane only where the receiver is behind it, by the bias. */
57
+ if (depth > glassDepthAt(u + offset.x * texel, v + offset.y * texel) + bias) {
58
+ cover = cover + 1.0;
59
+ }
60
+ /* The colour: the spread's taps, each an average, unmixed and weighed by the pane's share. */
61
+ let pane = sunGlassUnmix(glassTintAround(u + offset.x * radius, v + offset.y * radius, radius), clarity);
62
+ colour = colour + pane.xyz * pane.w;
63
+ found = found + pane.w;
64
+ }
65
+ let mixed = select(vec3<f32>(1.0), colour / max(found, 1e-6), found > 0.0);
66
+ return mix(vec3<f32>(1.0), mixed, cover / f32(max(taps, 1u)));
67
+ }
68
+ `;
69
+
70
+ /**
71
+ * `sunGlass` over maps held in storage buffers, read as the reference reads them, so the whole
72
+ * lookup can be compared with `glassTintAt` rather than only the arithmetic between the reads.
73
+ *
74
+ * Four floats a case in — u, v, the receiver's depth, one spare — and four out, the tint and one
75
+ * spare. The config is the map's size, the depth span, map units a metre, and the tap count.
76
+ */
77
+ export const SUN_GLASS_PARITY_WGSL = /* wgsl */ `
78
+ @group(0) @binding(0) var<storage, read> depths: array<f32>;
79
+ @group(0) @binding(1) var<storage, read> tints: array<f32>;
80
+ @group(0) @binding(2) var<storage, read> cases: array<f32>;
81
+ @group(0) @binding(3) var<storage, read> config: array<f32>;
82
+ @group(0) @binding(4) var<storage, read_write> results: array<f32>;
83
+
84
+ /* The opaque lookup's own read, which this entry never calls: included only for its tap table. */
85
+ fn shadowDepthAt(u: f32, v: f32) -> f32 { return 1.0; }
86
+ ${SHADE_SHADOW_WGSL}
87
+
88
+ fn glassIndex(u: f32, v: f32) -> u32 {
89
+ let size = config[0];
90
+ let x = u32(clamp(floor(u * size), 0.0, size - 1.0));
91
+ let y = u32(clamp(floor(v * size), 0.0, size - 1.0));
92
+ return y * u32(size) + x;
93
+ }
94
+
95
+ fn glassDepthAt(u: f32, v: f32) -> f32 {
96
+ return depths[glassIndex(u, v)];
97
+ }
98
+
99
+ fn glassTintTexel(u: f32, v: f32) -> vec4<f32> {
100
+ let at = glassIndex(u, v) * 4u;
101
+ return vec4<f32>(tints[at], tints[at + 1u], tints[at + 2u], tints[at + 3u]);
102
+ }
103
+
104
+ /* The reference's coarse read: the average of every texel within the radius. */
105
+ fn glassTintAround(u: f32, v: f32, radius: f32) -> vec4<f32> {
106
+ let size = config[0];
107
+ let reach = radius * size;
108
+ let x0 = u32(max(0.0, floor(u * size - reach)));
109
+ let x1 = u32(min(size - 1.0, floor(u * size + reach)));
110
+ let y0 = u32(max(0.0, floor(v * size - reach)));
111
+ let y1 = u32(min(size - 1.0, floor(v * size + reach)));
112
+ var sum = vec4<f32>(0.0);
113
+ var n = 0.0;
114
+ for (var y = y0; y <= y1; y = y + 1u) {
115
+ for (var x = x0; x <= x1; x = x + 1u) {
116
+ let at = (y * u32(size) + x) * 4u;
117
+ sum = sum + vec4<f32>(tints[at], tints[at + 1u], tints[at + 2u], tints[at + 3u]);
118
+ n = n + 1.0;
119
+ }
120
+ }
121
+ return sum / max(n, 1.0);
122
+ }
123
+ ${SUN_GLASS_WGSL}
124
+
125
+ @compute @workgroup_size(64)
126
+ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
127
+ if (id.x * 4u + 3u >= arrayLength(&cases)) { return; }
128
+ var settings: SunGlassSettings;
129
+ settings.mapSize = config[0];
130
+ settings.depthSpan = config[1];
131
+ settings.uvPerMetre = config[2];
132
+ settings.taps = config[3];
133
+ let at = id.x * 4u;
134
+ let tint = sunGlass(cases[at], cases[at + 1u], cases[at + 2u], settings);
135
+ results[at] = tint.x;
136
+ results[at + 1u] = tint.y;
137
+ results[at + 2u] = tint.z;
138
+ }
139
+ `;
@@ -47,6 +47,7 @@
47
47
  * halves of one frame disagreeing about the same light.
48
48
  */
49
49
 
50
+ import { SUN_DYNAMIC_LAYER, SUN_PEELED_LAYER, SUN_STATIC_LAYER } from '../shadowMap.ts';
50
51
  import { resolveConditionals } from './conditionals.ts';
51
52
 
52
53
  export const LIGHT_VOLUME_VERT = `#version 300 es
@@ -159,9 +160,8 @@ uniform vec3 uDustOffset;
159
160
  uniform float uSunShadow;
160
161
  uniform mat4 uLightViewProj;
161
162
  uniform float uShadowMapSize;
162
- uniform sampler2D uStaticShadowMap;
163
- uniform sampler2D uPeeledShadowMap;
164
- uniform sampler2D uDynamicShadowMap;
163
+ /* The sun's static, moving and peeled maps, as layers of one array: see shadowMap.ts. */
164
+ uniform highp sampler2DArray uSunShadows;
165
165
  uniform int uPeeledShadowEnabled;
166
166
  #endif
167
167
 
@@ -324,11 +324,11 @@ float sunReach(vec3 worldPos) {
324
324
  if (edgeFade <= 0.0) return 1.0;
325
325
 
326
326
  float compare = p.z - BIAS;
327
- float blocked = occlusion(textureLod(uStaticShadowMap, p.xy, 0.0).r, compare);
327
+ float blocked = occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_STATIC_LAYER}.0), 0.0).r, compare);
328
328
  if (uPeeledShadowEnabled != 0) {
329
- blocked = max(blocked, occlusion(textureLod(uPeeledShadowMap, p.xy, 0.0).r, compare));
329
+ blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_PEELED_LAYER}.0), 0.0).r, compare));
330
330
  }
331
- blocked = max(blocked, occlusion(textureLod(uDynamicShadowMap, p.xy, 0.0).r, compare));
331
+ blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_DYNAMIC_LAYER}.0), 0.0).r, compare));
332
332
  return mix(1.0, 1.0 - blocked, uSunShadow * edgeFade);
333
333
  }
334
334
  #endif
@@ -12,6 +12,30 @@ void main() {
12
12
  gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);
13
13
  }`;
14
14
 
15
+ /**
16
+ * Which cube face owns this octahedral texel, and where in that face it looks: `d`, `forward` and
17
+ * `faceUv`, with every texel another face owns discarded. **One text for both resolves**, depth
18
+ * and tint, because the tie-breaking has to agree with itself as well as with the CPU: a sliver
19
+ * of texels given to one face's depth and another face's colour is a tinted seam.
20
+ */
21
+ const FACE_REGION = ` vec3 d = octDecode(gl_FragCoord.xy / uEdge);
22
+
23
+ /*
24
+ * Which face owns this texel. The tie-breaking is x, then y, then z, and it has to match the
25
+ * CPU's exactly or a sliver of texels along a boundary belongs to two faces or to none.
26
+ */
27
+ vec3 a = abs(d);
28
+ int face;
29
+ if (a.x >= a.y && a.x >= a.z) face = d.x >= 0.0 ? 0 : 1;
30
+ else if (a.y >= a.z) face = d.y >= 0.0 ? 2 : 3;
31
+ else face = d.z >= 0.0 ? 4 : 5;
32
+ if (face != uFaceIndex) discard;
33
+
34
+ /* lookAt looks down -z, so a direction inside this face has a negative z here. */
35
+ vec3 v = uFaceRotation * d;
36
+ float forward = -v.z;
37
+ vec2 faceUv = (v.xy / forward) * 0.5 + 0.5;`;
38
+
15
39
  /**
16
40
  * One cube face into its region of an octahedral map, as linear radial distance.
17
41
  *
@@ -46,23 +70,7 @@ uniform float uEdge;
46
70
  ${OCTAHEDRAL_GLSL}
47
71
 
48
72
  void main() {
49
- vec3 d = octDecode(gl_FragCoord.xy / uEdge);
50
-
51
- /*
52
- * Which face owns this texel. The tie-breaking is x, then y, then z, and it has to match the
53
- * CPU's exactly or a sliver of texels along a boundary belongs to two faces or to none.
54
- */
55
- vec3 a = abs(d);
56
- int face;
57
- if (a.x >= a.y && a.x >= a.z) face = d.x >= 0.0 ? 0 : 1;
58
- else if (a.y >= a.z) face = d.y >= 0.0 ? 2 : 3;
59
- else face = d.z >= 0.0 ? 4 : 5;
60
- if (face != uFaceIndex) discard;
61
-
62
- /* lookAt looks down -z, so a direction inside this face has a negative z here. */
63
- vec3 v = uFaceRotation * d;
64
- float forward = -v.z;
65
- vec2 faceUv = (v.xy / forward) * 0.5 + 0.5;
73
+ ${FACE_REGION}
66
74
 
67
75
  /*
68
76
  * textureLod at level zero rather than plain texture. The scratch carries one storage level and
@@ -81,3 +89,28 @@ void main() {
81
89
  /* d is a unit vector, so forward is its cosine to the axis and this is the true radius. */
82
90
  gl_FragDepth = clamp((faceLocalZ / forward) / uFar, 0.0, 1.0);
83
91
  }`;
92
+
93
+ /**
94
+ * One face of a lamp's glass tint into its region of the tint layer: the depth resolve's region,
95
+ * and a colour copied rather than a depth decoded.
96
+ *
97
+ * **Nearest, at level zero**, like the depth beside it: the tint's outline has to land on the
98
+ * glass depth's texels, and a filtered copy would smear a pane's colour a texel past its edge.
99
+ */
100
+ export const OCTAHEDRAL_RESOLVE_TINT_FRAG = `#version 300 es
101
+ precision highp float;
102
+
103
+ /** The face the bake just tinted, as colour. */
104
+ uniform highp sampler2D uFace;
105
+ uniform mat3 uFaceRotation;
106
+ uniform int uFaceIndex;
107
+ uniform float uEdge;
108
+
109
+ out vec4 outTint;
110
+
111
+ ${OCTAHEDRAL_GLSL}
112
+
113
+ void main() {
114
+ ${FACE_REGION}
115
+ outTint = textureLod(uFace, faceUv, 0.0);
116
+ }`;