@driftengine/core 4.4.1 → 4.5.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 (218) hide show
  1. package/CHANGELOG.json +72 -0
  2. package/README.md +1 -1
  3. package/dist/index.d.ts +5 -1
  4. package/dist/index.js +7 -0
  5. package/dist/render/backend/api.d.ts +17 -11
  6. package/dist/render/backend/webgl2/glassTintPrograms.d.ts +13 -0
  7. package/dist/render/backend/webgl2/glassTintPrograms.js +38 -0
  8. package/dist/render/backend/webgl2/renderer.d.ts +82 -8
  9. package/dist/render/backend/webgl2/renderer.js +373 -105
  10. package/dist/render/backend/webgpu/buffers.d.ts +19 -1
  11. package/dist/render/backend/webgpu/buffers.js +27 -1
  12. package/dist/render/backend/webgpu/depthPass.d.ts +1 -1
  13. package/dist/render/backend/webgpu/depthPass.js +2 -1
  14. package/dist/render/backend/webgpu/flatPass.d.ts +2 -0
  15. package/dist/render/backend/webgpu/flatPass.js +20 -1
  16. package/dist/render/backend/webgpu/glassTintPass.d.ts +28 -0
  17. package/dist/render/backend/webgpu/glassTintPass.js +205 -0
  18. package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +60 -1
  19. package/dist/render/backend/webgpu/gpuDrivenPass.js +305 -5
  20. package/dist/render/backend/webgpu/instanced.d.ts +12 -1
  21. package/dist/render/backend/webgpu/instanced.js +20 -1
  22. package/dist/render/backend/webgpu/latePass.d.ts +26 -0
  23. package/dist/render/backend/webgpu/latePass.js +133 -0
  24. package/dist/render/backend/webgpu/lightVolumePass.js +5 -1
  25. package/dist/render/backend/webgpu/motionPass.d.ts +95 -0
  26. package/dist/render/backend/webgpu/motionPass.js +491 -0
  27. package/dist/render/backend/webgpu/pipelineCache.d.ts +10 -1
  28. package/dist/render/backend/webgpu/pipelineCache.js +11 -1
  29. package/dist/render/backend/webgpu/pointGlassTintPass.d.ts +32 -0
  30. package/dist/render/backend/webgpu/pointGlassTintPass.js +193 -0
  31. package/dist/render/backend/webgpu/pointShadowPass.d.ts +35 -6
  32. package/dist/render/backend/webgpu/pointShadowPass.js +105 -20
  33. package/dist/render/backend/webgpu/postPass.d.ts +21 -15
  34. package/dist/render/backend/webgpu/postPass.js +17 -4
  35. package/dist/render/backend/webgpu/renderer.d.ts +181 -54
  36. package/dist/render/backend/webgpu/renderer.js +1011 -394
  37. package/dist/render/backend/webgpu/scatterPass.js +2 -1
  38. package/dist/render/backend/webgpu/skinPaletteRing.d.ts +4 -0
  39. package/dist/render/backend/webgpu/skinPaletteRing.js +4 -0
  40. package/dist/render/backend/webgpu/snapshotMips.d.ts +29 -0
  41. package/dist/render/backend/webgpu/snapshotMips.js +52 -0
  42. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +5 -0
  43. package/dist/render/backend/webgpu/surfaceTexturePass.js +1 -1
  44. package/dist/render/flameLight.js +15 -2
  45. package/dist/render/glass.d.ts +45 -0
  46. package/dist/render/glass.js +39 -0
  47. package/dist/render/glassCasters.d.ts +40 -0
  48. package/dist/render/glassCasters.js +84 -0
  49. package/dist/render/glassShadow.d.ts +78 -0
  50. package/dist/render/glassShadow.js +125 -0
  51. package/dist/render/globalMediumPass.d.ts +2 -3
  52. package/dist/render/globalMediumPass.js +2 -8
  53. package/dist/render/gpudriven/lit.d.ts +12 -0
  54. package/dist/render/gpudriven/lit.js +23 -0
  55. package/dist/render/gpudriven/materialTable.d.ts +15 -5
  56. package/dist/render/gpudriven/materialTable.js +26 -6
  57. package/dist/render/gpudriven/pipeline.d.ts +1 -1
  58. package/dist/render/gpudriven/pipeline.js +4 -3
  59. package/dist/render/gpudriven/sunGlass.d.ts +35 -0
  60. package/dist/render/gpudriven/sunGlass.js +89 -0
  61. package/dist/render/lightBudget.d.ts +17 -5
  62. package/dist/render/lightBudget.js +17 -5
  63. package/dist/render/pointGlassTint.d.ts +59 -0
  64. package/dist/render/pointGlassTint.js +198 -0
  65. package/dist/render/pointShadowArray.d.ts +56 -3
  66. package/dist/render/pointShadowArray.js +127 -16
  67. package/dist/render/pointShadowBudget.js +51 -41
  68. package/dist/render/pointShadowMap.d.ts +23 -1
  69. package/dist/render/pointShadowMap.js +27 -1
  70. package/dist/render/recon/changeFrames.d.ts +15 -0
  71. package/dist/render/recon/changeFrames.js +21 -0
  72. package/dist/render/recon/disocclusion.d.ts +36 -3
  73. package/dist/render/recon/disocclusion.js +56 -4
  74. package/dist/render/recon/lateRouting.d.ts +14 -0
  75. package/dist/render/recon/lateRouting.js +18 -0
  76. package/dist/render/recon/mover.d.ts +57 -0
  77. package/dist/render/recon/mover.js +86 -0
  78. package/dist/render/recon/resolve.js +95 -12
  79. package/dist/render/renderQuality.d.ts +35 -0
  80. package/dist/render/renderQuality.js +7 -0
  81. package/dist/render/rendererHarness.js +12 -0
  82. package/dist/render/sceneTarget.d.ts +9 -1
  83. package/dist/render/sceneTarget.js +59 -13
  84. package/dist/render/shaders/depth.d.ts +16 -1
  85. package/dist/render/shaders/depth.js +85 -9
  86. package/dist/render/shaders/flat/directionalShadow.js +91 -6
  87. package/dist/render/shaders/flat/glassTint.d.ts +6 -0
  88. package/dist/render/shaders/flat/glassTint.js +25 -0
  89. package/dist/render/shaders/flat/index.d.ts +13 -0
  90. package/dist/render/shaders/flat/index.js +4 -0
  91. package/dist/render/shaders/flat/lampGlass.d.ts +1 -0
  92. package/dist/render/shaders/flat/lampGlass.js +183 -0
  93. package/dist/render/shaders/flat/main.d.ts +1 -1
  94. package/dist/render/shaders/flat/main.js +115 -15
  95. package/dist/render/shaders/flat/pointShadow.d.ts +1 -1
  96. package/dist/render/shaders/flat/pointShadow.js +2 -0
  97. package/dist/render/shaders/flat/preamble.js +21 -6
  98. package/dist/render/shaders/generated/depth.wgsl.d.ts +227 -4
  99. package/dist/render/shaders/generated/depth.wgsl.js +227 -4
  100. package/dist/render/shaders/generated/flat.wgsl.d.ts +360 -312
  101. package/dist/render/shaders/generated/flat.wgsl.js +376 -328
  102. package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +3 -13
  103. package/dist/render/shaders/generated/globalMedium.wgsl.js +3 -13
  104. package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +3 -13
  105. package/dist/render/shaders/generated/lightVolume.wgsl.js +4 -14
  106. package/dist/render/shaders/generated/octahedralResolve.wgsl.d.ts +29 -0
  107. package/dist/render/shaders/generated/octahedralResolve.wgsl.js +29 -0
  108. package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +31 -6
  109. package/dist/render/shaders/generated/temporalResolve.wgsl.js +31 -6
  110. package/dist/render/shaders/globalMedium.js +6 -6
  111. package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +7 -0
  112. package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +86 -1
  113. package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +1 -1
  114. package/dist/render/shaders/gpudriven/cull.wgsl.js +11 -2
  115. package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +1 -1
  116. package/dist/render/shaders/gpudriven/materialTable.wgsl.js +3 -1
  117. package/dist/render/shaders/gpudriven/shade.wgsl.js +50 -1
  118. package/dist/render/shaders/gpudriven/sunGlass.wgsl.d.ts +9 -0
  119. package/dist/render/shaders/gpudriven/sunGlass.wgsl.js +133 -0
  120. package/dist/render/shaders/lightVolume.js +6 -6
  121. package/dist/render/shaders/octahedralResolve.d.ts +8 -0
  122. package/dist/render/shaders/octahedralResolve.js +48 -17
  123. package/dist/render/shaders/recon/lateDepth.wgsl.d.ts +1 -0
  124. package/dist/render/shaders/recon/lateDepth.wgsl.js +44 -0
  125. package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
  126. package/dist/render/shaders/recon/motion.wgsl.js +84 -0
  127. package/dist/render/shaders/recon/resolve.wgsl.d.ts +1 -1
  128. package/dist/render/shaders/recon/resolve.wgsl.js +112 -8
  129. package/dist/render/shaders/temporalResolve.js +133 -5
  130. package/dist/render/shadowCasters.d.ts +20 -1
  131. package/dist/render/shadowCasters.js +15 -1
  132. package/dist/render/shadowMap.d.ts +54 -5
  133. package/dist/render/shadowMap.js +190 -36
  134. package/dist/render/sunGlassTint.d.ts +25 -0
  135. package/dist/render/sunGlassTint.js +79 -0
  136. package/dist/render/temporalAa.d.ts +145 -0
  137. package/dist/render/temporalAa.js +190 -0
  138. package/dist/render/temporalPass.d.ts +16 -14
  139. package/dist/render/temporalPass.js +59 -14
  140. package/dist/render/translucentQueue.d.ts +6 -0
  141. package/dist/render/translucentQueue.js +15 -1
  142. package/package.json +6 -6
  143. package/src/index.ts +10 -0
  144. package/src/render/backend/api.ts +15 -9
  145. package/src/render/backend/webgl2/glassTintPrograms.ts +58 -0
  146. package/src/render/backend/webgl2/renderer.ts +422 -109
  147. package/src/render/backend/webgpu/buffers.ts +50 -2
  148. package/src/render/backend/webgpu/depthPass.ts +2 -1
  149. package/src/render/backend/webgpu/flatPass.ts +22 -1
  150. package/src/render/backend/webgpu/glassTintPass.ts +244 -0
  151. package/src/render/backend/webgpu/gpuDrivenPass.ts +349 -5
  152. package/src/render/backend/webgpu/instanced.ts +21 -1
  153. package/src/render/backend/webgpu/latePass.ts +152 -0
  154. package/src/render/backend/webgpu/lightVolumePass.ts +5 -1
  155. package/src/render/backend/webgpu/motionPass.ts +535 -0
  156. package/src/render/backend/webgpu/pipelineCache.ts +12 -1
  157. package/src/render/backend/webgpu/pointGlassTintPass.ts +233 -0
  158. package/src/render/backend/webgpu/pointShadowPass.ts +158 -26
  159. package/src/render/backend/webgpu/postPass.ts +34 -4
  160. package/src/render/backend/webgpu/renderer.ts +1178 -425
  161. package/src/render/backend/webgpu/scatterPass.ts +2 -1
  162. package/src/render/backend/webgpu/skinPaletteRing.ts +4 -0
  163. package/src/render/backend/webgpu/snapshotMips.ts +80 -0
  164. package/src/render/backend/webgpu/surfaceTexturePass.ts +1 -1
  165. package/src/render/flameLight.ts +15 -2
  166. package/src/render/glass.ts +74 -0
  167. package/src/render/glassCasters.ts +164 -0
  168. package/src/render/glassShadow.ts +153 -0
  169. package/src/render/globalMediumPass.ts +4 -11
  170. package/src/render/gpudriven/lit.ts +31 -0
  171. package/src/render/gpudriven/materialTable.ts +28 -6
  172. package/src/render/gpudriven/pipeline.ts +4 -3
  173. package/src/render/gpudriven/sunGlass.ts +117 -0
  174. package/src/render/lightBudget.ts +19 -5
  175. package/src/render/pointGlassTint.ts +250 -0
  176. package/src/render/pointShadowArray.ts +188 -22
  177. package/src/render/pointShadowBudget.ts +49 -39
  178. package/src/render/pointShadowMap.ts +41 -0
  179. package/src/render/recon/changeFrames.ts +24 -0
  180. package/src/render/recon/disocclusion.ts +54 -3
  181. package/src/render/recon/lateRouting.ts +29 -0
  182. package/src/render/recon/mover.ts +118 -0
  183. package/src/render/recon/resolve.ts +137 -10
  184. package/src/render/renderQuality.ts +47 -0
  185. package/src/render/rendererHarness.ts +12 -0
  186. package/src/render/sceneTarget.ts +66 -12
  187. package/src/render/shaders/depth.ts +109 -9
  188. package/src/render/shaders/flat/directionalShadow.ts +97 -6
  189. package/src/render/shaders/flat/glassTint.ts +25 -0
  190. package/src/render/shaders/flat/index.ts +17 -0
  191. package/src/render/shaders/flat/lampGlass.ts +185 -0
  192. package/src/render/shaders/flat/main.ts +115 -15
  193. package/src/render/shaders/flat/pointShadow.ts +2 -0
  194. package/src/render/shaders/flat/preamble.ts +21 -6
  195. package/src/render/shaders/generated/depth.wgsl.ts +234 -4
  196. package/src/render/shaders/generated/flat.wgsl.ts +376 -328
  197. package/src/render/shaders/generated/globalMedium.wgsl.ts +3 -13
  198. package/src/render/shaders/generated/lightVolume.wgsl.ts +4 -14
  199. package/src/render/shaders/generated/octahedralResolve.wgsl.ts +30 -0
  200. package/src/render/shaders/generated/temporalResolve.wgsl.ts +31 -6
  201. package/src/render/shaders/globalMedium.ts +6 -6
  202. package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +88 -1
  203. package/src/render/shaders/gpudriven/cull.wgsl.ts +11 -2
  204. package/src/render/shaders/gpudriven/materialTable.wgsl.ts +3 -1
  205. package/src/render/shaders/gpudriven/shade.wgsl.ts +50 -1
  206. package/src/render/shaders/gpudriven/sunGlass.wgsl.ts +139 -0
  207. package/src/render/shaders/lightVolume.ts +6 -6
  208. package/src/render/shaders/octahedralResolve.ts +50 -17
  209. package/src/render/shaders/recon/lateDepth.wgsl.ts +47 -0
  210. package/src/render/shaders/recon/motion.wgsl.ts +84 -0
  211. package/src/render/shaders/recon/resolve.wgsl.ts +112 -8
  212. package/src/render/shaders/temporalResolve.ts +141 -5
  213. package/src/render/shadowCasters.ts +28 -1
  214. package/src/render/shadowMap.ts +231 -37
  215. package/src/render/sunGlassTint.ts +86 -0
  216. package/src/render/temporalAa.ts +227 -0
  217. package/src/render/temporalPass.ts +88 -12
  218. package/src/render/translucentQueue.ts +20 -1
@@ -4,7 +4,7 @@
4
4
  * The GLSL beside this file is the source of truth. A hand edit here is discarded by
5
5
  * the next generation, and `npm run wgsl:check` fails the build when this is stale.
6
6
  */
7
- export const TEMPORAL_RESOLVE_FRAG_WGSL = "struct Uniforms {\n uReprojection: mat4x4<f32>,\n uTexel: vec2<f32>,\n uHistoryBlend: f32,\n}\n\n@group(0) @binding(32) \nvar uScene_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uScene_s: sampler;\nvar<private> vUv_1: vec2<f32>;\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(34) \nvar uHistory_t: texture_2d<f32>;\n@group(0) @binding(35) \nvar uHistory_s: sampler;\nvar<private> fragColor: vec4<f32>;\n@group(0) @binding(36) \nvar uDepth_t: texture_2d<f32>;\n@group(0) @binding(37) \nvar uDepth_s: sampler;\n\nfn clipToNeighbourhood_u0028_vf3_u003b_vf3_u003b_vf3_u003b(history: ptr<function, vec3<f32>>, lo: ptr<function, vec3<f32>>, hi: ptr<function, vec3<f32>>) -> vec3<f32> {\n var centre: vec3<f32>;\n var extent: vec3<f32>;\n var offset: vec3<f32>;\n var ratios: vec3<f32>;\n var ratio: f32;\n\n let _e39 = (*lo);\n let _e40 = (*hi);\n centre = ((_e39 + _e40) * 0.5f);\n let _e43 = (*hi);\n let _e44 = (*lo);\n extent = ((_e43 - _e44) * 0.5f);\n let _e47 = (*history);\n let _e48 = centre;\n offset = (_e47 - _e48);\n let _e50 = offset;\n let _e52 = extent;\n ratios = (abs(_e50) / max(_e52, vec3<f32>(0.0000001f, 0.0000001f, 0.0000001f)));\n let _e56 = ratios[0u];\n let _e58 = ratios[1u];\n let _e60 = ratios[2u];\n ratio = max(_e56, max(_e58, _e60));\n let _e63 = ratio;\n if (_e63 <= 1f) {\n let _e65 = (*history);\n return _e65;\n }\n let _e66 = centre;\n let _e67 = offset;\n let _e68 = ratio;\n return (_e66 + (_e67 / vec3(_e68)));\n}\n\nfn historyCatmullRom_u0028_vf2_u003b(uv: ptr<function, vec2<f32>>) -> vec3<f32> {\n var size: vec2<f32>;\n var at: vec2<f32>;\n var base: vec2<f32>;\n var f: vec2<f32>;\n var w0_: vec2<f32>;\n var w1_: vec2<f32>;\n var w2_: vec2<f32>;\n var w3_: vec2<f32>;\n var w12_: vec2<f32>;\n var at0_: vec2<f32>;\n var at3_: vec2<f32>;\n var at12_: vec2<f32>;\n var sum: vec3<f32>;\n var weight: f32;\n\n let _e47 = unnamed.uTexel;\n size = (vec2(1f) / _e47);\n let _e50 = (*uv);\n let _e51 = size;\n at = (_e50 * _e51);\n let _e53 = at;\n base = (floor((_e53 - vec2(0.5f))) + vec2(0.5f));\n let _e59 = at;\n let _e60 = base;\n f = (_e59 - _e60);\n let _e62 = f;\n let _e63 = f;\n let _e64 = f;\n w0_ = (_e62 * (vec2(-0.5f) + (_e63 * (vec2(1f) - (_e64 * 0.5f)))));\n let _e72 = f;\n let _e73 = f;\n let _e75 = f;\n w1_ = (vec2(1f) + ((_e72 * _e73) * (vec2(-2.5f) + (_e75 * 1.5f))));\n let _e82 = f;\n let _e83 = f;\n let _e84 = f;\n w2_ = (_e82 * (vec2(0.5f) + (_e83 * (vec2(2f) - (_e84 * 1.5f)))));\n let _e92 = f;\n let _e93 = f;\n let _e95 = f;\n w3_ = ((_e92 * _e93) * (vec2(-0.5f) + (_e95 * 0.5f)));\n let _e100 = w1_;\n let _e101 = w2_;\n w12_ = (_e100 + _e101);\n let _e103 = base;\n let _e107 = unnamed.uTexel;\n at0_ = ((_e103 - vec2(1f)) * _e107);\n let _e109 = base;\n let _e113 = unnamed.uTexel;\n at3_ = ((_e109 + vec2(2f)) * _e113);\n let _e115 = base;\n let _e116 = w2_;\n let _e117 = w12_;\n let _e121 = unnamed.uTexel;\n at12_ = ((_e115 + (_e116 / _e117)) * _e121);\n let _e124 = at12_[0u];\n let _e126 = at0_[1u];\n let _e128 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e124, _e126), 0f);\n let _e131 = w12_[0u];\n let _e133 = w0_[1u];\n let _e137 = at0_[0u];\n let _e139 = at12_[1u];\n let _e141 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e137, _e139), 0f);\n let _e144 = w0_[0u];\n let _e146 = w12_[1u];\n let _e150 = at12_;\n let _e151 = textureSampleLevel(uHistory_t, uHistory_s, _e150, 0f);\n let _e154 = w12_[0u];\n let _e156 = w12_[1u];\n let _e161 = at3_[0u];\n let _e163 = at12_[1u];\n let _e165 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e161, _e163), 0f);\n let _e168 = w3_[0u];\n let _e170 = w12_[1u];\n let _e175 = at12_[0u];\n let _e177 = at3_[1u];\n let _e179 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e175, _e177), 0f);\n let _e182 = w12_[0u];\n let _e184 = w3_[1u];\n sum = (((((_e128.xyz * (_e131 * _e133)) + (_e141.xyz * (_e144 * _e146))) + (_e151.xyz * (_e154 * _e156))) + (_e165.xyz * (_e168 * _e170))) + (_e179.xyz * (_e182 * _e184)));\n let _e189 = w12_[0u];\n let _e191 = w0_[1u];\n let _e194 = w0_[0u];\n let _e196 = w12_[1u];\n let _e200 = w12_[0u];\n let _e202 = w12_[1u];\n let _e206 = w3_[0u];\n let _e208 = w12_[1u];\n let _e212 = w12_[0u];\n let _e214 = w3_[1u];\n weight = (((((_e189 * _e191) + (_e194 * _e196)) + (_e200 * _e202)) + (_e206 * _e208)) + (_e212 * _e214));\n let _e217 = sum;\n let _e218 = weight;\n return max((_e217 / vec3(_e218)), vec3<f32>(0f, 0f, 0f));\n}\n\nfn neighbourhood_u0028_vf3_u003b_vf3_u003b(lo_1: ptr<function, vec3<f32>>, hi_1: ptr<function, vec3<f32>>) {\n var y: i32;\n var x: i32;\n var c: vec3<f32>;\n\n (*lo_1) = vec3<f32>(1000000000f, 1000000000f, 1000000000f);\n (*hi_1) = vec3<f32>(-1000000000f, -1000000000f, -1000000000f);\n y = -1i;\n loop {\n let _e36 = y;\n if (_e36 <= 1i) {\n x = -1i;\n loop {\n let _e38 = x;\n if (_e38 <= 1i) {\n let _e40 = vUv_1;\n let _e41 = x;\n let _e43 = y;\n let _e47 = unnamed.uTexel;\n let _e50 = textureSampleLevel(uScene_t, uScene_s, (_e40 + (vec2<f32>(f32(_e41), f32(_e43)) * _e47)), 0f);\n c = _e50.xyz;\n let _e52 = (*lo_1);\n let _e53 = c;\n (*lo_1) = min(_e52, _e53);\n let _e55 = (*hi_1);\n let _e56 = c;\n (*hi_1) = max(_e55, _e56);\n continue;\n } else {\n break;\n }\n continuing {\n let _e58 = x;\n x = (_e58 + 1i);\n }\n }\n continue;\n } else {\n break;\n }\n continuing {\n let _e60 = y;\n y = (_e60 + 1i);\n }\n }\n return;\n}\n\nfn main_1() {\n var current: vec3<f32>;\n var depth: f32;\n var clip: vec4<f32>;\n var previous: vec4<f32>;\n var wasUv: vec2<f32>;\n var lo_2: vec3<f32>;\n var hi_2: vec3<f32>;\n var param: vec3<f32>;\n var param_1: vec3<f32>;\n var history_1: vec3<f32>;\n var param_2: vec2<f32>;\n var bounded: vec3<f32>;\n var param_3: vec3<f32>;\n var param_4: vec3<f32>;\n var param_5: vec3<f32>;\n var phi_440_: bool;\n var phi_447_: bool;\n var phi_454_: bool;\n\n let _e46 = vUv_1;\n let _e47 = textureSampleLevel(uScene_t, uScene_s, _e46, 0f);\n current = _e47.xyz;\n let _e50 = unnamed.uHistoryBlend;\n if (_e50 <= 0f) {\n let _e52 = current;\n fragColor = vec4<f32>(_e52.x, _e52.y, _e52.z, 1f);\n return;\n }\n let _e57 = vUv_1;\n let _e58 = textureSampleLevel(uDepth_t, uDepth_s, _e57, 0f);\n depth = _e58.x;\n let _e60 = vUv_1;\n let _e63 = ((_e60 * 2f) - vec2(1f));\n let _e64 = depth;\n clip = vec4<f32>(_e63.x, _e63.y, (1f - (_e64 * 2f)), 1f);\n let _e71 = unnamed.uReprojection;\n let _e72 = clip;\n previous = (_e71 * _e72);\n let _e75 = previous[3u];\n if (_e75 <= 0f) {\n let _e77 = current;\n fragColor = vec4<f32>(_e77.x, _e77.y, _e77.z, 1f);\n return;\n }\n let _e82 = previous;\n let _e85 = previous[3u];\n wasUv = (((_e82.xy / vec2(_e85)) * 0.5f) + vec2(0.5f));\n let _e92 = wasUv[0u];\n let _e93 = (_e92 < 0f);\n phi_440_ = _e93;\n if !(_e93) {\n let _e96 = wasUv[0u];\n phi_440_ = (_e96 > 1f);\n }\n let _e99 = phi_440_;\n phi_447_ = _e99;\n if !(_e99) {\n let _e102 = wasUv[1u];\n phi_447_ = (_e102 < 0f);\n }\n let _e105 = phi_447_;\n phi_454_ = _e105;\n if !(_e105) {\n let _e108 = wasUv[1u];\n phi_454_ = (_e108 > 1f);\n }\n let _e111 = phi_454_;\n if _e111 {\n let _e112 = current;\n fragColor = vec4<f32>(_e112.x, _e112.y, _e112.z, 1f);\n return;\n }\n neighbourhood_u0028_vf3_u003b_vf3_u003b((&param), (&param_1));\n let _e117 = param;\n lo_2 = _e117;\n let _e118 = param_1;\n hi_2 = _e118;\n let _e119 = wasUv;\n param_2 = _e119;\n let _e120 = historyCatmullRom_u0028_vf2_u003b((&param_2));\n history_1 = _e120;\n let _e121 = history_1;\n param_3 = _e121;\n let _e122 = lo_2;\n param_4 = _e122;\n let _e123 = hi_2;\n param_5 = _e123;\n let _e124 = clipToNeighbourhood_u0028_vf3_u003b_vf3_u003b_vf3_u003b((&param_3), (&param_4), (&param_5));\n bounded = _e124;\n let _e125 = current;\n let _e126 = bounded;\n let _e128 = unnamed.uHistoryBlend;\n let _e130 = mix(_e125, _e126, vec3(_e128));\n fragColor = vec4<f32>(_e130.x, _e130.y, _e130.z, 1f);\n return;\n}\n\n@fragment \nfn main(@location(0) vUv: vec2<f32>) -> @location(0) vec4<f32> {\n vUv_1 = vUv;\n main_1();\n let _e3 = fragColor;\n return _e3;\n}\n";
7
+ export const TEMPORAL_RESOLVE_FRAG_WGSL = "struct Uniforms {\n uDepthToViewZ: vec4<f32>,\n uAntiFlicker: f32,\n uReprojection: mat4x4<f32>,\n uTexel: vec2<f32>,\n uPeriodStart: f32,\n uHistoryBlend: f32,\n}\n\nstruct FragmentOutput {\n @location(0) member: vec4<f32>,\n @location(1) member_1: vec4<f32>,\n @location(2) member_2: vec4<f32>,\n}\n\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(32) \nvar uScene_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uScene_s: sampler;\nvar<private> vUv_1: vec2<f32>;\n@group(0) @binding(34) \nvar uHistory_t: texture_2d<f32>;\n@group(0) @binding(35) \nvar uHistory_s: sampler;\nvar<private> fragColor: vec4<f32>;\nvar<private> flickerOut: vec4<f32>;\nvar<private> flickerMotionOut: vec4<f32>;\n@group(0) @binding(40) \nvar uDepth_t: texture_2d<f32>;\n@group(0) @binding(41) \nvar uDepth_s: sampler;\n@group(0) @binding(36) \nvar uFlicker_t: texture_2d<f32>;\n@group(0) @binding(38) \nvar uFlickerMotion_t: texture_2d<f32>;\n@group(0) @binding(37) \nvar uFlicker_s: sampler;\n@group(0) @binding(39) \nvar uFlickerMotion_s: sampler;\n\nfn repeats_u0028_f1_u003b_f1_u003b(mean: ptr<function, f32>, previous: ptr<function, f32>) -> f32 {\n var apart: f32;\n\n let _e63 = (*mean);\n let _e64 = (*previous);\n let _e67 = (*mean);\n let _e68 = (*previous);\n apart = (abs((_e63 - _e64)) / max(max(_e67, _e68), 0.003921569f));\n let _e72 = apart;\n return (1f - smoothstep(0.05f, 0.1f, _e72));\n}\n\nfn clipToNeighbourhood_u0028_vf3_u003b_vf3_u003b_vf3_u003b(history: ptr<function, vec3<f32>>, lo: ptr<function, vec3<f32>>, hi: ptr<function, vec3<f32>>) -> vec3<f32> {\n var centre: vec3<f32>;\n var extent: vec3<f32>;\n var offset: vec3<f32>;\n var ratios: vec3<f32>;\n var ratio: f32;\n\n let _e68 = (*lo);\n let _e69 = (*hi);\n centre = ((_e68 + _e69) * 0.5f);\n let _e72 = (*hi);\n let _e73 = (*lo);\n extent = ((_e72 - _e73) * 0.5f);\n let _e76 = (*history);\n let _e77 = centre;\n offset = (_e76 - _e77);\n let _e79 = offset;\n let _e81 = extent;\n ratios = (abs(_e79) / max(_e81, vec3<f32>(0.0000001f, 0.0000001f, 0.0000001f)));\n let _e85 = ratios[0u];\n let _e87 = ratios[1u];\n let _e89 = ratios[2u];\n ratio = max(_e85, max(_e87, _e89));\n let _e92 = ratio;\n if (_e92 <= 1f) {\n let _e94 = (*history);\n return _e94;\n }\n let _e95 = centre;\n let _e96 = offset;\n let _e97 = ratio;\n return (_e95 + (_e96 / vec3(_e97)));\n}\n\nfn luma_u0028_vf3_u003b(c: ptr<function, vec3<f32>>) -> f32 {\n let _e61 = (*c);\n return dot(_e61, vec3<f32>(0.2126f, 0.7152f, 0.0722f));\n}\n\nfn historyCatmullRom_u0028_vf2_u003b(uv: ptr<function, vec2<f32>>) -> vec3<f32> {\n var size: vec2<f32>;\n var at: vec2<f32>;\n var base: vec2<f32>;\n var f: vec2<f32>;\n var w0_: vec2<f32>;\n var w1_: vec2<f32>;\n var w2_: vec2<f32>;\n var w3_: vec2<f32>;\n var w12_: vec2<f32>;\n var at0_: vec2<f32>;\n var at3_: vec2<f32>;\n var at12_: vec2<f32>;\n var sum: vec3<f32>;\n var weight: f32;\n\n let _e76 = unnamed.uTexel;\n size = (vec2(1f) / _e76);\n let _e79 = (*uv);\n let _e80 = size;\n at = (_e79 * _e80);\n let _e82 = at;\n base = (floor((_e82 - vec2(0.5f))) + vec2(0.5f));\n let _e88 = at;\n let _e89 = base;\n f = (_e88 - _e89);\n let _e91 = f;\n let _e92 = f;\n let _e93 = f;\n w0_ = (_e91 * (vec2(-0.5f) + (_e92 * (vec2(1f) - (_e93 * 0.5f)))));\n let _e101 = f;\n let _e102 = f;\n let _e104 = f;\n w1_ = (vec2(1f) + ((_e101 * _e102) * (vec2(-2.5f) + (_e104 * 1.5f))));\n let _e111 = f;\n let _e112 = f;\n let _e113 = f;\n w2_ = (_e111 * (vec2(0.5f) + (_e112 * (vec2(2f) - (_e113 * 1.5f)))));\n let _e121 = f;\n let _e122 = f;\n let _e124 = f;\n w3_ = ((_e121 * _e122) * (vec2(-0.5f) + (_e124 * 0.5f)));\n let _e129 = w1_;\n let _e130 = w2_;\n w12_ = (_e129 + _e130);\n let _e132 = base;\n let _e136 = unnamed.uTexel;\n at0_ = ((_e132 - vec2(1f)) * _e136);\n let _e138 = base;\n let _e142 = unnamed.uTexel;\n at3_ = ((_e138 + vec2(2f)) * _e142);\n let _e144 = base;\n let _e145 = w2_;\n let _e146 = w12_;\n let _e150 = unnamed.uTexel;\n at12_ = ((_e144 + (_e145 / _e146)) * _e150);\n let _e153 = at12_[0u];\n let _e155 = at0_[1u];\n let _e157 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e153, _e155), 0f);\n let _e160 = w12_[0u];\n let _e162 = w0_[1u];\n let _e166 = at0_[0u];\n let _e168 = at12_[1u];\n let _e170 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e166, _e168), 0f);\n let _e173 = w0_[0u];\n let _e175 = w12_[1u];\n let _e179 = at12_;\n let _e180 = textureSampleLevel(uHistory_t, uHistory_s, _e179, 0f);\n let _e183 = w12_[0u];\n let _e185 = w12_[1u];\n let _e190 = at3_[0u];\n let _e192 = at12_[1u];\n let _e194 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e190, _e192), 0f);\n let _e197 = w3_[0u];\n let _e199 = w12_[1u];\n let _e204 = at12_[0u];\n let _e206 = at3_[1u];\n let _e208 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e204, _e206), 0f);\n let _e211 = w12_[0u];\n let _e213 = w3_[1u];\n sum = (((((_e157.xyz * (_e160 * _e162)) + (_e170.xyz * (_e173 * _e175))) + (_e180.xyz * (_e183 * _e185))) + (_e194.xyz * (_e197 * _e199))) + (_e208.xyz * (_e211 * _e213)));\n let _e218 = w12_[0u];\n let _e220 = w0_[1u];\n let _e223 = w0_[0u];\n let _e225 = w12_[1u];\n let _e229 = w12_[0u];\n let _e231 = w12_[1u];\n let _e235 = w3_[0u];\n let _e237 = w12_[1u];\n let _e241 = w12_[0u];\n let _e243 = w3_[1u];\n weight = (((((_e218 * _e220) + (_e223 * _e225)) + (_e229 * _e231)) + (_e235 * _e237)) + (_e241 * _e243));\n let _e246 = sum;\n let _e247 = weight;\n return max((_e246 / vec3(_e247)), vec3<f32>(0f, 0f, 0f));\n}\n\nfn neighbourhood_u0028_vf3_u003b_vf3_u003b(lo_1: ptr<function, vec3<f32>>, hi_1: ptr<function, vec3<f32>>) {\n var y: i32;\n var x: i32;\n var c_1: vec3<f32>;\n\n (*lo_1) = vec3<f32>(1000000000f, 1000000000f, 1000000000f);\n (*hi_1) = vec3<f32>(-1000000000f, -1000000000f, -1000000000f);\n y = -1i;\n loop {\n let _e65 = y;\n if (_e65 <= 1i) {\n x = -1i;\n loop {\n let _e67 = x;\n if (_e67 <= 1i) {\n let _e69 = vUv_1;\n let _e70 = x;\n let _e72 = y;\n let _e76 = unnamed.uTexel;\n let _e79 = textureSampleLevel(uScene_t, uScene_s, (_e69 + (vec2<f32>(f32(_e70), f32(_e72)) * _e76)), 0f);\n c_1 = _e79.xyz;\n let _e81 = (*lo_1);\n let _e82 = c_1;\n (*lo_1) = min(_e81, _e82);\n let _e84 = (*hi_1);\n let _e85 = c_1;\n (*hi_1) = max(_e84, _e85);\n continue;\n } else {\n break;\n }\n continuing {\n let _e87 = x;\n x = (_e87 + 1i);\n }\n }\n continue;\n } else {\n break;\n }\n continuing {\n let _e89 = y;\n y = (_e89 + 1i);\n }\n }\n return;\n}\n\nfn viewDepthOf_u0028_f1_u003b(depth: ptr<function, f32>) -> f32 {\n var z: f32;\n\n let _e62 = (*depth);\n z = (1f - (_e62 * 2f));\n let _e67 = unnamed.uDepthToViewZ[0u];\n let _e68 = z;\n let _e72 = unnamed.uDepthToViewZ[1u];\n let _e77 = unnamed.uDepthToViewZ[2u];\n let _e78 = z;\n let _e82 = unnamed.uDepthToViewZ[3u];\n return (-(((_e67 * _e68) + _e72)) / ((_e77 * _e78) + _e82));\n}\n\nfn freshRecord_u0028_vf3_u003b(current: ptr<function, vec3<f32>>) -> vec4<f32> {\n var seen: f32;\n var param: vec3<f32>;\n\n let _e63 = (*current);\n param = _e63;\n let _e64 = luma_u0028_vf3_u003b((&param));\n seen = _e64;\n let _e65 = seen;\n let _e67 = seen;\n return vec4<f32>(0f, (_e65 * 0.125f), _e67, 0f);\n}\n\nfn main_1() {\n var current_1: vec3<f32>;\n var param_1: vec3<f32>;\n var nearestAt: vec2<f32>;\n var depth_1: f32;\n var metres: f32;\n var param_2: f32;\n var y_1: i32;\n var x_1: i32;\n var at_1: vec2<f32>;\n var tap: f32;\n var tapMetres: f32;\n var param_3: f32;\n var clip: vec4<f32>;\n var previous_1: vec4<f32>;\n var param_4: vec3<f32>;\n var wasUv: vec2<f32>;\n var param_5: vec3<f32>;\n var lo_2: vec3<f32>;\n var hi_2: vec3<f32>;\n var param_6: vec3<f32>;\n var param_7: vec3<f32>;\n var history_1: vec3<f32>;\n var param_8: vec2<f32>;\n var size_1: vec2<i32>;\n var was: vec2<i32>;\n var nearest: f32;\n var n: i32;\n var at_2: vec2<i32>;\n var local: vec2<i32>;\n var local_1: vec2<i32>;\n var local_2: vec2<i32>;\n var stood: f32;\n var motionThere: vec4<f32>;\n var missedAll: bool;\n var same: bool;\n var swingOut: f32;\n var local_3: f32;\n var seen_1: f32;\n var param_9: vec3<f32>;\n var held: vec4<f32>;\n var local_4: vec4<f32>;\n var param_10: vec3<f32>;\n var still: f32;\n var apart_1: f32;\n var reach: f32;\n var within: bool;\n var proven: bool;\n var widen: f32;\n var local_5: f32;\n var blend: f32;\n var local_6: f32;\n var bounded: vec3<f32>;\n var param_11: vec3<f32>;\n var param_12: vec3<f32>;\n var param_13: vec3<f32>;\n var sum_1: f32;\n var mean_1: f32;\n var repeated: f32;\n var local_7: f32;\n var param_14: f32;\n var param_15: f32;\n var local_8: f32;\n var phi_589_: bool;\n var phi_596_: bool;\n var phi_603_: bool;\n var phi_740_: bool;\n\n let _e122 = vUv_1;\n let _e123 = textureSampleLevel(uScene_t, uScene_s, _e122, 0f);\n current_1 = _e123.xyz;\n let _e126 = unnamed.uHistoryBlend;\n if (_e126 <= 0f) {\n let _e128 = current_1;\n fragColor = vec4<f32>(_e128.x, _e128.y, _e128.z, 1f);\n let _e133 = current_1;\n param_1 = _e133;\n let _e134 = freshRecord_u0028_vf3_u003b((&param_1));\n flickerOut = _e134;\n flickerMotionOut = vec4<f32>(0f, 0f, 0f, 0f);\n return;\n }\n let _e135 = vUv_1;\n nearestAt = _e135;\n let _e136 = vUv_1;\n let _e137 = textureSampleLevel(uDepth_t, uDepth_s, _e136, 0f);\n depth_1 = _e137.x;\n let _e139 = depth_1;\n param_2 = _e139;\n let _e140 = viewDepthOf_u0028_f1_u003b((&param_2));\n metres = _e140;\n y_1 = -1i;\n loop {\n let _e141 = y_1;\n if (_e141 <= 1i) {\n x_1 = -1i;\n loop {\n let _e143 = x_1;\n if (_e143 <= 1i) {\n let _e145 = vUv_1;\n let _e146 = x_1;\n let _e148 = y_1;\n let _e152 = unnamed.uTexel;\n at_1 = (_e145 + (vec2<f32>(f32(_e146), f32(_e148)) * _e152));\n let _e155 = at_1;\n let _e156 = textureSampleLevel(uDepth_t, uDepth_s, _e155, 0f);\n tap = _e156.x;\n let _e158 = tap;\n param_3 = _e158;\n let _e159 = viewDepthOf_u0028_f1_u003b((&param_3));\n tapMetres = _e159;\n let _e160 = tapMetres;\n let _e161 = metres;\n if (_e160 < _e161) {\n let _e163 = tapMetres;\n metres = _e163;\n let _e164 = tap;\n depth_1 = _e164;\n let _e165 = at_1;\n nearestAt = _e165;\n }\n continue;\n } else {\n break;\n }\n continuing {\n let _e166 = x_1;\n x_1 = (_e166 + 1i);\n }\n }\n continue;\n } else {\n break;\n }\n continuing {\n let _e168 = y_1;\n y_1 = (_e168 + 1i);\n }\n }\n let _e170 = nearestAt;\n let _e173 = ((_e170 * 2f) - vec2(1f));\n let _e174 = depth_1;\n clip = vec4<f32>(_e173.x, _e173.y, (1f - (_e174 * 2f)), 1f);\n let _e181 = unnamed.uReprojection;\n let _e182 = clip;\n previous_1 = (_e181 * _e182);\n let _e185 = previous_1[3u];\n if (_e185 <= 0f) {\n let _e187 = current_1;\n fragColor = vec4<f32>(_e187.x, _e187.y, _e187.z, 1f);\n let _e192 = current_1;\n param_4 = _e192;\n let _e193 = freshRecord_u0028_vf3_u003b((&param_4));\n flickerOut = _e193;\n let _e194 = metres;\n flickerMotionOut = vec4<f32>(_e194, 0f, 0f, 0f);\n return;\n }\n let _e196 = vUv_1;\n let _e197 = previous_1;\n let _e200 = previous_1[3u];\n let _e206 = nearestAt;\n wasUv = (_e196 + ((((_e197.xy / vec2(_e200)) * 0.5f) + vec2(0.5f)) - _e206));\n let _e210 = wasUv[0u];\n let _e211 = (_e210 < 0f);\n phi_589_ = _e211;\n if !(_e211) {\n let _e214 = wasUv[0u];\n phi_589_ = (_e214 > 1f);\n }\n let _e217 = phi_589_;\n phi_596_ = _e217;\n if !(_e217) {\n let _e220 = wasUv[1u];\n phi_596_ = (_e220 < 0f);\n }\n let _e223 = phi_596_;\n phi_603_ = _e223;\n if !(_e223) {\n let _e226 = wasUv[1u];\n phi_603_ = (_e226 > 1f);\n }\n let _e229 = phi_603_;\n if _e229 {\n let _e230 = current_1;\n fragColor = vec4<f32>(_e230.x, _e230.y, _e230.z, 1f);\n let _e235 = current_1;\n param_5 = _e235;\n let _e236 = freshRecord_u0028_vf3_u003b((&param_5));\n flickerOut = _e236;\n let _e237 = metres;\n flickerMotionOut = vec4<f32>(_e237, 0f, 0f, 0f);\n return;\n }\n neighbourhood_u0028_vf3_u003b_vf3_u003b((&param_6), (&param_7));\n let _e239 = param_6;\n lo_2 = _e239;\n let _e240 = param_7;\n hi_2 = _e240;\n let _e241 = wasUv;\n param_8 = _e241;\n let _e242 = historyCatmullRom_u0028_vf2_u003b((&param_8));\n history_1 = _e242;\n let _e243 = textureDimensions(uFlicker_t, 0i);\n size_1 = vec2<i32>(_e243);\n let _e245 = wasUv;\n let _e246 = size_1;\n let _e250 = size_1;\n was = clamp(vec2<i32>((_e245 * vec2<f32>(_e246))), vec2<i32>(0i, 0i), (_e250 - vec2(1i)));\n nearest = 1000000000f;\n n = 0i;\n loop {\n let _e254 = n;\n if (_e254 < 5i) {\n let _e256 = was;\n let _e257 = n;\n if (_e257 == 1i) {\n local = vec2<i32>(1i, 0i);\n } else {\n let _e259 = n;\n if (_e259 == 2i) {\n local_1 = vec2<i32>(-1i, 0i);\n } else {\n let _e261 = n;\n if (_e261 == 3i) {\n local_2 = vec2<i32>(0i, 1i);\n } else {\n let _e263 = n;\n local_2 = select(vec2<i32>(0i, 0i), vec2<i32>(0i, -1i), vec2((_e263 == 4i)));\n }\n let _e267 = local_2;\n local_1 = _e267;\n }\n let _e268 = local_1;\n local = _e268;\n }\n let _e269 = local;\n at_2 = (_e256 + _e269);\n let _e271 = at_2;\n let _e272 = size_1;\n let _e276 = textureLoad(uFlickerMotion_t, clamp(_e271, vec2<i32>(0i, 0i), (_e272 - vec2(1i))), 0i);\n stood = _e276.x;\n let _e278 = stood;\n if (_e278 > 0f) {\n let _e280 = nearest;\n let _e281 = stood;\n let _e283 = previous_1[3u];\n nearest = min(_e280, abs((_e281 - _e283)));\n }\n continue;\n } else {\n break;\n }\n continuing {\n let _e287 = n;\n n = (_e287 + 1i);\n }\n }\n let _e289 = was;\n let _e290 = textureLoad(uFlickerMotion_t, _e289, 0i);\n motionThere = _e290;\n let _e291 = nearest;\n missedAll = (_e291 > 100000000f);\n let _e294 = unnamed.uAntiFlicker;\n let _e296 = missedAll;\n let _e298 = ((_e294 > 0.5f) && !(_e296));\n phi_740_ = _e298;\n if _e298 {\n let _e299 = nearest;\n let _e301 = motionThere[1u];\n let _e304 = previous_1[3u];\n phi_740_ = (_e299 <= ((6f * _e301) + (0.02f * _e304)));\n }\n let _e309 = phi_740_;\n same = _e309;\n let _e310 = missedAll;\n if _e310 {\n local_3 = 0f;\n } else {\n let _e312 = motionThere[1u];\n let _e313 = nearest;\n let _e315 = motionThere[1u];\n local_3 = (_e312 + ((_e313 - _e315) * 0.125f));\n }\n let _e319 = local_3;\n swingOut = _e319;\n let _e320 = current_1;\n param_9 = _e320;\n let _e321 = luma_u0028_vf3_u003b((&param_9));\n seen_1 = _e321;\n let _e322 = same;\n if _e322 {\n let _e323 = was;\n let _e324 = textureLoad(uFlicker_t, _e323, 0i);\n local_4 = _e324;\n } else {\n let _e325 = current_1;\n param_10 = _e325;\n let _e326 = freshRecord_u0028_vf3_u003b((&param_10));\n local_4 = _e326;\n }\n let _e327 = local_4;\n held = _e327;\n let _e328 = wasUv;\n let _e329 = vUv_1;\n let _e332 = unnamed.uTexel;\n still = (1f - smoothstep(0.01f, 0.05f, length(((_e328 - _e329) / _e332))));\n let _e337 = seen_1;\n let _e339 = held[2u];\n apart_1 = abs((_e337 - _e339));\n let _e343 = held[0u];\n reach = ((6f * _e343) + 0.003921569f);\n let _e346 = apart_1;\n let _e347 = reach;\n within = (_e346 <= _e347);\n let _e350 = held[3u];\n let _e352 = within;\n proven = ((_e350 > 0.75f) && _e352);\n let _e354 = proven;\n if _e354 {\n let _e356 = held[0u];\n let _e358 = still;\n local_5 = ((6f * _e356) * _e358);\n } else {\n local_5 = 0f;\n }\n let _e360 = local_5;\n widen = _e360;\n let _e361 = proven;\n if _e361 {\n let _e363 = unnamed.uHistoryBlend;\n let _e364 = still;\n local_6 = mix(_e363, 0.97f, _e364);\n } else {\n let _e367 = unnamed.uHistoryBlend;\n local_6 = _e367;\n }\n let _e368 = local_6;\n blend = _e368;\n let _e369 = lo_2;\n let _e370 = widen;\n let _e373 = hi_2;\n let _e374 = widen;\n let _e377 = history_1;\n param_11 = _e377;\n param_12 = (_e369 - vec3(_e370));\n param_13 = (_e373 + vec3(_e374));\n let _e378 = clipToNeighbourhood_u0028_vf3_u003b_vf3_u003b_vf3_u003b((&param_11), (&param_12), (&param_13));\n bounded = _e378;\n let _e380 = held[1u];\n sum_1 = _e380;\n let _e382 = held[2u];\n mean_1 = _e382;\n let _e383 = within;\n if _e383 {\n let _e385 = held[3u];\n local_7 = _e385;\n } else {\n local_7 = 0f;\n }\n let _e386 = local_7;\n repeated = _e386;\n let _e388 = unnamed.uPeriodStart;\n if (_e388 > 0.5f) {\n let _e390 = sum_1;\n param_14 = _e390;\n let _e391 = mean_1;\n param_15 = _e391;\n let _e392 = repeats_u0028_f1_u003b_f1_u003b((&param_14), (&param_15));\n if (_e392 > 0.5f) {\n let _e394 = repeated;\n local_8 = min(1f, (_e394 + 0.5f));\n } else {\n local_8 = 0f;\n }\n let _e397 = local_8;\n repeated = _e397;\n let _e398 = sum_1;\n mean_1 = _e398;\n sum_1 = 0f;\n }\n let _e400 = held[0u];\n let _e401 = apart_1;\n let _e403 = held[0u];\n let _e407 = sum_1;\n let _e408 = seen_1;\n let _e411 = mean_1;\n let _e412 = repeated;\n let _e413 = still;\n flickerOut = vec4<f32>((_e400 + ((_e401 - _e403) * 0.125f)), (_e407 + (_e408 * 0.125f)), _e411, (_e412 * _e413));\n let _e416 = metres;\n let _e417 = swingOut;\n flickerMotionOut = vec4<f32>(_e416, _e417, 0f, 0f);\n let _e419 = current_1;\n let _e420 = bounded;\n let _e421 = blend;\n let _e423 = mix(_e419, _e420, vec3(_e421));\n fragColor = vec4<f32>(_e423.x, _e423.y, _e423.z, 1f);\n return;\n}\n\n@fragment \nfn main(@location(0) vUv: vec2<f32>) -> FragmentOutput {\n vUv_1 = vUv;\n main_1();\n let _e5 = fragColor;\n let _e6 = flickerOut;\n let _e7 = flickerMotionOut;\n return FragmentOutput(_e5, _e6, _e7);\n}\n";
8
8
  /**
9
9
  * What the transform assigned, so the renderer binds the same numbers.
10
10
  *
@@ -13,20 +13,35 @@ export const TEMPORAL_RESOLVE_FRAG_WGSL = "struct Uniforms {\n uReprojection:
13
13
  export const TEMPORALRESOLVE_BINDINGS = {
14
14
  "TEMPORAL_RESOLVE_FRAG": {
15
15
  "uniforms": 1,
16
- "uniformSize": 80,
16
+ "uniformSize": 112,
17
17
  "fields": {
18
- "uReprojection": {
18
+ "uDepthToViewZ": {
19
19
  "offset": 0,
20
+ "size": 16,
21
+ "type": "vec4"
22
+ },
23
+ "uAntiFlicker": {
24
+ "offset": 16,
25
+ "size": 4,
26
+ "type": "float"
27
+ },
28
+ "uReprojection": {
29
+ "offset": 32,
20
30
  "size": 64,
21
31
  "type": "mat4"
22
32
  },
23
33
  "uTexel": {
24
- "offset": 64,
34
+ "offset": 96,
25
35
  "size": 8,
26
36
  "type": "vec2"
27
37
  },
38
+ "uPeriodStart": {
39
+ "offset": 104,
40
+ "size": 4,
41
+ "type": "float"
42
+ },
28
43
  "uHistoryBlend": {
29
- "offset": 72,
44
+ "offset": 108,
30
45
  "size": 4,
31
46
  "type": "float"
32
47
  }
@@ -42,10 +57,20 @@ export const TEMPORALRESOLVE_BINDINGS = {
42
57
  "sampler": 35,
43
58
  "type": "sampler2D"
44
59
  },
45
- "uDepth": {
60
+ "uFlicker": {
46
61
  "texture": 36,
47
62
  "sampler": 37,
48
63
  "type": "sampler2D"
64
+ },
65
+ "uFlickerMotion": {
66
+ "texture": 38,
67
+ "sampler": 39,
68
+ "type": "sampler2D"
69
+ },
70
+ "uDepth": {
71
+ "texture": 40,
72
+ "sampler": 41,
73
+ "type": "sampler2D"
49
74
  }
50
75
  }
51
76
  }
@@ -1,3 +1,4 @@
1
+ import { SUN_DYNAMIC_LAYER, SUN_PEELED_LAYER, SUN_STATIC_LAYER } from '../shadowMap.js';
1
2
  import { glslIsFarDepth, glslSceneDepthToNdc } from '../depthConvention.js';
2
3
  import { MAX_GLOBAL_MEDIUM_STEPS } from '../globalMedium.js';
3
4
  /**
@@ -77,9 +78,8 @@ uniform int uSteps;
77
78
  /** How much of the medium the sun's own shadow map removes, 0 to 1. At 0 nothing is sampled. */
78
79
  uniform float uSunShadow;
79
80
  uniform mat4 uLightViewProj;
80
- uniform sampler2D uStaticShadowMap;
81
- uniform sampler2D uPeeledShadowMap;
82
- uniform sampler2D uDynamicShadowMap;
81
+ /* The sun's static, moving and peeled maps, as layers of one array: see shadowMap.ts. */
82
+ uniform highp sampler2DArray uSunShadows;
83
83
  uniform int uPeeledShadowEnabled;
84
84
 
85
85
  out vec4 fragColor;
@@ -148,11 +148,11 @@ float sunReach(vec3 worldPos) {
148
148
  if (edgeFade <= 0.0) return 1.0;
149
149
 
150
150
  float compare = p.z - SHADOW_BIAS;
151
- float blocked = occlusion(textureLod(uStaticShadowMap, p.xy, 0.0).r, compare);
151
+ float blocked = occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_STATIC_LAYER}.0), 0.0).r, compare);
152
152
  if (uPeeledShadowEnabled != 0) {
153
- blocked = max(blocked, occlusion(textureLod(uPeeledShadowMap, p.xy, 0.0).r, compare));
153
+ blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_PEELED_LAYER}.0), 0.0).r, compare));
154
154
  }
155
- blocked = max(blocked, occlusion(textureLod(uDynamicShadowMap, p.xy, 0.0).r, compare));
155
+ blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_DYNAMIC_LAYER}.0), 0.0).r, compare));
156
156
  return mix(1.0, 1.0 - blocked, uSunShadow * edgeFade);
157
157
  }
158
158
 
@@ -24,3 +24,10 @@ export declare const BLEND_RESOLVE_WGSL = "\n@group(0) @binding(0) var accumMap:
24
24
  * `oitWeight` and `resolveOit` over generated cases.
25
25
  */
26
26
  export declare const BLEND_OIT_PARITY_WGSL = "\n/** Six floats a case: depth, alpha, colour, and the background behind it. */\n@group(0) @binding(0) var<storage, read> cases: array<f32>;\n/** Four out: the weight, and the three resolved channels. */\n@group(0) @binding(1) var<storage, read_write> results: array<f32>;\n\nfn oitWeight(viewDepth: f32, alpha: f32) -> f32 {\n let z = max(viewDepth, 0.0) / 200.0;\n let falloff = 0.03 / (1e-5 + z * z * z * z);\n return alpha * clamp(falloff, 1e-2, 3e3);\n}\n\n/* Premultiplied and weighted, against a blend of \"one, one\": the target holds the two sums. */\nfn oitAccumulate(colour: vec3<f32>, alpha: f32, weight: f32) -> vec4<f32> {\n return vec4<f32>(colour * alpha * weight, alpha * weight);\n}\n\n/*\n * The two targets, as a premultiplied fragment to lay over what is behind them.\n *\n * The weighted sum divided by the weighted alpha is the average colour the layers make, and the\n * revealage says how much of the background still shows. The division is guarded because a pixel no\n * fragment touched has a weighted alpha of zero \u2014 and its revealage of one discards whatever this\n * produces anyway.\n */\nfn oitResolved(accum: vec4<f32>, reveal: f32) -> vec4<f32> {\n let average = accum.xyz / max(accum.w, 1e-5);\n let covered = 1.0 - reveal;\n return vec4<f32>(average * covered, covered);\n}\n\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) id: vec3<u32>) {\n if (id.x * 8u + 7u >= arrayLength(&cases)) { return; }\n let at = id.x * 8u;\n let depth = cases[at];\n let alpha = cases[at + 1u];\n let colour = vec3<f32>(cases[at + 2u], cases[at + 3u], cases[at + 4u]);\n let background = vec3<f32>(cases[at + 5u], cases[at + 6u], cases[at + 7u]);\n\n let weight = oitWeight(depth, alpha);\n /* One fragment folded in, which is the anchor: for a single layer this reduces to \"over\". */\n let accum = oitAccumulate(colour, alpha, weight);\n let reveal = 1.0 - alpha;\n /*\n * The resolve's own fragment, then the blend state applied by hand: the pipeline lays it over\n * the target with \"one, one-minus-src-alpha\", so the background keeps the revealage.\n */\n let over = oitResolved(accum, reveal);\n let resolved = over.xyz + background * (1.0 - over.w);\n\n let out = id.x * 4u;\n results[out] = weight;\n results[out + 1u] = resolved.x;\n results[out + 2u] = resolved.y;\n results[out + 3u] = resolved.z;\n}\n";
27
+ /**
28
+ * `glassShade` alone, as a dispatch, so it can be checked against `gpudriven/lit.ts`.
29
+ *
30
+ * Sixteen floats a case — own, seen, transmission, frost, tint, the view cosine, the glow, one
31
+ * spare — and four out, the colour and one spare.
32
+ */
33
+ export declare const GLASS_SHADE_PARITY_WGSL = "\n@group(0) @binding(0) var<storage, read> cases: array<f32>;\n@group(0) @binding(1) var<storage, read_write> results: array<f32>;\n\nfn glassShade(\n own: vec3<f32>,\n seen: vec3<f32>,\n transmission: f32,\n frost: f32,\n tint: vec3<f32>,\n cosView: f32,\n sunGlow: vec3<f32>,\n) -> vec3<f32> {\n let c = clamp(abs(cosView), 0.05, 1.0);\n let fresnel = 0.04 + 0.96 * pow(1.0 - c, 5.0);\n let shown = transmission * (1.0 - fresnel);\n return own + (seen * tint - own) * shown + sunGlow * tint * (frost * transmission);\n}\n\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) id: vec3<u32>) {\n if (id.x * 16u + 15u >= arrayLength(&cases)) { return; }\n let at = id.x * 16u;\n let own = vec3<f32>(cases[at], cases[at + 1u], cases[at + 2u]);\n let seen = vec3<f32>(cases[at + 3u], cases[at + 4u], cases[at + 5u]);\n let tint = vec3<f32>(cases[at + 8u], cases[at + 9u], cases[at + 10u]);\n let glow = vec3<f32>(cases[at + 12u], cases[at + 13u], cases[at + 14u]);\n let shaded = glassShade(own, seen, cases[at + 6u], cases[at + 7u], tint, cases[at + 11u], glow);\n let out = id.x * 4u;\n results[out] = shaded.x;\n results[out + 1u] = shaded.y;\n results[out + 2u] = shaded.z;\n}\n";
@@ -80,6 +80,27 @@ fn oitResolved(accum: vec4<f32>, reveal: f32) -> vec4<f32> {
80
80
  return vec4<f32>(average * covered, covered);
81
81
  }
82
82
  `;
83
+ /**
84
+ * Glass over its own shading, as the forward path draws it: `gpudriven/lit.ts`'s `glassShade`,
85
+ * which `scripts/gpu-parity.mjs` holds this to. Schlick at 0.04 with the angle unsigned — a pane
86
+ * passes the same light seen from either side — and floored at the forward path's grazing 0.05.
87
+ */
88
+ const GLASS_SHADE_WGSL = /* wgsl */ `
89
+ fn glassShade(
90
+ own: vec3<f32>,
91
+ seen: vec3<f32>,
92
+ transmission: f32,
93
+ frost: f32,
94
+ tint: vec3<f32>,
95
+ cosView: f32,
96
+ sunGlow: vec3<f32>,
97
+ ) -> vec3<f32> {
98
+ let c = clamp(abs(cosView), 0.05, 1.0);
99
+ let fresnel = 0.04 + 0.96 * pow(1.0 - c, 5.0);
100
+ let shown = transmission * (1.0 - fresnel);
101
+ return own + (seen * tint - own) * shown + sunGlow * tint * (frost * transmission);
102
+ }
103
+ `;
83
104
  export const BLEND_RASTER_WGSL = /* wgsl */ `
84
105
  struct BlendVarying {
85
106
  @builtin(position) position: vec4<f32>,
@@ -106,6 +127,12 @@ ${FRAME_BLOCK_WGSL}
106
127
  @group(0) @binding(9) var environmentMap: texture_2d_array<f32>;
107
128
  @group(0) @binding(10) var environmentSampler: sampler;
108
129
  ${decodeResourcesWgsl({ group: 0, latents: 11, clampSampler: 12, repeatSampler: 13, nodes: 14, weights: 15 })}
130
+ /**
131
+ * What the opaque half drew, with a mip chain on a frame whose scene holds glass: a pane shows it,
132
+ * a frosted one a coarser level of it. Read only by a material whose transmission is not zero.
133
+ */
134
+ @group(0) @binding(16) var opaqueColour: texture_2d<f32>;
135
+ @group(0) @binding(17) var opaqueSampler: sampler;
109
136
  fn decodeLatentSize() -> f32 {
110
137
  return frame.size.w;
111
138
  }
@@ -124,6 +151,7 @@ ${MESH_TRANSFORM_WGSL}
124
151
  ${SHADE_LIGHTING_WGSL}
125
152
  ${FOG_WGSL}
126
153
  ${OIT_WGSL}
154
+ ${GLASS_SHADE_WGSL}
127
155
 
128
156
  const NO_PROGRAM_HERE: u32 = ${0xffffffff}u;
129
157
 
@@ -239,7 +267,25 @@ fn blendFrag(in: BlendVarying) -> BlendTargets {
239
267
  * distance — which is the whole reason this pipeline gained a fog.
240
268
  */
241
269
  let toward = distance(in.world, frame.eye.xyz);
242
- let colour = mix(litColour(surface, room), mediumColour(), mediumFog(toward, in.world.y));
270
+ let fog = mediumFog(toward, in.world.y);
271
+ var colour = mix(litColour(surface, room), mediumColour(), fog);
272
+ /*
273
+ * **Glass shows what is behind it**, as the forward path's glass branch does: the opaque half's
274
+ * picture at this pixel, at the level frost picks, two short of the chain's end so a fully frosted
275
+ * pane keeps the large light and dark behind it. The sun glows through from the pane's far side,
276
+ * after the haze as the forward path adds it. A pane is seen from both sides, so its facing is
277
+ * the side toward the eye.
278
+ */
279
+ let transmission = entry.extra.y;
280
+ if (transmission > 0.0) {
281
+ let size = vec2<f32>(textureDimensions(opaqueColour, 0));
282
+ let levels = max(floor(log2(max(size.x, size.y))) - 2.0, 0.0);
283
+ let seen = textureSampleLevel(opaqueColour, opaqueSampler, in.position.xy / size, entry.extra.z * levels).xyz;
284
+ let cosView = dot(surface.normal, toEye);
285
+ let facing = select(surface.normal, -surface.normal, cosView < 0.0);
286
+ let sunGlow = frame.lightColour.xyz * max(-dot(facing, frame.lightDir.xyz), 0.0) * (1.0 - fog);
287
+ colour = glassShade(colour, seen, transmission, entry.extra.z, entry.glassTint.xyz, cosView, sunGlow);
288
+ }
243
289
 
244
290
  /*
245
291
  * **The distance to the eye, not the clip-space depth**, because that is what oitWeight's falloff
@@ -253,6 +299,20 @@ fn blendFrag(in: BlendVarying) -> BlendTargets {
253
299
  out.reveal = vec4<f32>(alpha, 0.0, 0.0, alpha);
254
300
  return out;
255
301
  }
302
+
303
+ /*
304
+ * **What a pane lets through, drawn from the sun into the tint map**: \`blendVert\` again, handed
305
+ * the light's raster matrix and the glass list, and this for the colour — \`glassShadow.ts\`'s
306
+ * paneTexel, the forward path's GLASS_TINT_FRAG in this language. Written against a white target
307
+ * with a multiplying blend and no depth, so every pane on a ray counts in any order.
308
+ */
309
+ @fragment
310
+ fn glassTintFrag(in: BlendVarying) -> @location(0) vec4<f32> {
311
+ let entry = materials[min(in.material, ${MATERIAL_SLOTS - 1}u)];
312
+ let c = clamp(abs(dot(normalize(in.normal), frame.lightDir.xyz)), 0.05, 1.0);
313
+ let passes = entry.extra.y * (1.0 - (0.04 + 0.96 * pow(1.0 - c, 5.0)));
314
+ return vec4<f32>(passes * entry.glassTint.xyz, 1.0 - entry.extra.z);
315
+ }
256
316
  `;
257
317
  /**
258
318
  * The two targets composited over what the opaque half drew.
@@ -337,3 +397,28 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
337
397
  results[out + 3u] = resolved.z;
338
398
  }
339
399
  `;
400
+ /**
401
+ * `glassShade` alone, as a dispatch, so it can be checked against `gpudriven/lit.ts`.
402
+ *
403
+ * Sixteen floats a case — own, seen, transmission, frost, tint, the view cosine, the glow, one
404
+ * spare — and four out, the colour and one spare.
405
+ */
406
+ export const GLASS_SHADE_PARITY_WGSL = /* wgsl */ `
407
+ @group(0) @binding(0) var<storage, read> cases: array<f32>;
408
+ @group(0) @binding(1) var<storage, read_write> results: array<f32>;
409
+ ${GLASS_SHADE_WGSL}
410
+ @compute @workgroup_size(64)
411
+ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
412
+ if (id.x * 16u + 15u >= arrayLength(&cases)) { return; }
413
+ let at = id.x * 16u;
414
+ let own = vec3<f32>(cases[at], cases[at + 1u], cases[at + 2u]);
415
+ let seen = vec3<f32>(cases[at + 3u], cases[at + 4u], cases[at + 5u]);
416
+ let tint = vec3<f32>(cases[at + 8u], cases[at + 9u], cases[at + 10u]);
417
+ let glow = vec3<f32>(cases[at + 12u], cases[at + 13u], cases[at + 14u]);
418
+ let shaded = glassShade(own, seen, cases[at + 6u], cases[at + 7u], tint, cases[at + 11u], glow);
419
+ let out = id.x * 4u;
420
+ results[out] = shaded.x;
421
+ results[out + 1u] = shaded.y;
422
+ results[out + 2u] = shaded.z;
423
+ }
424
+ `;
@@ -43,7 +43,7 @@ export declare const CULL_INSTANCES_WGSL = "\n@group(0) @binding(0) var<storage,
43
43
  * wall and is the whole reason the front half of the pipeline is reusable. A scene with nothing
44
44
  * blended runs this once and the filter costs it one comparison against a uniform.
45
45
  */
46
- export declare const LOD_CUT_WGSL = "\nstruct Params {\n screenHeight: f32,\n fovY: f32,\n thresholdPixels: f32,\n eyeX: f32,\n eyeY: f32,\n eyeZ: f32,\n /** Non-zero to select the blended clusters, zero to select everything else. */\n wantBlend: f32,\n};\n\nstruct Material {\n /** rgb is the tint, w is the emissive gain. */\n tint: vec4<f32>,\n /** x is the roughness, y the specular reflectance, z the environment's and w the metalness. */\n surface: vec4<f32>,\n /** Base colour, normal, ORM and emissive programs; NO_PROGRAM where there is none. */\n programs: vec4<u32>,\n /** u scale, v scale, normal strength, occlusion strength. */\n maps: vec4<f32>,\n /** Roughness scale, metallic scale, the alpha cutoff, and non-zero where this one blends. */\n orm: vec4<f32>,\n /** The blended opacity, and three spare. */\n extra: vec4<f32>,\n}\n\nconst NO_PROGRAM: u32 = 4294967295u;\n\n@group(0) @binding(0) var<storage, read> params: array<f32, 7>;\n/** Six floats a cluster: centre, radius, own error, parent error. */\n@group(0) @binding(1) var<storage, read> clusters: array<f32>;\n@group(0) @binding(2) var<storage, read_write> selected: array<u32>;\n/** Four words a cluster: index offset, index count, identifier, mesh. */\n@group(0) @binding(3) var<storage, read> clusterMeta: array<u32>;\n/** One word a mesh, nonzero where CULL_INSTANCES_WGSL found it wholly outside the view. */\n@group(0) @binding(4) var<storage, read> instanceHidden: array<u32>;\n/** One material a cluster, and the table it indexes. Both only to read one flag. */\n@group(0) @binding(5) var<storage, read> materialOf: array<u32>;\n@group(0) @binding(6) var<uniform> materials: array<Material, 64>;\n\nfn projectedError(error: f32, distance: f32, radius: f32, screenHeight: f32, fovY: f32) -> f32 {\n let safe = max(max(distance, radius), 1e-4);\n let scale = screenHeight / (2.0 * tan(fovY * 0.5));\n return (error * scale) / safe;\n}\n\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) id: vec3<u32>) {\n let i = id.x;\n if (i * 6u + 5u >= arrayLength(&clusters)) { return; }\n /* A hidden mesh contributes nothing, so none of its clusters is in the cut at any level. */\n if (instanceHidden[clusterMeta[i * 4u + 3u]] != 0u) {\n selected[i] = 0u;\n return;\n }\n /*\n * **Which half of the frame this cluster belongs to, asked once.** The two halves are exclusive:\n * a blended cluster is not in the opaque cut and an opaque one is not in the blended cut, so\n * neither is drawn twice and neither is dropped. The flag is read through a uniform by an index\n * that is the same for every cluster of a mesh, so the branch is as coherent as this shader gets.\n */\n let blended = materials[min(materialOf[i], 63u)].orm.w != 0.0;\n if (blended != (params[6] != 0.0)) {\n selected[i] = 0u;\n return;\n }\n let screenHeight = params[0];\n let fovY = params[1];\n let threshold = params[2];\n let eye = vec3<f32>(params[3], params[4], params[5]);\n\n let centre = vec3<f32>(clusters[i * 6u], clusters[i * 6u + 1u], clusters[i * 6u + 2u]);\n let radius = clusters[i * 6u + 3u];\n let ownError = clusters[i * 6u + 4u];\n let parentError = clusters[i * 6u + 5u];\n let distance = length(centre - eye);\n\n let own = projectedError(ownError, distance, radius, screenHeight, fovY);\n let parent = projectedError(parentError, distance, radius, screenHeight, fovY);\n /* Both halves: the first alone draws every ancestor too, the second alone draws nothing. */\n selected[i] = select(0u, 1u, own <= threshold && parent > threshold);\n}\n";
46
+ export declare const LOD_CUT_WGSL = "\nstruct Params {\n screenHeight: f32,\n fovY: f32,\n thresholdPixels: f32,\n eyeX: f32,\n eyeY: f32,\n eyeZ: f32,\n /** Non-zero to select the blended clusters, zero to select everything else. */\n wantBlend: f32,\n /** Non-zero to keep, of those, only glass: what the light's glass pass draws. */\n wantGlass: f32,\n};\n\nstruct Material {\n /** rgb is the tint, w is the emissive gain. */\n tint: vec4<f32>,\n /** x is the roughness, y the specular reflectance, z the environment's and w the metalness. */\n surface: vec4<f32>,\n /** Base colour, normal, ORM and emissive programs; NO_PROGRAM where there is none. */\n programs: vec4<u32>,\n /** u scale, v scale, normal strength, occlusion strength. */\n maps: vec4<f32>,\n /** Roughness scale, metallic scale, the alpha cutoff, and non-zero where this one blends. */\n orm: vec4<f32>,\n /** The blended opacity, the glass's transmission and frost, and one spare. */\n extra: vec4<f32>,\n /** The glass's tint, white where the material is not glass, and one spare. */\n glassTint: vec4<f32>,\n}\n\nconst NO_PROGRAM: u32 = 4294967295u;\n\n@group(0) @binding(0) var<storage, read> params: array<f32, 8>;\n/** Six floats a cluster: centre, radius, own error, parent error. */\n@group(0) @binding(1) var<storage, read> clusters: array<f32>;\n@group(0) @binding(2) var<storage, read_write> selected: array<u32>;\n/** Four words a cluster: index offset, index count, identifier, mesh. */\n@group(0) @binding(3) var<storage, read> clusterMeta: array<u32>;\n/** One word a mesh, nonzero where CULL_INSTANCES_WGSL found it wholly outside the view. */\n@group(0) @binding(4) var<storage, read> instanceHidden: array<u32>;\n/** One material a cluster, and the table it indexes. Both only to read one flag. */\n@group(0) @binding(5) var<storage, read> materialOf: array<u32>;\n@group(0) @binding(6) var<uniform> materials: array<Material, 64>;\n\nfn projectedError(error: f32, distance: f32, radius: f32, screenHeight: f32, fovY: f32) -> f32 {\n let safe = max(max(distance, radius), 1e-4);\n let scale = screenHeight / (2.0 * tan(fovY * 0.5));\n return (error * scale) / safe;\n}\n\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) id: vec3<u32>) {\n let i = id.x;\n if (i * 6u + 5u >= arrayLength(&clusters)) { return; }\n /* A hidden mesh contributes nothing, so none of its clusters is in the cut at any level. */\n if (instanceHidden[clusterMeta[i * 4u + 3u]] != 0u) {\n selected[i] = 0u;\n return;\n }\n /*\n * **Which half of the frame this cluster belongs to, asked once.** The two halves are exclusive:\n * a blended cluster is not in the opaque cut and an opaque one is not in the blended cut, so\n * neither is drawn twice and neither is dropped. The flag is read through a uniform by an index\n * that is the same for every cluster of a mesh, so the branch is as coherent as this shader gets.\n */\n let material = materials[min(materialOf[i], 63u)];\n let blended = material.orm.w != 0.0;\n if (blended != (params[6] != 0.0)) {\n selected[i] = 0u;\n return;\n }\n /* The light's glass pass: a blended surface that is not glass casts nothing, as on the forward\n path, so only a material letting light through is kept. */\n if (params[7] != 0.0 && material.extra.y <= 0.0) {\n selected[i] = 0u;\n return;\n }\n let screenHeight = params[0];\n let fovY = params[1];\n let threshold = params[2];\n let eye = vec3<f32>(params[3], params[4], params[5]);\n\n let centre = vec3<f32>(clusters[i * 6u], clusters[i * 6u + 1u], clusters[i * 6u + 2u]);\n let radius = clusters[i * 6u + 3u];\n let ownError = clusters[i * 6u + 4u];\n let parentError = clusters[i * 6u + 5u];\n let distance = length(centre - eye);\n\n let own = projectedError(ownError, distance, radius, screenHeight, fovY);\n let parent = projectedError(parentError, distance, radius, screenHeight, fovY);\n /* Both halves: the first alone draws every ancestor too, the second alone draws nothing. */\n selected[i] = select(0u, 1u, own <= threshold && parent > threshold);\n}\n";
47
47
  /**
48
48
  * The pyramid's base level, copied out of the depth attachment a phase drew into.
49
49
  *
@@ -100,9 +100,11 @@ struct Params {
100
100
  eyeZ: f32,
101
101
  /** Non-zero to select the blended clusters, zero to select everything else. */
102
102
  wantBlend: f32,
103
+ /** Non-zero to keep, of those, only glass: what the light's glass pass draws. */
104
+ wantGlass: f32,
103
105
  };
104
106
  ${MATERIAL_TABLE_WGSL}
105
- @group(0) @binding(0) var<storage, read> params: array<f32, 7>;
107
+ @group(0) @binding(0) var<storage, read> params: array<f32, 8>;
106
108
  /** Six floats a cluster: centre, radius, own error, parent error. */
107
109
  @group(0) @binding(1) var<storage, read> clusters: array<f32>;
108
110
  @group(0) @binding(2) var<storage, read_write> selected: array<u32>;
@@ -135,11 +137,18 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
135
137
  * neither is drawn twice and neither is dropped. The flag is read through a uniform by an index
136
138
  * that is the same for every cluster of a mesh, so the branch is as coherent as this shader gets.
137
139
  */
138
- let blended = materials[min(materialOf[i], ${MATERIAL_SLOTS - 1}u)].orm.w != 0.0;
140
+ let material = materials[min(materialOf[i], ${MATERIAL_SLOTS - 1}u)];
141
+ let blended = material.orm.w != 0.0;
139
142
  if (blended != (params[6] != 0.0)) {
140
143
  selected[i] = 0u;
141
144
  return;
142
145
  }
146
+ /* The light's glass pass: a blended surface that is not glass casts nothing, as on the forward
147
+ path, so only a material letting light through is kept. */
148
+ if (params[7] != 0.0 && material.extra.y <= 0.0) {
149
+ selected[i] = 0u;
150
+ return;
151
+ }
143
152
  let screenHeight = params[0];
144
153
  let fovY = params[1];
145
154
  let threshold = params[2];
@@ -22,4 +22,4 @@
22
22
  */
23
23
  export declare const MATERIAL_SLOTS = 64;
24
24
  /** The struct and the sentinel, for any module that binds the table. */
25
- export declare const MATERIAL_TABLE_WGSL = "\nstruct Material {\n /** rgb is the tint, w is the emissive gain. */\n tint: vec4<f32>,\n /** x is the roughness, y the specular reflectance, z the environment's and w the metalness. */\n surface: vec4<f32>,\n /** Base colour, normal, ORM and emissive programs; NO_PROGRAM where there is none. */\n programs: vec4<u32>,\n /** u scale, v scale, normal strength, occlusion strength. */\n maps: vec4<f32>,\n /** Roughness scale, metallic scale, the alpha cutoff, and non-zero where this one blends. */\n orm: vec4<f32>,\n /** The blended opacity, and three spare. */\n extra: vec4<f32>,\n}\n\nconst NO_PROGRAM: u32 = 4294967295u;\n";
25
+ export declare const MATERIAL_TABLE_WGSL = "\nstruct Material {\n /** rgb is the tint, w is the emissive gain. */\n tint: vec4<f32>,\n /** x is the roughness, y the specular reflectance, z the environment's and w the metalness. */\n surface: vec4<f32>,\n /** Base colour, normal, ORM and emissive programs; NO_PROGRAM where there is none. */\n programs: vec4<u32>,\n /** u scale, v scale, normal strength, occlusion strength. */\n maps: vec4<f32>,\n /** Roughness scale, metallic scale, the alpha cutoff, and non-zero where this one blends. */\n orm: vec4<f32>,\n /** The blended opacity, the glass's transmission and frost, and one spare. */\n extra: vec4<f32>,\n /** The glass's tint, white where the material is not glass, and one spare. */\n glassTint: vec4<f32>,\n}\n\nconst NO_PROGRAM: u32 = 4294967295u;\n";
@@ -35,8 +35,10 @@ struct Material {
35
35
  maps: vec4<f32>,
36
36
  /** Roughness scale, metallic scale, the alpha cutoff, and non-zero where this one blends. */
37
37
  orm: vec4<f32>,
38
- /** The blended opacity, and three spare. */
38
+ /** The blended opacity, the glass's transmission and frost, and one spare. */
39
39
  extra: vec4<f32>,
40
+ /** The glass's tint, white where the material is not glass, and one spare. */
41
+ glassTint: vec4<f32>,
40
42
  }
41
43
 
42
44
  const NO_PROGRAM: u32 = ${DECODE_NO_PROGRAM}u;
@@ -8,6 +8,7 @@ import { MATERIAL_SLOTS, MATERIAL_TABLE_WGSL } from './materialTable.wgsl.js';
8
8
  import { MESH_TRANSFORM_WGSL } from './meshTransform.wgsl.js';
9
9
  import { ENVIRONMENT_WGSL } from './environment.wgsl.js';
10
10
  import { SHADE_SHADOW_WGSL } from './shadow.wgsl.js';
11
+ import { SUN_GLASS_WGSL } from './sunGlass.wgsl.js';
11
12
  /**
12
13
  * Rebuilding a pixel's surface from the triangle it recorded, on the device.
13
14
  *
@@ -509,6 +510,14 @@ struct Job {
509
510
  @group(0) @binding(12) var environmentMap: texture_2d_array<f32>;
510
511
  @group(0) @binding(13) var environmentSampler: sampler;
511
512
  ${decodeResourcesWgsl({ group: 0, latents: 14, clampSampler: 15, repeatSampler: 16, nodes: 17, weights: 18 })}
513
+ /*
514
+ * **What the sun keeps through glass: the nearest pane's depth and what the panes let through**,
515
+ * which the pass draws from the sun after its opaque map. Where no material is glass the depth is
516
+ * the opaque map again and the tint a single white texel, which sunGlassAt reads as none.
517
+ */
518
+ @group(0) @binding(19) var glassDepthMap: texture_depth_2d;
519
+ @group(0) @binding(20) var glassTints: texture_2d<f32>;
520
+ @group(0) @binding(21) var glassSampler: sampler;
512
521
 
513
522
  fn decodeLatentSize() -> f32 {
514
523
  return frame.size.w;
@@ -540,6 +549,45 @@ fn shadowDepthAt(u: f32, v: f32) -> f32 {
540
549
  return textureLoad(shadowMap, vec2<i32>(x, y), 0);
541
550
  }
542
551
  ${SHADE_SHADOW_WGSL}
552
+
553
+ /* sunGlass.wgsl.ts's three reads, as the opaque map is read: nearest by integer coordinate. */
554
+ fn glassDepthAt(u: f32, v: f32) -> f32 {
555
+ let size = frame.shadow.y;
556
+ let x = i32(clamp(floor(u * size), 0.0, size - 1.0));
557
+ let y = i32(clamp(floor(v * size), 0.0, size - 1.0));
558
+ return textureLoad(glassDepthMap, vec2<i32>(x, y), 0);
559
+ }
560
+
561
+ fn glassTintTexel(u: f32, v: f32) -> vec4<f32> {
562
+ let size = f32(textureDimensions(glassTints, 0).x);
563
+ let x = i32(clamp(floor(u * size), 0.0, size - 1.0));
564
+ let y = i32(clamp(floor(v * size), 0.0, size - 1.0));
565
+ return textureLoad(glassTints, vec2<i32>(x, y), 0);
566
+ }
567
+
568
+ /* The tint over a spread, from the chain: the level whose texel is the spread's width. */
569
+ fn glassTintAround(u: f32, v: f32, radius: f32) -> vec4<f32> {
570
+ let size = f32(textureDimensions(glassTints, 0).x);
571
+ return textureSampleLevel(glassTints, glassSampler, vec2<f32>(u, v), log2(max(radius * size, 1.0)));
572
+ }
573
+ ${SUN_GLASS_WGSL}
574
+
575
+ /*
576
+ * The sun's colour at this receiver after the panes between it and the sun: white where no glass
577
+ * cast, and faded with the opaque shadow's own strength. The map's scale in metres comes off the
578
+ * light's matrix, which is orthographic: a compute invocation has no derivatives to take it from.
579
+ */
580
+ fn sunGlassAt(lightPos: vec3<f32>) -> vec3<f32> {
581
+ if (textureDimensions(glassTints, 0).x <= 1u || frame.shadow.x <= 0.0) { return vec3<f32>(1.0); }
582
+ let m = frame.lightViewProj;
583
+ var settings: SunGlassSettings;
584
+ settings.mapSize = frame.shadow.y;
585
+ settings.depthSpan = frame.shadow.z;
586
+ settings.uvPerMetre = 0.5 * length(vec3<f32>(m[0][0], m[1][0], m[2][0]));
587
+ settings.taps = frame.shadowLimits.y;
588
+ let tint = sunGlass(lightPos.x * 0.5 + 0.5, lightPos.y * 0.5 + 0.5, lightPos.z, settings);
589
+ return mix(vec3<f32>(1.0), tint, frame.shadow.x);
590
+ }
543
591
  ${ENVIRONMENT_WGSL}
544
592
  ${FOG_WGSL}
545
593
 
@@ -732,7 +780,8 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
732
780
 
733
781
  var room: LitEnvironment;
734
782
  room.lightDir = frame.lightDir.xyz;
735
- room.lightColour = frame.lightColour.xyz;
783
+ /* The sun's colour through whatever glass stands between it and here, as flat/main.ts's is. */
784
+ room.lightColour = frame.lightColour.xyz * sunGlassAt(lightPos);
736
785
  room.sky = frame.sky.xyz;
737
786
  room.ground = frame.ground.xyz;
738
787
  /*
@@ -0,0 +1,9 @@
1
+ export declare const SUN_GLASS_WGSL: string;
2
+ /**
3
+ * `sunGlass` over maps held in storage buffers, read as the reference reads them, so the whole
4
+ * lookup can be compared with `glassTintAt` rather than only the arithmetic between the reads.
5
+ *
6
+ * Four floats a case in — u, v, the receiver's depth, one spare — and four out, the tint and one
7
+ * spare. The config is the map's size, the depth span, map units a metre, and the tap count.
8
+ */
9
+ export declare const SUN_GLASS_PARITY_WGSL: string;
@@ -0,0 +1,133 @@
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.js';
13
+ import { SHADOW_DEPTH_BIAS, SHADOW_PCF_OFFSETS, SHADOW_TEXEL_SCALE, } from '../../gpudriven/shadow.js';
14
+ import { SHADE_SHADOW_WGSL } from './shadow.wgsl.js';
15
+ export const SUN_GLASS_WGSL = /* wgsl */ `
16
+ struct SunGlassSettings {
17
+ mapSize: f32,
18
+ depthSpan: f32,
19
+ uvPerMetre: f32,
20
+ taps: f32,
21
+ }
22
+
23
+ /*
24
+ * A coarse texel with the open ground's white taken back out, by how milky the pane at the
25
+ * receiver is: the pane's colour and its share of the texel. glassShadow.ts's unmixTint.
26
+ */
27
+ fn sunGlassUnmix(mip: vec4<f32>, centreClarity: f32) -> vec4<f32> {
28
+ if (centreClarity >= 1.0) { return vec4<f32>(mip.xyz, 1.0); }
29
+ let share = clamp((1.0 - mip.w) / (1.0 - centreClarity), 0.0, 1.0);
30
+ if (share <= 0.0) { return vec4<f32>(1.0, 1.0, 1.0, 0.0); }
31
+ let colour = clamp((mip.xyz - vec3<f32>(1.0 - share)) / share, vec3<f32>(0.0), vec3<f32>(1.0));
32
+ return vec4<f32>(colour, share);
33
+ }
34
+
35
+ /* What the sun keeps through glass at map position (u, v) and light depth "depth". */
36
+ fn sunGlass(u: f32, v: f32, depth: f32, settings: SunGlassSettings) -> vec3<f32> {
37
+ if (u < 0.0 || u > 1.0 || v < 0.0 || v > 1.0) { return vec3<f32>(1.0); }
38
+ let texel = ${SHADOW_TEXEL_SCALE.toFixed(4)} / settings.mapSize;
39
+ let bias = ${SHADOW_DEPTH_BIAS.toFixed(4)} / settings.depthSpan;
40
+ let taps = min(u32(settings.taps), ${SHADOW_PCF_OFFSETS.length}u);
41
+ let clarity = glassTintTexel(u, v).w;
42
+ let behind = max(depth - glassDepthAt(u, v), 0.0) * settings.depthSpan;
43
+ let spread = (1.0 - clarity) * ${FROST_SPREAD.toFixed(6)} * behind * settings.uvPerMetre;
44
+ let radius = min(max(texel, spread), texel * ${FROST_RADIUS_CAP.toFixed(1)});
45
+
46
+ var cover = 0.0;
47
+ var colour = vec3<f32>(0.0);
48
+ var found = 0.0;
49
+ for (var i = 0u; i < taps; i = i + 1u) {
50
+ let offset = SHADOW_TAPS[i];
51
+ /* The outline: a tap counts the pane only where the receiver is behind it, by the bias. */
52
+ if (depth > glassDepthAt(u + offset.x * texel, v + offset.y * texel) + bias) {
53
+ cover = cover + 1.0;
54
+ }
55
+ /* The colour: the spread's taps, each an average, unmixed and weighed by the pane's share. */
56
+ let pane = sunGlassUnmix(glassTintAround(u + offset.x * radius, v + offset.y * radius, radius), clarity);
57
+ colour = colour + pane.xyz * pane.w;
58
+ found = found + pane.w;
59
+ }
60
+ let mixed = select(vec3<f32>(1.0), colour / max(found, 1e-6), found > 0.0);
61
+ return mix(vec3<f32>(1.0), mixed, cover / f32(max(taps, 1u)));
62
+ }
63
+ `;
64
+ /**
65
+ * `sunGlass` over maps held in storage buffers, read as the reference reads them, so the whole
66
+ * lookup can be compared with `glassTintAt` rather than only the arithmetic between the reads.
67
+ *
68
+ * Four floats a case in — u, v, the receiver's depth, one spare — and four out, the tint and one
69
+ * spare. The config is the map's size, the depth span, map units a metre, and the tap count.
70
+ */
71
+ export const SUN_GLASS_PARITY_WGSL = /* wgsl */ `
72
+ @group(0) @binding(0) var<storage, read> depths: array<f32>;
73
+ @group(0) @binding(1) var<storage, read> tints: array<f32>;
74
+ @group(0) @binding(2) var<storage, read> cases: array<f32>;
75
+ @group(0) @binding(3) var<storage, read> config: array<f32>;
76
+ @group(0) @binding(4) var<storage, read_write> results: array<f32>;
77
+
78
+ /* The opaque lookup's own read, which this entry never calls: included only for its tap table. */
79
+ fn shadowDepthAt(u: f32, v: f32) -> f32 { return 1.0; }
80
+ ${SHADE_SHADOW_WGSL}
81
+
82
+ fn glassIndex(u: f32, v: f32) -> u32 {
83
+ let size = config[0];
84
+ let x = u32(clamp(floor(u * size), 0.0, size - 1.0));
85
+ let y = u32(clamp(floor(v * size), 0.0, size - 1.0));
86
+ return y * u32(size) + x;
87
+ }
88
+
89
+ fn glassDepthAt(u: f32, v: f32) -> f32 {
90
+ return depths[glassIndex(u, v)];
91
+ }
92
+
93
+ fn glassTintTexel(u: f32, v: f32) -> vec4<f32> {
94
+ let at = glassIndex(u, v) * 4u;
95
+ return vec4<f32>(tints[at], tints[at + 1u], tints[at + 2u], tints[at + 3u]);
96
+ }
97
+
98
+ /* The reference's coarse read: the average of every texel within the radius. */
99
+ fn glassTintAround(u: f32, v: f32, radius: f32) -> vec4<f32> {
100
+ let size = config[0];
101
+ let reach = radius * size;
102
+ let x0 = u32(max(0.0, floor(u * size - reach)));
103
+ let x1 = u32(min(size - 1.0, floor(u * size + reach)));
104
+ let y0 = u32(max(0.0, floor(v * size - reach)));
105
+ let y1 = u32(min(size - 1.0, floor(v * size + reach)));
106
+ var sum = vec4<f32>(0.0);
107
+ var n = 0.0;
108
+ for (var y = y0; y <= y1; y = y + 1u) {
109
+ for (var x = x0; x <= x1; x = x + 1u) {
110
+ let at = (y * u32(size) + x) * 4u;
111
+ sum = sum + vec4<f32>(tints[at], tints[at + 1u], tints[at + 2u], tints[at + 3u]);
112
+ n = n + 1.0;
113
+ }
114
+ }
115
+ return sum / max(n, 1.0);
116
+ }
117
+ ${SUN_GLASS_WGSL}
118
+
119
+ @compute @workgroup_size(64)
120
+ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
121
+ if (id.x * 4u + 3u >= arrayLength(&cases)) { return; }
122
+ var settings: SunGlassSettings;
123
+ settings.mapSize = config[0];
124
+ settings.depthSpan = config[1];
125
+ settings.uvPerMetre = config[2];
126
+ settings.taps = config[3];
127
+ let at = id.x * 4u;
128
+ let tint = sunGlass(cases[at], cases[at + 1u], cases[at + 2u], settings);
129
+ results[at] = tint.x;
130
+ results[at + 1u] = tint.y;
131
+ results[at + 2u] = tint.z;
132
+ }
133
+ `;