@driftengine/core 4.8.5 → 4.8.7

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 (214) hide show
  1. package/CHANGELOG.json +4392 -4250
  2. package/README.md +1 -1
  3. package/dist/index.d.ts +12 -4
  4. package/dist/index.js +12 -2
  5. package/dist/render/ambientHarmonics.d.ts +46 -0
  6. package/dist/render/ambientHarmonics.js +80 -0
  7. package/dist/render/anisotropicLobe.d.ts +10 -0
  8. package/dist/render/anisotropicLobe.js +19 -0
  9. package/dist/render/areaLights.d.ts +54 -0
  10. package/dist/render/areaLights.js +55 -0
  11. package/dist/render/backend/api.d.ts +43 -2
  12. package/dist/render/backend/webgl2/instanced.d.ts +2 -0
  13. package/dist/render/backend/webgl2/instanced.js +11 -2
  14. package/dist/render/backend/webgl2/renderer.d.ts +120 -11
  15. package/dist/render/backend/webgl2/renderer.js +356 -53
  16. package/dist/render/backend/webgl2/sceneCaptureTarget.d.ts +29 -0
  17. package/dist/render/backend/webgl2/sceneCaptureTarget.js +96 -0
  18. package/dist/render/backend/webgl2/skinScatter.d.ts +14 -0
  19. package/dist/render/backend/webgl2/skinScatter.js +88 -26
  20. package/dist/render/backend/webgpu/buffers.js +2 -1
  21. package/dist/render/backend/webgpu/clusterBinner.js +3 -2
  22. package/dist/render/backend/webgpu/flatPass.d.ts +7 -5
  23. package/dist/render/backend/webgpu/flatPass.js +15 -13
  24. package/dist/render/backend/webgpu/particlePass.d.ts +37 -4
  25. package/dist/render/backend/webgpu/particlePass.js +81 -12
  26. package/dist/render/backend/webgpu/postPass.d.ts +6 -1
  27. package/dist/render/backend/webgpu/postPass.js +7 -2
  28. package/dist/render/backend/webgpu/renderer.d.ts +93 -8
  29. package/dist/render/backend/webgpu/renderer.js +483 -93
  30. package/dist/render/backend/webgpu/sceneCaptureTarget.d.ts +24 -0
  31. package/dist/render/backend/webgpu/sceneCaptureTarget.js +59 -0
  32. package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.d.ts +1 -1
  33. package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.js +41 -1
  34. package/dist/render/backend/webgpu/skinPaletteRing.d.ts +40 -28
  35. package/dist/render/backend/webgpu/skinPaletteRing.js +69 -32
  36. package/dist/render/backend/webgpu/skinScatterPass.d.ts +10 -2
  37. package/dist/render/backend/webgpu/skinScatterPass.js +59 -9
  38. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +5 -1
  39. package/dist/render/backend/webgpu/surfaceTexturePass.js +45 -5
  40. package/dist/render/backend/webgpu/waterPass.d.ts +1 -1
  41. package/dist/render/bloomChain.d.ts +44 -0
  42. package/dist/render/bloomChain.js +28 -0
  43. package/dist/render/bloomPass.d.ts +3 -1
  44. package/dist/render/bloomPass.js +16 -2
  45. package/dist/render/clusteredLights.d.ts +78 -6
  46. package/dist/render/clusteredLights.js +214 -13
  47. package/dist/render/driftLight/bake.d.ts +2 -0
  48. package/dist/render/driftLight/bake.js +1 -1
  49. package/dist/render/driftLight/falloff.d.ts +4 -2
  50. package/dist/render/driftLight/falloff.js +8 -2
  51. package/dist/render/fixtureAtlas.js +1 -1
  52. package/dist/render/gi/bounceLights.d.ts +3 -2
  53. package/dist/render/gi/bounceLights.js +8 -3
  54. package/dist/render/instanceCull.js +12 -0
  55. package/dist/render/instances.d.ts +47 -11
  56. package/dist/render/instances.js +24 -9
  57. package/dist/render/lightBudget.d.ts +38 -2
  58. package/dist/render/lightBudget.js +48 -5
  59. package/dist/render/lightmap.d.ts +116 -0
  60. package/dist/render/lightmap.js +140 -0
  61. package/dist/render/mesh.js +2 -1
  62. package/dist/render/particleBatch.d.ts +59 -3
  63. package/dist/render/particleBatch.js +53 -2
  64. package/dist/render/particleMaterial.d.ts +6 -1
  65. package/dist/render/particleMaterial.js +10 -2
  66. package/dist/render/particlePool.d.ts +32 -0
  67. package/dist/render/particlePool.js +9 -0
  68. package/dist/render/particleSort.d.ts +34 -0
  69. package/dist/render/particleSort.js +96 -0
  70. package/dist/render/pointLightSelection.d.ts +13 -0
  71. package/dist/render/pointLightSelection.js +3 -1
  72. package/dist/render/renderQuality.d.ts +8 -7
  73. package/dist/render/rendererHarness.js +3 -0
  74. package/dist/render/rgb9e5.d.ts +22 -0
  75. package/dist/render/rgb9e5.js +47 -0
  76. package/dist/render/sceneCapture.d.ts +29 -0
  77. package/dist/render/sceneCapture.js +36 -0
  78. package/dist/render/sceneTarget.d.ts +5 -0
  79. package/dist/render/sceneTarget.js +8 -1
  80. package/dist/render/screenSpaceReflection.d.ts +27 -1
  81. package/dist/render/screenSpaceReflection.js +9 -0
  82. package/dist/render/shaders/bloom.d.ts +8 -4
  83. package/dist/render/shaders/bloom.js +20 -3
  84. package/dist/render/shaders/bolt.d.ts +1 -1
  85. package/dist/render/shaders/bolt.js +7 -1
  86. package/dist/render/shaders/depth.js +11 -0
  87. package/dist/render/shaders/flat/anisotropic.d.ts +1 -1
  88. package/dist/render/shaders/flat/anisotropic.js +37 -3
  89. package/dist/render/shaders/flat/areaLight.d.ts +10 -0
  90. package/dist/render/shaders/flat/areaLight.js +142 -0
  91. package/dist/render/shaders/flat/glassTint.d.ts +3 -2
  92. package/dist/render/shaders/flat/glassTint.js +3 -1
  93. package/dist/render/shaders/flat/index.d.ts +5 -0
  94. package/dist/render/shaders/flat/index.js +46 -6
  95. package/dist/render/shaders/flat/lobes.d.ts +6 -0
  96. package/dist/render/shaders/flat/lobes.js +49 -43
  97. package/dist/render/shaders/flat/main.d.ts +1 -1
  98. package/dist/render/shaders/flat/main.js +158 -121
  99. package/dist/render/shaders/flat/models.d.ts +21 -6
  100. package/dist/render/shaders/flat/models.js +161 -17
  101. package/dist/render/shaders/flat/normalMap.d.ts +10 -0
  102. package/dist/render/shaders/flat/normalMap.js +25 -0
  103. package/dist/render/shaders/flat/preamble.js +84 -40
  104. package/dist/render/shaders/flat/skin.js +6 -5
  105. package/dist/render/shaders/generated/bloom.wgsl.d.ts +13 -3
  106. package/dist/render/shaders/generated/bloom.wgsl.js +13 -3
  107. package/dist/render/shaders/generated/bolt.wgsl.d.ts +1 -1
  108. package/dist/render/shaders/generated/bolt.wgsl.js +1 -1
  109. package/dist/render/shaders/generated/depth.wgsl.d.ts +4 -4
  110. package/dist/render/shaders/generated/depth.wgsl.js +4 -4
  111. package/dist/render/shaders/generated/flat.wgsl.d.ts +1647 -2044
  112. package/dist/render/shaders/generated/flat.wgsl.js +1685 -2082
  113. package/dist/render/shaders/generated/particle.wgsl.d.ts +115 -1
  114. package/dist/render/shaders/generated/particle.wgsl.js +115 -1
  115. package/dist/render/shaders/generated/skinBlur.wgsl.d.ts +12 -2
  116. package/dist/render/shaders/generated/skinBlur.wgsl.js +12 -2
  117. package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +11 -6
  118. package/dist/render/shaders/generated/ssrTrace.wgsl.js +11 -6
  119. package/dist/render/shaders/generated/water.wgsl.d.ts +23 -16
  120. package/dist/render/shaders/generated/water.wgsl.js +23 -16
  121. package/dist/render/shaders/gi/probeBake.wgsl.js +9 -5
  122. package/dist/render/shaders/particle.d.ts +17 -1
  123. package/dist/render/shaders/particle.js +133 -1
  124. package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
  125. package/dist/render/shaders/recon/motion.wgsl.js +13 -2
  126. package/dist/render/shaders/skinBlur.js +25 -3
  127. package/dist/render/shaders/ssrTrace.js +20 -1
  128. package/dist/render/shaders/water.d.ts +1 -1
  129. package/dist/render/shaders/water.js +12 -3
  130. package/dist/render/skinBlur.d.ts +8 -5
  131. package/dist/render/skinBlur.js +8 -5
  132. package/dist/render/skinScatter.d.ts +3 -1
  133. package/dist/render/skinScatter.js +3 -1
  134. package/dist/render/ssrPass.js +1 -0
  135. package/dist/render/surfaceModel.d.ts +49 -8
  136. package/dist/render/surfaceModel.js +54 -8
  137. package/dist/render/surfaceTexture.d.ts +38 -1
  138. package/dist/render/surfaceTexture.js +37 -2
  139. package/package.json +6 -6
  140. package/src/index.ts +26 -3
  141. package/src/render/ambientHarmonics.ts +92 -0
  142. package/src/render/anisotropicLobe.ts +29 -0
  143. package/src/render/areaLights.ts +97 -0
  144. package/src/render/backend/api.ts +61 -1
  145. package/src/render/backend/webgl2/instanced.ts +12 -2
  146. package/src/render/backend/webgl2/renderer.ts +470 -59
  147. package/src/render/backend/webgl2/sceneCaptureTarget.ts +130 -0
  148. package/src/render/backend/webgl2/skinScatter.ts +120 -43
  149. package/src/render/backend/webgpu/buffers.ts +2 -1
  150. package/src/render/backend/webgpu/clusterBinner.ts +3 -1
  151. package/src/render/backend/webgpu/flatPass.ts +18 -13
  152. package/src/render/backend/webgpu/particlePass.ts +119 -12
  153. package/src/render/backend/webgpu/postPass.ts +7 -2
  154. package/src/render/backend/webgpu/renderer.ts +589 -113
  155. package/src/render/backend/webgpu/sceneCaptureTarget.ts +63 -0
  156. package/src/render/backend/webgpu/shaders/clusterBin.wgsl.ts +41 -1
  157. package/src/render/backend/webgpu/skinPaletteRing.ts +65 -33
  158. package/src/render/backend/webgpu/skinScatterPass.ts +59 -9
  159. package/src/render/backend/webgpu/surfaceTexturePass.ts +57 -6
  160. package/src/render/bloomChain.ts +69 -0
  161. package/src/render/bloomPass.ts +26 -2
  162. package/src/render/clusteredLights.ts +259 -12
  163. package/src/render/driftLight/bake.ts +3 -1
  164. package/src/render/driftLight/falloff.ts +13 -2
  165. package/src/render/fixtureAtlas.ts +1 -1
  166. package/src/render/gi/bounceLights.ts +12 -3
  167. package/src/render/instanceCull.ts +9 -0
  168. package/src/render/instances.ts +61 -12
  169. package/src/render/lightBudget.ts +88 -4
  170. package/src/render/lightmap.ts +243 -0
  171. package/src/render/mesh.ts +2 -1
  172. package/src/render/particleBatch.ts +95 -4
  173. package/src/render/particleMaterial.ts +11 -1
  174. package/src/render/particlePool.ts +36 -0
  175. package/src/render/particleSort.ts +133 -0
  176. package/src/render/pointLightSelection.ts +20 -1
  177. package/src/render/renderQuality.ts +8 -7
  178. package/src/render/rendererHarness.ts +3 -0
  179. package/src/render/rgb9e5.ts +52 -0
  180. package/src/render/sceneCapture.ts +56 -0
  181. package/src/render/sceneTarget.ts +18 -1
  182. package/src/render/screenSpaceReflection.ts +33 -1
  183. package/src/render/shaders/bloom.ts +20 -3
  184. package/src/render/shaders/bolt.ts +7 -1
  185. package/src/render/shaders/depth.ts +11 -0
  186. package/src/render/shaders/flat/anisotropic.ts +37 -3
  187. package/src/render/shaders/flat/areaLight.ts +142 -0
  188. package/src/render/shaders/flat/glassTint.ts +9 -2
  189. package/src/render/shaders/flat/index.ts +51 -6
  190. package/src/render/shaders/flat/lobes.ts +50 -43
  191. package/src/render/shaders/flat/main.ts +158 -121
  192. package/src/render/shaders/flat/models.ts +170 -21
  193. package/src/render/shaders/flat/normalMap.ts +25 -0
  194. package/src/render/shaders/flat/preamble.ts +84 -40
  195. package/src/render/shaders/flat/skin.ts +6 -5
  196. package/src/render/shaders/generated/bloom.wgsl.ts +13 -3
  197. package/src/render/shaders/generated/bolt.wgsl.ts +1 -1
  198. package/src/render/shaders/generated/depth.wgsl.ts +4 -4
  199. package/src/render/shaders/generated/flat.wgsl.ts +1685 -2082
  200. package/src/render/shaders/generated/particle.wgsl.ts +116 -1
  201. package/src/render/shaders/generated/skinBlur.wgsl.ts +12 -2
  202. package/src/render/shaders/generated/ssrTrace.wgsl.ts +11 -6
  203. package/src/render/shaders/generated/water.wgsl.ts +23 -16
  204. package/src/render/shaders/gi/probeBake.wgsl.ts +9 -5
  205. package/src/render/shaders/particle.ts +134 -1
  206. package/src/render/shaders/recon/motion.wgsl.ts +13 -2
  207. package/src/render/shaders/skinBlur.ts +25 -3
  208. package/src/render/shaders/ssrTrace.ts +20 -1
  209. package/src/render/shaders/water.ts +12 -3
  210. package/src/render/skinBlur.ts +8 -5
  211. package/src/render/skinScatter.ts +3 -1
  212. package/src/render/ssrPass.ts +1 -0
  213. package/src/render/surfaceModel.ts +82 -10
  214. package/src/render/surfaceTexture.ts +101 -3
@@ -35,12 +35,25 @@ const bool MODEL_HAIR = false; // wgsl:override
35
35
  const bool MODEL_SKIN = false; // wgsl:override
36
36
  const bool MODEL_EYE = false; // wgsl:override
37
37
  /*
38
- * Skin's screen-space scattering, as two halves of one surface: the scene pass without its diffuse,
39
- * and a pass that is nothing but it, which the blur spreads before it is added back. Both off but
40
- * where \`skinScattering\` is \`'screen-space'\`; see \`skinBlur.ts\`.
38
+ * Skin's screen-space scattering, as halves of one surface: the scene pass without its diffuse; a
39
+ * pass that is nothing but the light the diffuse is made of, which the blur spreads; and a pass that
40
+ * is nothing but the colour that light is multiplied by once it has spread. All off but where
41
+ * \`skinScattering\` is \`'screen-space'\`; see \`skinBlur.ts\`.
41
42
  */
42
43
  const bool SKIN_SCREEN = false; // wgsl:override
43
44
  const bool SKIN_DIFFUSE = false; // wgsl:override
45
+ const bool SKIN_ALBEDO = false; // wgsl:override
46
+ /*
47
+ * Not a model of light but a page of it: the standard model, plus what a bake left (lightmap.ts).
48
+ * Declared after skin's halves so that every switch before it keeps the id it shipped with.
49
+ */
50
+ const bool MODEL_LIGHTMAP = false; // wgsl:override
51
+ /*
52
+ * Not a model either: whether this program carries GGX's own highlight for a material that asks
53
+ * (\`SurfaceMaterial.physicalSpecular\`). A lit switch, off until a material first asks and then
54
+ * on for good, as \`litSwitchesGlsl\`'s are; declared last so every switch before it keeps its id.
55
+ */
56
+ const bool PHYSICAL_SPECULAR = PHYSICAL_SPECULAR_ON; // wgsl:override
44
57
 
45
58
  /*
46
59
  * A model's numbers, two vectors a material — the lit stage's uniform budget has no more room
@@ -67,6 +80,14 @@ bool modelDiffuseAlone() {
67
80
  return false;
68
81
  }
69
82
 
83
+ /** Whether this pipeline draws skin's colour alone, which the spread light is multiplied by. */
84
+ bool modelAlbedoAlone() {
85
+ if (MODEL_SKIN) {
86
+ if (SKIN_ALBEDO) return true;
87
+ }
88
+ return false;
89
+ }
90
+
70
91
  /** Whether light from behind the surface reaches the eye through it: hair, and skin's thin parts. */
71
92
  bool modelSeesBehind() {
72
93
  if (MODEL_HAIR) return true;
@@ -111,15 +132,57 @@ float smithMasking(float ndl, float ndv, float alpha) {
111
132
  );
112
133
  }
113
134
 
135
+ /*
136
+ * Whether this surface's highlights are GGX's own (\`SurfaceMaterial.physicalSpecular\`), from the
137
+ * lane the standard, lightmap and anisotropic models leave free (\`packModel\`). Skin, hair and the
138
+ * eye shade their own highlights, and the eye's axis holds that lane, so they are never asked. The
139
+ * lit switch first, so a program built before any material asked carries none of it.
140
+ */
141
+ bool physicalSpecular() {
142
+ if (PHYSICAL_SPECULAR) {
143
+ if (MODEL_HAIR) return false;
144
+ if (MODEL_SKIN) return false;
145
+ if (MODEL_EYE) return false;
146
+ return uModelParams[1].z > 0.5;
147
+ }
148
+ return false;
149
+ }
150
+
151
+ /**
152
+ * GGX as a BRDF in this engine's light units, \`π · D · Vis · N·L\` with Fresnel left to the caller:
153
+ * the term skin's and the eye's highlights are, for a surface that asks for it. Its peak is
154
+ * \`1 / (4 α²)\` of the light head-on, against the look's 1. A lamp's size widens α as \`sphereLobe\`
155
+ * widens it, and a normalised distribution keeps its energy as it widens.
156
+ */
157
+ float physicalLobe(float ndh, float ndl, float ndv, float roughness, float sourceRadius, float dist) {
158
+ float grow = sourceRadius / max(2.0 * dist, 1e-3);
159
+ float alpha = min(max(roughness * roughness, MIN_LOBE_ALPHA) + grow, 1.0);
160
+ return 3.14159265 * ggxLobe(ndh, alpha) * smithMasking(ndl, max(ndv, 1e-4), alpha) * ndl;
161
+ }
162
+
163
+ /**
164
+ * A highlight's colour: Schlick's Fresnel from the surface's reflectance toward white at a grazing
165
+ * \`voh\`. On a metal alone for the look, whose dielectric attribute is a strength rather than a
166
+ * reflectance; on every surface where the highlight is physical, whose attribute is its F0 — but
167
+ * one reflecting nothing head-on keeps nothing, as the lamps' gate on that attribute has it.
168
+ */
169
+ vec3 highlightTint(vec3 specColor, float voh, float metal) {
170
+ float edge = pow(1.0 - voh, 5.0);
171
+ bool reflects = max(max(specColor.r, specColor.g), specColor.b) > 0.0;
172
+ return mix(specColor, vec3(1.0), physicalSpecular() && reflects ? edge : edge * metal);
173
+ }
174
+
114
175
  /** The standard model's answer to one light, which a model falls back to for what it does not change. */
115
176
  void standardLight(vec3 l, float sourceRadius, float dist) {
116
177
  float ndl = max(dot(mNormal, l), 0.0);
117
178
  vec3 h = normalize(l + mToEye);
118
179
  float ndh = max(dot(mNormal, h), 0.0);
119
- float lobe = sourceRadius > 0.0
120
- ? sphereLobe(ndh, mRoughness, sourceRadius, dist)
121
- : specularLobe(ndh, mRoughness);
122
- vec3 tint = mix(mSpecColor, vec3(1.0), pow(1.0 - max(dot(mToEye, h), 0.0), 5.0) * mMetal);
180
+ float lobe = physicalSpecular()
181
+ ? physicalLobe(ndh, ndl, dot(mNormal, mToEye), mRoughness, sourceRadius, dist)
182
+ : sourceRadius > 0.0
183
+ ? sphereLobe(ndh, mRoughness, sourceRadius, dist)
184
+ : specularLobe(ndh, mRoughness);
185
+ vec3 tint = highlightTint(mSpecColor, max(dot(mToEye, h), 0.0), mMetal);
123
186
  mDiffuse = mAlbedo * ndl * (1.0 - mMetal);
124
187
  mSpecular = ndl > 0.0 ? tint * lobe : vec3(0.0);
125
188
  }
@@ -149,6 +212,15 @@ void modelSurface(vec3 n, vec3 albedo, float roughness, float metal, vec3 at) {
149
212
  mTangent = frame[0];
150
213
  mBitangent = frame[1];
151
214
  mAlbedo = albedo;
215
+ /*
216
+ * **The diffuse half is light, not colour.** The blur spreads what this half writes, and what
217
+ * spreads beneath skin is the light: a brow, a lip line and a freckle stay where they are drawn.
218
+ * So this half shades a white surface and the colour is applied after the spread, from a half of
219
+ * its own. Spreading the coloured diffuse smeared every mark on a face into the skin around it.
220
+ */
221
+ if (MODEL_SKIN) {
222
+ if (SKIN_DIFFUSE) mAlbedo = vec3(1.0);
223
+ }
152
224
  mSpecColor = mix(vec3(vSpecular), albedo, metal);
153
225
  mRoughness = roughness;
154
226
  mMetal = metal;
@@ -229,6 +301,56 @@ vec3 modelEnvironment(vec3 environment) {
229
301
  return environment;
230
302
  }
231
303
 
304
+ /**
305
+ * One texel of a page's irradiance layer: its four bytes put back into the rgb9e5 word they are,
306
+ * lowest first, and decoded — three 9-bit mantissas over the exponent in the top five bits.
307
+ */
308
+ vec3 bakedIrradianceAt(ivec3 texel) {
309
+ uvec4 bytes = uvec4(texelFetch(uModelMap, texel, 0) * 255.0 + 0.5);
310
+ uint word = bytes.x | (bytes.y << 8u) | (bytes.z << 16u) | (bytes.w << 24u);
311
+ float scale = exp2(float(word >> 27u) - 24.0);
312
+ return vec3(float(word & 511u), float((word >> 9u) & 511u), float((word >> 18u) & 511u)) * scale;
313
+ }
314
+
315
+ /**
316
+ * What a baked page adds to this surface's diffuse: nothing in any pipeline but a lightmapped one,
317
+ * nor in one whose page is missing. The page's two layers at the surface's second coordinates, which
318
+ * ride the grain and relief lanes as \`-1 - uv\` (lightmap.ts) and are placed by the material's
319
+ * region: the irradiance, and the first-order harmonic its direction is, answered by the shading
320
+ * normal.
321
+ *
322
+ * **Filtered here, because the page cannot be filtered as it is stored**: the irradiance is a
323
+ * shared-exponent word in four bytes, and a blend of two words is not the blend of their colours.
324
+ * So the four texels around the sample are fetched, decoded and blended, as a bilinear sampler
325
+ * clamped at the page's edge would. Fetches need no derivative, so the branch costs nothing there.
326
+ */
327
+ vec3 modelBaked(vec3 n, vec3 albedo, float metal) {
328
+ if (MODEL_LIGHTMAP) {
329
+ if (uModelParams[1].w <= 0.0) return vec3(0.0);
330
+ vec2 at = (vec2(-1.0) - vec2(vGrain, vRelief)) * uModelParams[0].xy + uModelParams[0].zw;
331
+ ivec2 size = textureSize(uModelMap, 0).xy;
332
+ vec2 texel = at * vec2(size) - 0.5;
333
+ vec2 corner = floor(texel);
334
+ vec2 f = texel - corner;
335
+ ivec2 last = size - 1;
336
+ ivec2 lo = clamp(ivec2(corner), ivec2(0), last);
337
+ ivec2 hi = clamp(ivec2(corner) + 1, ivec2(0), last);
338
+ vec3 irradiance = mix(
339
+ mix(bakedIrradianceAt(ivec3(lo.x, lo.y, 0)), bakedIrradianceAt(ivec3(hi.x, lo.y, 0)), f.x),
340
+ mix(bakedIrradianceAt(ivec3(lo.x, hi.y, 0)), bakedIrradianceAt(ivec3(hi.x, hi.y, 0)), f.x),
341
+ f.y
342
+ );
343
+ vec4 direction = mix(
344
+ mix(texelFetch(uModelMap, ivec3(lo.x, lo.y, 1), 0), texelFetch(uModelMap, ivec3(hi.x, lo.y, 1), 0), f.x),
345
+ mix(texelFetch(uModelMap, ivec3(lo.x, hi.y, 1), 0), texelFetch(uModelMap, ivec3(hi.x, hi.y, 1), 0), f.x),
346
+ f.y
347
+ );
348
+ vec4 d = direction * 2.0 - 1.0;
349
+ return albedo * (1.0 - metal) * irradiance * max(dot(d.xyz, n) + d.w, 0.0);
350
+ }
351
+ return vec3(0.0);
352
+ }
353
+
232
354
  /** Skin's diffuse as the diffuse pass writes it, from the lit total before emission, fogged. */
233
355
  vec3 modelDiffuseOut(vec3 diffuse, float fog) {
234
356
  return diffuse * (1.0 - fog);
@@ -246,28 +368,41 @@ float modelReflectance(float standard) {
246
368
  }
247
369
  `;
248
370
 
249
- /** The models' whole chunk, at depth zero before `main`: see `flatFrag`. */
250
- export const MODELS_GLSL = [
251
- MODELS_HEAD,
252
- ANISOTROPIC_GLSL,
253
- HAIR_GLSL,
254
- SKIN_GLSL,
255
- EYE_GLSL,
256
- MODELS_DISPATCH,
257
- ].join('\n');
371
+ /**
372
+ * The models' whole chunk, at depth zero before `main`: see `flatFrag`. `physicalSpecular` is the
373
+ * \`PHYSICAL_SPECULAR\` lit switch's value, written in as \`litSwitchesGlsl\` writes the others.
374
+ */
375
+ export function modelsGlsl(physicalSpecular: boolean): string {
376
+ return [
377
+ MODELS_HEAD.replace('PHYSICAL_SPECULAR_ON', physicalSpecular ? 'true' : 'false'),
378
+ ANISOTROPIC_GLSL,
379
+ HAIR_GLSL,
380
+ SKIN_GLSL,
381
+ EYE_GLSL,
382
+ MODELS_DISPATCH,
383
+ ].join('\n');
384
+ }
258
385
 
259
386
  /**
260
387
  * Which half of a skin a lit pipeline draws under `skinScattering: 'screen-space'`: the whole
261
- * surface (every other pipeline), the frame's half without its diffuse, or the diffuse alone into
262
- * the blur's target — that last one depth-tested for equality against what the frame's half wrote
263
- * and writing none, since it is the same surface drawn again. See `skinBlur.ts`.
388
+ * surface (every other pipeline), the frame's half without its diffuse, the diffuse's light alone
389
+ * into the blur's target, or the colour that light is multiplied by after the blur into a target
390
+ * of its own — those last two depth-tested for equality against what the frame's half wrote and
391
+ * writing none, since they are the same surface drawn again. See `skinBlur.ts`.
264
392
  */
265
- export type SkinHalf = 'whole' | 'scene' | 'diffuse';
393
+ export type SkinHalf = 'whole' | 'scene' | 'diffuse' | 'albedo';
394
+
395
+ /** The constant each half of a skin turns on. See `SkinHalf`. */
396
+ export const SKIN_HALF_SWITCH = {
397
+ scene: 'SKIN_SCREEN',
398
+ diffuse: 'SKIN_DIFFUSE',
399
+ albedo: 'SKIN_ALBEDO',
400
+ } as const;
266
401
 
267
402
  /** A skin lit stage with one half's switch on, WebGL2's way: see `SkinHalf`. */
268
403
  export function skinHalfBound(source: string, half: SkinHalf): string {
269
404
  if (half === 'whole') return source;
270
- const name = half === 'scene' ? 'SKIN_SCREEN' : 'SKIN_DIFFUSE';
405
+ const name = SKIN_HALF_SWITCH[half];
271
406
  const off = `const bool ${name} = false;`;
272
407
  if (!source.includes(off)) {
273
408
  throw new Error(`skinHalfBound: this lit stage declares no ${name} constant`);
@@ -275,6 +410,20 @@ export function skinHalfBound(source: string, half: SkinHalf): string {
275
410
  return source.replace(off, `const bool ${name} = true;`);
276
411
  }
277
412
 
413
+ /**
414
+ * An instanced vertex stage whose tint lane is a lightmap region: the same source, the constant
415
+ * flipped — WebGL2's way. Only the instanced stage declares it.
416
+ */
417
+ export function lightmapRegionsBound(source: string): string {
418
+ const off = 'const bool LIGHTMAP_REGIONS = false;';
419
+ if (!source.includes(off)) {
420
+ throw new Error(
421
+ 'lightmapRegionsBound: this vertex stage declares no LIGHTMAP_REGIONS constant',
422
+ );
423
+ }
424
+ return source.replace(off, 'const bool LIGHTMAP_REGIONS = true;');
425
+ }
426
+
278
427
  /** A lit stage with one model's switch on: the same source, the constant flipped — WebGL2's way. */
279
428
  export function modelBound(source: string, kind: SurfaceModelKind): string {
280
429
  const name = SURFACE_MODEL_SWITCH[kind];
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The material's normal map applied to a surface normal. **The one statement of it**, read by the
3
+ * lit block for every light and by an unlit refracting draw for the direction it bends, so a lit
4
+ * pane and an unlit distortion bend by one tilt rather than two transcriptions of it.
5
+ *
6
+ * Depth zero, after the tangent frame it calls; see `flatFrag`. **Only ever called under a branch
7
+ * on a uniform** — `uNormalStrength` and whatever gates its caller — which is what makes the
8
+ * derivatives inside `tangentFrame` and the implicit level of the read legal: AGENTS.md 2026-08-07.
9
+ */
10
+ export const NORMAL_MAP_GLSL = /* glsl */ `
11
+ vec3 normalMapped(vec3 n, vec3 at) {
12
+ vec3 mapped = texture(uNormalMap, at).xyz * 2.0 - 1.0;
13
+ /*
14
+ * z rebuilt where none is stored. A tangent-space normal points out of its surface, so a
15
+ * stored z at or below zero is never a real one: it is a two-channel map, BC5, whose blue a
16
+ * device samples as zero and which arrives here as -1. Every map baked from BC5 to PNG before
17
+ * 4.8.4 carried the same zero. A select rather than a flag: no uniform to bind, no material
18
+ * that has to say what format it holds, and continuous at the boundary, since a unit texel
19
+ * lying flat has its z near zero either way. A texel with z above zero is left as it was.
20
+ */
21
+ mapped.z = mapped.z > 0.0 ? mapped.z : sqrt(max(0.0, 1.0 - dot(mapped.xy, mapped.xy)));
22
+ mat3 tbn = tangentFrame(n, vWorldPos, vUv.xy, vTangent, vHasTangents);
23
+ return normalize(mix(n, normalize(tbn * mapped), uNormalStrength));
24
+ }
25
+ `;
@@ -169,10 +169,38 @@ uniform ivec4 uMaterialFlags;
169
169
  *
170
170
  * **Four numbers in one row**: x is the cutoff, y how this frame resolves the edge (0 the hard test,
171
171
  * 1 a dither the temporal resolve averages, 2 alpha-to-coverage; see \`cutoutDither.ts\`), z the
172
- * frame the dither's pattern is offset by, w spare. One vector rather than a float and two more,
173
- * because every loose scalar is a row of WebGL2's 224 that the light budget gives up.
172
+ * frame the dither's pattern is offset by, w the material's lighting channels — a mask a light
173
+ * shades it only where its own shares a bit with (\`SurfaceMaterial.lightChannels\`, 1 unless a
174
+ * material names others). One vector rather than a float and three more, because every loose
175
+ * scalar is a row of WebGL2's 224 that the light budget gives up.
174
176
  */
175
177
  uniform vec4 uCutout;
178
+ /**
179
+ * A draw's own ambient, as nine spherical-harmonic coefficients of incoming radiance, red green blue
180
+ * in turn, twenty-seven floats, and in the last of the twenty-eight a 1 where they are on — 0 is the
181
+ * frame's own ambient, the sky's gradient or the probes'. \`ambientHarmonics.ts\` is the arithmetic
182
+ * and the basis, and its tests hold this to it. Seven rows of the material block, which is per draw
183
+ * as far as anything here is: \`setAmbientSH\` moves it between two draws as \`setMaterial\` does.
184
+ */
185
+ uniform vec4 uAmbientSH[7];
186
+
187
+ /** The ambient a surface facing \`n\` receives from \`uAmbientSH\`: \`ambientFromSH\`'s arithmetic. */
188
+ vec3 ambientHarmonics(vec3 n) {
189
+ vec3 c0 = uAmbientSH[0].xyz;
190
+ vec3 c1 = vec3(uAmbientSH[0].w, uAmbientSH[1].xy);
191
+ vec3 c2 = vec3(uAmbientSH[1].zw, uAmbientSH[2].x);
192
+ vec3 c3 = uAmbientSH[2].yzw;
193
+ vec3 c4 = uAmbientSH[3].xyz;
194
+ vec3 c5 = vec3(uAmbientSH[3].w, uAmbientSH[4].xy);
195
+ vec3 c6 = vec3(uAmbientSH[4].zw, uAmbientSH[5].x);
196
+ vec3 c7 = uAmbientSH[5].yzw;
197
+ vec3 c8 = uAmbientSH[6].xyz;
198
+ /* The bands over pi after the cosine convolution: 1, 2/3 and 1/4. */
199
+ vec3 band1 = (0.488603 * 2.0 / 3.0) * (c1 * n.y + c2 * n.z + c3 * n.x);
200
+ vec3 band2 = 0.25 * (1.092548 * (c4 * n.x * n.y + c5 * n.y * n.z + c7 * n.x * n.z)
201
+ + 0.315392 * c6 * (3.0 * n.z * n.z - 1.0) + 0.546274 * c8 * (n.x * n.x - n.y * n.y));
202
+ return max(0.282095 * c0 + band1 + band2, vec3(0.0));
203
+ }
176
204
  /**
177
205
  * The albedo array's per-layer effects table: six texels a layer, read with \`texelFetch\` at the
178
206
  * layer a vertex carries. A 1×1 stand-in where the array has none, which the size test below reads
@@ -233,8 +261,12 @@ uniform vec3 uOrmScale;
233
261
  *
234
262
  * A uniform rather than a permutation flag, following the ORM map's in \`uMaterialFlags\`: a fifth boolean doubles the
235
263
  * generated WGSL every consumer bundles as source, and this is a few multiply-adds.
264
+ *
265
+ * **x of \`uEnvironmentDials\`**, beside the two below: one row where three floats were three
266
+ * (\`uniformVectorBudget.ts\`). y is how much of the environment the material mirrors, z how
267
+ * bright what it mirrors is.
236
268
  */
237
- uniform float uEnvironmentPrefiltered;
269
+ uniform vec3 uEnvironmentDials;
238
270
 
239
271
  /**
240
272
  * Where a surface glows, and in what colour.
@@ -338,8 +370,12 @@ uniform vec4 uClipPlane;
338
370
  * One row for all four, paid for by the flag the clip plane no longer needs.
339
371
  */
340
372
  uniform vec4 uSurfaceScene;
341
- uniform float uEmissiveGain;
342
- uniform float uNightFactor;
373
+ /**
374
+ * What emission is multiplied by: x the gain (\`setEmissiveGain\`, the environment's own until a
375
+ * draw moves it), y the night factor emission is gated on. One row where two floats were two
376
+ * (\`uniformVectorBudget.ts\`).
377
+ */
378
+ uniform vec2 uEmission;
343
379
  #if NIGHT_EMISSIVE
344
380
  /**
345
381
  * Emission that only shows where the dominant light does not reach. 0 is off and is the default.
@@ -468,10 +504,9 @@ uniform float uGrain;
468
504
  * Two numbers rather than one because they are what separates the surfaces this exists for.
469
505
  * Asphalt is coarse and deep, orange peel on paint is fine and shallow, cast concrete sits
470
506
  * between them, and the geometry carrying them is identical in all three cases. See
471
- * Renderer.setSurfaceRelief.
507
+ * Renderer.setSurfaceRelief. x is the strength and y the bumps to a metre, in one row.
472
508
  */
473
- uniform float uRelief;
474
- uniform float uReliefCycles;
509
+ uniform vec2 uRelief;
475
510
  /**
476
511
  * How hard the bound surface texture's own luminance turns the shading normal, 0 for not at all.
477
512
  *
@@ -504,9 +539,8 @@ uniform float uTextureRelief;
504
539
  * how tight the lobe was made, because what makes a car body look wet is mostly the world
505
540
  * in it rather than the lights on it.
506
541
  *
507
- * Off by default, so every scene written before it is unchanged.
542
+ * Off by default, so every scene written before it is unchanged. **y of \`uEnvironmentDials\`.**
508
543
  */
509
- uniform float uReflectivity;
510
544
  /**
511
545
  * How bright the environment these surfaces reflect is, as a multiplier on it.
512
546
  *
@@ -526,9 +560,8 @@ uniform float uReflectivity;
526
560
  *
527
561
  * Applies to whatever the surface reflects, probe or hemispheric approximation alike, and to the
528
562
  * probe's own irradiance where a caller asked for that. **1 is the default and the identity**, so
529
- * every scene written before this is unchanged.
563
+ * every scene written before this is unchanged. **z of \`uEnvironmentDials\`.**
530
564
  */
531
- uniform float uEnvironmentGain;
532
565
  /**
533
566
  * The room itself, as a cubemap baked from one point, and whether one exists.
534
567
  *
@@ -628,10 +661,12 @@ uniform float uProbeGridAmbient;
628
661
  */
629
662
  uniform vec3 uProbeGridSets;
630
663
  #endif
631
- /** A world-space box that lights up regardless of time of day (run finished). */
664
+ /**
665
+ * A world-space box that lights up regardless of time of day: its corners, and in the far corner's
666
+ * w the gain — one row where a loose float was another (\`uniformVectorBudget.ts\`).
667
+ */
632
668
  uniform vec3 uHighlightMin;
633
- uniform vec3 uHighlightMax;
634
- uniform float uHighlightGain;
669
+ uniform vec4 uHighlightMax;
635
670
 
636
671
  /*
637
672
  * The froxel table, and the numbers needed to find a fragment's place in it.
@@ -749,13 +784,15 @@ uniform float uLightWeight[MAX_LIGHTS];
749
784
  */
750
785
  uniform vec3 uLightDir[MAX_LIGHTS];
751
786
  /**
752
- * The cosine of each light's inner cone angle, then of its outer.
787
+ * The cosine of each light's inner cone angle, then of its outer, and in z the light's own falloff
788
+ * exponent, 0 for the frame's falloff (\`PointLightSource.falloffExponent\`): a \`vec2\` array cost
789
+ * a whole row a light anyway, so the exponent spends no row of its own.
753
790
  *
754
791
  * A light with no cone carries -1 and -2, which makes \`smoothstep(outer, inner, dot)\` exactly 1
755
792
  * for every direction on the sphere. See \`POINT_LIGHT_COS_OUTER\`: the pair is chosen so a point
756
793
  * light collapses to the arithmetic it had rather than to something very close to it.
757
794
  */
758
- uniform vec2 uLightCone[MAX_LIGHTS];
795
+ uniform vec4 uLightCone[MAX_LIGHTS];
759
796
  /**
760
797
  * Which row of the photometric atlas each light uses, or a negative index for none.
761
798
  *
@@ -775,8 +812,13 @@ uniform float uLightIesProfile[MAX_LIGHTS];
775
812
  * tangent to a sphere, so any reference built from the aim alone flips somewhere — and the obvious
776
813
  * constructions put that flip exactly where these fixtures point, \`cross(worldUp, dir)\` being
777
814
  * singular for a light aimed straight down.
815
+ *
816
+ * **w is the light's lighting channels**, a mask compared with the material's (\`uCutout.w\`): a
817
+ * light shades a surface only where the two share a bit. In the lane the axis left, because an
818
+ * array of its own would be a row a light of a budget with none to spare; the froxel record keeps
819
+ * it beside the axis too, in the slot that was spare there.
778
820
  */
779
- uniform vec3 uLightIesAxis[MAX_LIGHTS];
821
+ uniform vec4 uLightIesAxis[MAX_LIGHTS];
780
822
  /**
781
823
  * Which tile of the cookie atlas each light projects, or a negative index for none.
782
824
  *
@@ -794,32 +836,29 @@ uniform float uLightCookie[MAX_LIGHTS];
794
836
  * single row of ones, the multiplicative identity, because a declared sampler needs a complete
795
837
  * texture whether or not the branch reads it and a row of zeros would switch off every light.
796
838
  */
797
- /** Rows of profile in the fixture atlas, below its cookies. At least 1. */
798
- uniform float uIesAtlasRows;
799
- /**
800
- * Horizontal planes each profile occupies, so a row is \`profile * planes + plane\`.
801
- *
802
- * **1 for an atlas with nothing asymmetric in it**, which is nearly every atlas, and the whole
803
- * plane path is branched away on that — see \`photometric\` in \`main.ts\`. One count for the atlas
804
- * rather than one per profile, because a per-profile count would need a second number in a light's
805
- * record to divide by, and a light's record is where space is expensive.
806
- */
807
- uniform float uIesPlaneCount;
808
839
  /**
809
- * Cookies: one row of square tiles, one tile a fixture's mask.
810
- *
811
- * **0 when no consumer has loaded one, and the whole projection is branched away on it** — a
812
- * \`uniform float\` is provably uniform control flow, so a scene with no cookie performs no
813
- * arithmetic and no fetch. With none loaded this holds a single white texel, the multiplicative
814
- * identity, because a declared sampler needs a complete texture whether or not the branch reads it
815
- * and a black stand-in would switch off every light that reached it.
816
- */
817
- uniform float uCookieTiles;
840
+ * The fixture atlas's shape, three numbers in one row — a row each would be three of a budget that
841
+ * has none to give (\`uniformVectorBudget.ts\`):
842
+ *
843
+ * - **x, rows of profile** below its cookies. At least 1.
844
+ * - **y, horizontal planes each profile occupies**, so a row is \`profile * planes + plane\`. 1 for
845
+ * an atlas with nothing asymmetric in it, which is nearly every atlas, and the whole plane path is
846
+ * branched away on that — see \`photometric\` in \`main.ts\`. One count for the atlas rather
847
+ * than one per profile, because a per-profile count would need a second number in a light's
848
+ * record to divide by, and a light's record is where space is expensive.
849
+ * - **z, cookie tiles**: one row of square tiles, one a fixture's mask. 0 when no consumer has
850
+ * loaded one, and the whole projection is branched away on it — a uniform is provably uniform
851
+ * control flow, so a scene with no cookie performs no arithmetic and no fetch. With none loaded
852
+ * the atlas holds a single white texel, the multiplicative identity, because a declared sampler
853
+ * needs a complete texture whether or not the branch reads it and a black stand-in would switch
854
+ * off every light that reached it.
855
+ */
856
+ uniform vec3 uFixtureShape;
818
857
  /**
819
858
  * Both tables in one texture: the cookies' row of tiles in the top band, the profiles' rows below.
820
859
  * One sampler for the two since 2026-09-30, because the lit stage bound fifteen of the sixteen
821
860
  * WebGL2 guarantees; see \`fixtureAtlas.ts\`. The bands are found from \`textureSize\` and
822
- * \`uIesAtlasRows\`, so the fold cost no uniform.
861
+ * \`uFixtureShape.x\`, so the fold cost no uniform.
823
862
  */
824
863
  uniform sampler2D uFixtureAtlas;
825
864
  /**
@@ -858,7 +897,12 @@ uniform vec3 uAreaLightColor[MAX_AREA_LIGHTS];
858
897
  /** The rectangle's in-plane axes, unit length, and its half extents along each. */
859
898
  uniform vec3 uAreaLightRight[MAX_AREA_LIGHTS];
860
899
  uniform vec3 uAreaLightUp[MAX_AREA_LIGHTS];
861
- uniform vec2 uAreaLightSize[MAX_AREA_LIGHTS];
900
+ /*
901
+ * Each rectangle's half extents, and in zw its barn doors: the cosine of their angle from its normal
902
+ * and their length, 0 for none (\`areaBarnDoors\`). A \`vec2\` array costs a whole row a rectangle
903
+ * anyway, so the doors spend no row of their own.
904
+ */
905
+ uniform vec4 uAreaLightSize[MAX_AREA_LIGHTS];
862
906
  /**
863
907
  * Whether the rectangle emits from both faces, 1 or 0.
864
908
  *
@@ -17,11 +17,12 @@
17
17
  * behind both, still glows. The shadow map's depth at the receiver would separate the two, and the
18
18
  * lamp loop reads a visibility rather than a depth.
19
19
  *
20
- * **Under \`skinScattering: 'screen-space'\`** the surface is drawn in two halves: the frame's
21
- * without its diffuse, and the diffuse alone into the blur's target — Lambert's, with the shadow as
22
- * it is, because the blur that follows carries light across curvature and shadow edges in the
23
- * picture and the fit as well would count it twice — keeping the transmission, which the picture
24
- * cannot see. \`skinBlur.ts\` is the rest.
20
+ * **Under \`skinScattering: 'screen-space'\`** the surface is drawn in halves: the frame's without
21
+ * its diffuse; the diffuse's light alone into the blur's target, shaded on a white surface —
22
+ * Lambert's, with the shadow as it is, because the blur that follows carries light across curvature
23
+ * and shadow edges in the picture and the fit as well would count it twice — keeping the
24
+ * transmission, which the picture cannot see; and the colour alone, which the spread light is
25
+ * multiplied by. \`skinBlur.ts\` is the rest.
25
26
  *
26
27
  * **The highlight** is two GGX lobes — 0.85 at the material's roughness and 0.15 at 0.6 of it, for
27
28
  * the skin's oil — normalised, with Smith's masking and the Fresnel of index 1.4, in lamp units, so
@@ -7,9 +7,9 @@
7
7
 
8
8
  export const BLOOM_DOWNSAMPLE_FRAG_WGSL = "struct Uniforms {\n uTexel: vec2<f32>,\n}\n\n@group(0) @binding(32) \nvar uSource_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uSource_s: sampler;\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\nvar<private> vUv_1: vec2<f32>;\nvar<private> fragColor: vec4<f32>;\n\nfn fetch_u0028_vf2_u003b(uv: ptr<function, vec2<f32>>) -> vec3<f32> {\n let _e27 = (*uv);\n let _e28 = textureSampleLevel(uSource_t, uSource_s, _e27, 0f);\n return _e28.xyz;\n}\n\nfn main_1() {\n var t: vec2<f32>;\n var a: vec3<f32>;\n var param: vec2<f32>;\n var b: vec3<f32>;\n var param_1: vec2<f32>;\n var c: vec3<f32>;\n var param_2: vec2<f32>;\n var d: vec3<f32>;\n var param_3: vec2<f32>;\n var e: vec3<f32>;\n var param_4: vec2<f32>;\n var f: vec3<f32>;\n var param_5: vec2<f32>;\n var g: vec3<f32>;\n var param_6: vec2<f32>;\n var h: vec3<f32>;\n var param_7: vec2<f32>;\n var i: vec3<f32>;\n var param_8: vec2<f32>;\n var j: vec3<f32>;\n var param_9: vec2<f32>;\n var k: vec3<f32>;\n var param_10: vec2<f32>;\n var l: vec3<f32>;\n var param_11: vec2<f32>;\n var m: vec3<f32>;\n var param_12: vec2<f32>;\n var box0_: vec3<f32>;\n var box1_: vec3<f32>;\n var box2_: vec3<f32>;\n var box3_: vec3<f32>;\n var box4_: vec3<f32>;\n\n let _e59 = unnamed.uTexel;\n t = _e59;\n let _e60 = vUv_1;\n let _e61 = t;\n param = (_e60 + (vec2<f32>(-2f, 2f) * _e61));\n let _e64 = fetch_u0028_vf2_u003b((&param));\n a = _e64;\n let _e65 = vUv_1;\n let _e66 = t;\n param_1 = (_e65 + (vec2<f32>(0f, 2f) * _e66));\n let _e69 = fetch_u0028_vf2_u003b((&param_1));\n b = _e69;\n let _e70 = vUv_1;\n let _e71 = t;\n param_2 = (_e70 + (vec2<f32>(2f, 2f) * _e71));\n let _e74 = fetch_u0028_vf2_u003b((&param_2));\n c = _e74;\n let _e75 = vUv_1;\n let _e76 = t;\n param_3 = (_e75 + (vec2<f32>(-2f, 0f) * _e76));\n let _e79 = fetch_u0028_vf2_u003b((&param_3));\n d = _e79;\n let _e80 = vUv_1;\n param_4 = _e80;\n let _e81 = fetch_u0028_vf2_u003b((&param_4));\n e = _e81;\n let _e82 = vUv_1;\n let _e83 = t;\n param_5 = (_e82 + (vec2<f32>(2f, 0f) * _e83));\n let _e86 = fetch_u0028_vf2_u003b((&param_5));\n f = _e86;\n let _e87 = vUv_1;\n let _e88 = t;\n param_6 = (_e87 + (vec2<f32>(-2f, -2f) * _e88));\n let _e91 = fetch_u0028_vf2_u003b((&param_6));\n g = _e91;\n let _e92 = vUv_1;\n let _e93 = t;\n param_7 = (_e92 + (vec2<f32>(0f, -2f) * _e93));\n let _e96 = fetch_u0028_vf2_u003b((&param_7));\n h = _e96;\n let _e97 = vUv_1;\n let _e98 = t;\n param_8 = (_e97 + (vec2<f32>(2f, -2f) * _e98));\n let _e101 = fetch_u0028_vf2_u003b((&param_8));\n i = _e101;\n let _e102 = vUv_1;\n let _e103 = t;\n param_9 = (_e102 + (vec2<f32>(-1f, 1f) * _e103));\n let _e106 = fetch_u0028_vf2_u003b((&param_9));\n j = _e106;\n let _e107 = vUv_1;\n let _e108 = t;\n param_10 = (_e107 + (vec2<f32>(1f, 1f) * _e108));\n let _e111 = fetch_u0028_vf2_u003b((&param_10));\n k = _e111;\n let _e112 = vUv_1;\n let _e113 = t;\n param_11 = (_e112 + (vec2<f32>(-1f, -1f) * _e113));\n let _e116 = fetch_u0028_vf2_u003b((&param_11));\n l = _e116;\n let _e117 = vUv_1;\n let _e118 = t;\n param_12 = (_e117 + (vec2<f32>(1f, -1f) * _e118));\n let _e121 = fetch_u0028_vf2_u003b((&param_12));\n m = _e121;\n let _e122 = a;\n let _e123 = b;\n let _e125 = d;\n let _e127 = e;\n box0_ = ((((_e122 + _e123) + _e125) + _e127) * 0.25f);\n let _e130 = b;\n let _e131 = c;\n let _e133 = e;\n let _e135 = f;\n box1_ = ((((_e130 + _e131) + _e133) + _e135) * 0.25f);\n let _e138 = d;\n let _e139 = e;\n let _e141 = g;\n let _e143 = h;\n box2_ = ((((_e138 + _e139) + _e141) + _e143) * 0.25f);\n let _e146 = e;\n let _e147 = f;\n let _e149 = h;\n let _e151 = i;\n box3_ = ((((_e146 + _e147) + _e149) + _e151) * 0.25f);\n let _e154 = j;\n let _e155 = k;\n let _e157 = l;\n let _e159 = m;\n box4_ = ((((_e154 + _e155) + _e157) + _e159) * 0.25f);\n let _e162 = box4_;\n let _e164 = box0_;\n let _e165 = box1_;\n let _e167 = box2_;\n let _e169 = box3_;\n let _e172 = ((_e162 * 0.5f) + ((((_e164 + _e165) + _e167) + _e169) * 0.125f));\n fragColor = vec4<f32>(_e172.x, _e172.y, _e172.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";
9
9
 
10
- export const BLOOM_PREFILTER_FRAG_WGSL = "struct Uniforms {\n uTexel: vec2<f32>,\n uThreshold: f32,\n}\n\n@group(0) @binding(32) \nvar uSource_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uSource_s: sampler;\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\nvar<private> vUv_1: vec2<f32>;\nvar<private> fragColor: vec4<f32>;\n\nfn brightness_u0028_vf3_u003b(c: ptr<function, vec3<f32>>) -> f32 {\n let _e35 = (*c)[0u];\n let _e37 = (*c)[1u];\n let _e39 = (*c)[2u];\n return max(_e35, max(_e37, _e39));\n}\n\nfn firefly_u0028_vf3_u003b(c_1: ptr<function, vec3<f32>>) -> f32 {\n var param: vec3<f32>;\n\n let _e35 = (*c_1);\n param = _e35;\n let _e36 = brightness_u0028_vf3_u003b((&param));\n return (1f / (1f + _e36));\n}\n\nfn fetch_u0028_vf2_u003b(uv: ptr<function, vec2<f32>>) -> vec3<f32> {\n var c_2: vec3<f32>;\n var bright: f32;\n var param_1: vec3<f32>;\n\n let _e37 = (*uv);\n let _e38 = textureSampleLevel(uSource_t, uSource_s, _e37, 0f);\n c_2 = min(_e38.xyz, vec3<f32>(256f, 256f, 256f));\n let _e41 = c_2;\n param_1 = _e41;\n let _e42 = brightness_u0028_vf3_u003b((&param_1));\n bright = _e42;\n let _e43 = c_2;\n let _e44 = bright;\n let _e46 = unnamed.uThreshold;\n let _e49 = bright;\n return (_e43 * (max((_e44 - _e46), 0f) / max(_e49, 0.0001f)));\n}\n\nfn main_1() {\n var t: vec2<f32>;\n var a: vec3<f32>;\n var param_2: vec2<f32>;\n var b: vec3<f32>;\n var param_3: vec2<f32>;\n var c_3: vec3<f32>;\n var param_4: vec2<f32>;\n var d: vec3<f32>;\n var param_5: vec2<f32>;\n var e: vec3<f32>;\n var param_6: vec2<f32>;\n var f: vec3<f32>;\n var param_7: vec2<f32>;\n var g: vec3<f32>;\n var param_8: vec2<f32>;\n var h: vec3<f32>;\n var param_9: vec2<f32>;\n var i: vec3<f32>;\n var param_10: vec2<f32>;\n var j: vec3<f32>;\n var param_11: vec2<f32>;\n var k: vec3<f32>;\n var param_12: vec2<f32>;\n var l: vec3<f32>;\n var param_13: vec2<f32>;\n var m: vec3<f32>;\n var param_14: vec2<f32>;\n var box0_: vec3<f32>;\n var box1_: vec3<f32>;\n var box2_: vec3<f32>;\n var box3_: vec3<f32>;\n var box4_: vec3<f32>;\n var w0_: f32;\n var param_15: vec3<f32>;\n var w1_: f32;\n var param_16: vec3<f32>;\n var w2_: f32;\n var param_17: vec3<f32>;\n var w3_: f32;\n var param_18: vec3<f32>;\n var w4_: f32;\n var param_19: vec3<f32>;\n var sum: vec3<f32>;\n\n let _e77 = unnamed.uTexel;\n t = _e77;\n let _e78 = vUv_1;\n let _e79 = t;\n param_2 = (_e78 + (vec2<f32>(-2f, 2f) * _e79));\n let _e82 = fetch_u0028_vf2_u003b((&param_2));\n a = _e82;\n let _e83 = vUv_1;\n let _e84 = t;\n param_3 = (_e83 + (vec2<f32>(0f, 2f) * _e84));\n let _e87 = fetch_u0028_vf2_u003b((&param_3));\n b = _e87;\n let _e88 = vUv_1;\n let _e89 = t;\n param_4 = (_e88 + (vec2<f32>(2f, 2f) * _e89));\n let _e92 = fetch_u0028_vf2_u003b((&param_4));\n c_3 = _e92;\n let _e93 = vUv_1;\n let _e94 = t;\n param_5 = (_e93 + (vec2<f32>(-2f, 0f) * _e94));\n let _e97 = fetch_u0028_vf2_u003b((&param_5));\n d = _e97;\n let _e98 = vUv_1;\n param_6 = _e98;\n let _e99 = fetch_u0028_vf2_u003b((&param_6));\n e = _e99;\n let _e100 = vUv_1;\n let _e101 = t;\n param_7 = (_e100 + (vec2<f32>(2f, 0f) * _e101));\n let _e104 = fetch_u0028_vf2_u003b((&param_7));\n f = _e104;\n let _e105 = vUv_1;\n let _e106 = t;\n param_8 = (_e105 + (vec2<f32>(-2f, -2f) * _e106));\n let _e109 = fetch_u0028_vf2_u003b((&param_8));\n g = _e109;\n let _e110 = vUv_1;\n let _e111 = t;\n param_9 = (_e110 + (vec2<f32>(0f, -2f) * _e111));\n let _e114 = fetch_u0028_vf2_u003b((&param_9));\n h = _e114;\n let _e115 = vUv_1;\n let _e116 = t;\n param_10 = (_e115 + (vec2<f32>(2f, -2f) * _e116));\n let _e119 = fetch_u0028_vf2_u003b((&param_10));\n i = _e119;\n let _e120 = vUv_1;\n let _e121 = t;\n param_11 = (_e120 + (vec2<f32>(-1f, 1f) * _e121));\n let _e124 = fetch_u0028_vf2_u003b((&param_11));\n j = _e124;\n let _e125 = vUv_1;\n let _e126 = t;\n param_12 = (_e125 + (vec2<f32>(1f, 1f) * _e126));\n let _e129 = fetch_u0028_vf2_u003b((&param_12));\n k = _e129;\n let _e130 = vUv_1;\n let _e131 = t;\n param_13 = (_e130 + (vec2<f32>(-1f, -1f) * _e131));\n let _e134 = fetch_u0028_vf2_u003b((&param_13));\n l = _e134;\n let _e135 = vUv_1;\n let _e136 = t;\n param_14 = (_e135 + (vec2<f32>(1f, -1f) * _e136));\n let _e139 = fetch_u0028_vf2_u003b((&param_14));\n m = _e139;\n let _e140 = a;\n let _e141 = b;\n let _e143 = d;\n let _e145 = e;\n box0_ = ((((_e140 + _e141) + _e143) + _e145) * 0.25f);\n let _e148 = b;\n let _e149 = c_3;\n let _e151 = e;\n let _e153 = f;\n box1_ = ((((_e148 + _e149) + _e151) + _e153) * 0.25f);\n let _e156 = d;\n let _e157 = e;\n let _e159 = g;\n let _e161 = h;\n box2_ = ((((_e156 + _e157) + _e159) + _e161) * 0.25f);\n let _e164 = e;\n let _e165 = f;\n let _e167 = h;\n let _e169 = i;\n box3_ = ((((_e164 + _e165) + _e167) + _e169) * 0.25f);\n let _e172 = j;\n let _e173 = k;\n let _e175 = l;\n let _e177 = m;\n box4_ = ((((_e172 + _e173) + _e175) + _e177) * 0.25f);\n let _e180 = box0_;\n param_15 = _e180;\n let _e181 = firefly_u0028_vf3_u003b((&param_15));\n w0_ = (_e181 * 0.125f);\n let _e183 = box1_;\n param_16 = _e183;\n let _e184 = firefly_u0028_vf3_u003b((&param_16));\n w1_ = (_e184 * 0.125f);\n let _e186 = box2_;\n param_17 = _e186;\n let _e187 = firefly_u0028_vf3_u003b((&param_17));\n w2_ = (_e187 * 0.125f);\n let _e189 = box3_;\n param_18 = _e189;\n let _e190 = firefly_u0028_vf3_u003b((&param_18));\n w3_ = (_e190 * 0.125f);\n let _e192 = box4_;\n param_19 = _e192;\n let _e193 = firefly_u0028_vf3_u003b((&param_19));\n w4_ = (_e193 * 0.5f);\n let _e195 = box0_;\n let _e196 = w0_;\n let _e198 = box1_;\n let _e199 = w1_;\n let _e202 = box2_;\n let _e203 = w2_;\n let _e206 = box3_;\n let _e207 = w3_;\n let _e210 = box4_;\n let _e211 = w4_;\n sum = (((((_e195 * _e196) + (_e198 * _e199)) + (_e202 * _e203)) + (_e206 * _e207)) + (_e210 * _e211));\n let _e214 = sum;\n let _e215 = w0_;\n let _e216 = w1_;\n let _e218 = w2_;\n let _e220 = w3_;\n let _e222 = w4_;\n let _e226 = (_e214 / vec3(max(((((_e215 + _e216) + _e218) + _e220) + _e222), 0.0001f)));\n fragColor = vec4<f32>(_e226.x, _e226.y, _e226.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";
10
+ export const BLOOM_PREFILTER_FRAG_WGSL = "struct Uniforms {\n uTexel: vec2<f32>,\n uThreshold: f32,\n uRamp: f32,\n}\n\n@group(0) @binding(32) \nvar uSource_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uSource_s: sampler;\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\nvar<private> vUv_1: vec2<f32>;\nvar<private> fragColor: vec4<f32>;\n\nfn brightness_u0028_vf3_u003b(c: ptr<function, vec3<f32>>) -> f32 {\n let _e36 = (*c)[0u];\n let _e38 = (*c)[1u];\n let _e40 = (*c)[2u];\n return max(_e36, max(_e38, _e40));\n}\n\nfn firefly_u0028_vf3_u003b(c_1: ptr<function, vec3<f32>>) -> f32 {\n var param: vec3<f32>;\n\n let _e36 = (*c_1);\n param = _e36;\n let _e37 = brightness_u0028_vf3_u003b((&param));\n return (1f / (1f + _e37));\n}\n\nfn fetch_u0028_vf2_u003b(uv: ptr<function, vec2<f32>>) -> vec3<f32> {\n var c_2: vec3<f32>;\n var bright: f32;\n var param_1: vec3<f32>;\n\n let _e38 = (*uv);\n let _e39 = textureSampleLevel(uSource_t, uSource_s, _e38, 0f);\n c_2 = min(_e39.xyz, vec3<f32>(256f, 256f, 256f));\n let _e42 = c_2;\n param_1 = _e42;\n let _e43 = brightness_u0028_vf3_u003b((&param_1));\n bright = _e43;\n let _e45 = unnamed.uRamp;\n if (_e45 > 0f) {\n let _e47 = c_2;\n let _e48 = bright;\n let _e50 = unnamed.uThreshold;\n let _e53 = unnamed.uRamp;\n return (_e47 * clamp(((_e48 - _e50) / _e53), 0f, 1f));\n }\n let _e57 = c_2;\n let _e58 = bright;\n let _e60 = unnamed.uThreshold;\n let _e63 = bright;\n return (_e57 * (max((_e58 - _e60), 0f) / max(_e63, 0.0001f)));\n}\n\nfn main_1() {\n var t: vec2<f32>;\n var a: vec3<f32>;\n var param_2: vec2<f32>;\n var b: vec3<f32>;\n var param_3: vec2<f32>;\n var c_3: vec3<f32>;\n var param_4: vec2<f32>;\n var d: vec3<f32>;\n var param_5: vec2<f32>;\n var e: vec3<f32>;\n var param_6: vec2<f32>;\n var f: vec3<f32>;\n var param_7: vec2<f32>;\n var g: vec3<f32>;\n var param_8: vec2<f32>;\n var h: vec3<f32>;\n var param_9: vec2<f32>;\n var i: vec3<f32>;\n var param_10: vec2<f32>;\n var j: vec3<f32>;\n var param_11: vec2<f32>;\n var k: vec3<f32>;\n var param_12: vec2<f32>;\n var l: vec3<f32>;\n var param_13: vec2<f32>;\n var m: vec3<f32>;\n var param_14: vec2<f32>;\n var box0_: vec3<f32>;\n var box1_: vec3<f32>;\n var box2_: vec3<f32>;\n var box3_: vec3<f32>;\n var box4_: vec3<f32>;\n var w0_: f32;\n var param_15: vec3<f32>;\n var w1_: f32;\n var param_16: vec3<f32>;\n var w2_: f32;\n var param_17: vec3<f32>;\n var w3_: f32;\n var param_18: vec3<f32>;\n var w4_: f32;\n var param_19: vec3<f32>;\n var sum: vec3<f32>;\n\n let _e78 = unnamed.uTexel;\n t = _e78;\n let _e79 = vUv_1;\n let _e80 = t;\n param_2 = (_e79 + (vec2<f32>(-2f, 2f) * _e80));\n let _e83 = fetch_u0028_vf2_u003b((&param_2));\n a = _e83;\n let _e84 = vUv_1;\n let _e85 = t;\n param_3 = (_e84 + (vec2<f32>(0f, 2f) * _e85));\n let _e88 = fetch_u0028_vf2_u003b((&param_3));\n b = _e88;\n let _e89 = vUv_1;\n let _e90 = t;\n param_4 = (_e89 + (vec2<f32>(2f, 2f) * _e90));\n let _e93 = fetch_u0028_vf2_u003b((&param_4));\n c_3 = _e93;\n let _e94 = vUv_1;\n let _e95 = t;\n param_5 = (_e94 + (vec2<f32>(-2f, 0f) * _e95));\n let _e98 = fetch_u0028_vf2_u003b((&param_5));\n d = _e98;\n let _e99 = vUv_1;\n param_6 = _e99;\n let _e100 = fetch_u0028_vf2_u003b((&param_6));\n e = _e100;\n let _e101 = vUv_1;\n let _e102 = t;\n param_7 = (_e101 + (vec2<f32>(2f, 0f) * _e102));\n let _e105 = fetch_u0028_vf2_u003b((&param_7));\n f = _e105;\n let _e106 = vUv_1;\n let _e107 = t;\n param_8 = (_e106 + (vec2<f32>(-2f, -2f) * _e107));\n let _e110 = fetch_u0028_vf2_u003b((&param_8));\n g = _e110;\n let _e111 = vUv_1;\n let _e112 = t;\n param_9 = (_e111 + (vec2<f32>(0f, -2f) * _e112));\n let _e115 = fetch_u0028_vf2_u003b((&param_9));\n h = _e115;\n let _e116 = vUv_1;\n let _e117 = t;\n param_10 = (_e116 + (vec2<f32>(2f, -2f) * _e117));\n let _e120 = fetch_u0028_vf2_u003b((&param_10));\n i = _e120;\n let _e121 = vUv_1;\n let _e122 = t;\n param_11 = (_e121 + (vec2<f32>(-1f, 1f) * _e122));\n let _e125 = fetch_u0028_vf2_u003b((&param_11));\n j = _e125;\n let _e126 = vUv_1;\n let _e127 = t;\n param_12 = (_e126 + (vec2<f32>(1f, 1f) * _e127));\n let _e130 = fetch_u0028_vf2_u003b((&param_12));\n k = _e130;\n let _e131 = vUv_1;\n let _e132 = t;\n param_13 = (_e131 + (vec2<f32>(-1f, -1f) * _e132));\n let _e135 = fetch_u0028_vf2_u003b((&param_13));\n l = _e135;\n let _e136 = vUv_1;\n let _e137 = t;\n param_14 = (_e136 + (vec2<f32>(1f, -1f) * _e137));\n let _e140 = fetch_u0028_vf2_u003b((&param_14));\n m = _e140;\n let _e141 = a;\n let _e142 = b;\n let _e144 = d;\n let _e146 = e;\n box0_ = ((((_e141 + _e142) + _e144) + _e146) * 0.25f);\n let _e149 = b;\n let _e150 = c_3;\n let _e152 = e;\n let _e154 = f;\n box1_ = ((((_e149 + _e150) + _e152) + _e154) * 0.25f);\n let _e157 = d;\n let _e158 = e;\n let _e160 = g;\n let _e162 = h;\n box2_ = ((((_e157 + _e158) + _e160) + _e162) * 0.25f);\n let _e165 = e;\n let _e166 = f;\n let _e168 = h;\n let _e170 = i;\n box3_ = ((((_e165 + _e166) + _e168) + _e170) * 0.25f);\n let _e173 = j;\n let _e174 = k;\n let _e176 = l;\n let _e178 = m;\n box4_ = ((((_e173 + _e174) + _e176) + _e178) * 0.25f);\n let _e181 = box0_;\n param_15 = _e181;\n let _e182 = firefly_u0028_vf3_u003b((&param_15));\n w0_ = (_e182 * 0.125f);\n let _e184 = box1_;\n param_16 = _e184;\n let _e185 = firefly_u0028_vf3_u003b((&param_16));\n w1_ = (_e185 * 0.125f);\n let _e187 = box2_;\n param_17 = _e187;\n let _e188 = firefly_u0028_vf3_u003b((&param_17));\n w2_ = (_e188 * 0.125f);\n let _e190 = box3_;\n param_18 = _e190;\n let _e191 = firefly_u0028_vf3_u003b((&param_18));\n w3_ = (_e191 * 0.125f);\n let _e193 = box4_;\n param_19 = _e193;\n let _e194 = firefly_u0028_vf3_u003b((&param_19));\n w4_ = (_e194 * 0.5f);\n let _e196 = box0_;\n let _e197 = w0_;\n let _e199 = box1_;\n let _e200 = w1_;\n let _e203 = box2_;\n let _e204 = w2_;\n let _e207 = box3_;\n let _e208 = w3_;\n let _e211 = box4_;\n let _e212 = w4_;\n sum = (((((_e196 * _e197) + (_e199 * _e200)) + (_e203 * _e204)) + (_e207 * _e208)) + (_e211 * _e212));\n let _e215 = sum;\n let _e216 = w0_;\n let _e217 = w1_;\n let _e219 = w2_;\n let _e221 = w3_;\n let _e223 = w4_;\n let _e227 = (_e215 / vec3(max(((((_e216 + _e217) + _e219) + _e221) + _e223), 0.0001f)));\n fragColor = vec4<f32>(_e227.x, _e227.y, _e227.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";
11
11
 
12
- export const BLOOM_UPSAMPLE_FRAG_WGSL = "struct Uniforms {\n uRadius: f32,\n}\n\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(32) \nvar uSource_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uSource_s: sampler;\nvar<private> vUv_1: vec2<f32>;\nvar<private> fragColor: vec4<f32>;\n\nfn main_1() {\n var r: f32;\n var a: vec3<f32>;\n var b: vec3<f32>;\n var c: vec3<f32>;\n var d: vec3<f32>;\n var e: vec3<f32>;\n var f: vec3<f32>;\n var g: vec3<f32>;\n var h: vec3<f32>;\n var i: vec3<f32>;\n var sum: vec3<f32>;\n\n let _e23 = unnamed.uRadius;\n r = _e23;\n let _e24 = vUv_1;\n let _e25 = r;\n let _e27 = r;\n let _e30 = textureSampleLevel(uSource_t, uSource_s, (_e24 + vec2<f32>(-(_e25), _e27)), 0f);\n a = _e30.xyz;\n let _e32 = vUv_1;\n let _e33 = r;\n let _e36 = textureSampleLevel(uSource_t, uSource_s, (_e32 + vec2<f32>(0f, _e33)), 0f);\n b = _e36.xyz;\n let _e38 = vUv_1;\n let _e39 = r;\n let _e40 = r;\n let _e43 = textureSampleLevel(uSource_t, uSource_s, (_e38 + vec2<f32>(_e39, _e40)), 0f);\n c = _e43.xyz;\n let _e45 = vUv_1;\n let _e46 = r;\n let _e50 = textureSampleLevel(uSource_t, uSource_s, (_e45 + vec2<f32>(-(_e46), 0f)), 0f);\n d = _e50.xyz;\n let _e52 = vUv_1;\n let _e53 = textureSampleLevel(uSource_t, uSource_s, _e52, 0f);\n e = _e53.xyz;\n let _e55 = vUv_1;\n let _e56 = r;\n let _e59 = textureSampleLevel(uSource_t, uSource_s, (_e55 + vec2<f32>(_e56, 0f)), 0f);\n f = _e59.xyz;\n let _e61 = vUv_1;\n let _e62 = r;\n let _e64 = r;\n let _e68 = textureSampleLevel(uSource_t, uSource_s, (_e61 + vec2<f32>(-(_e62), -(_e64))), 0f);\n g = _e68.xyz;\n let _e70 = vUv_1;\n let _e71 = r;\n let _e75 = textureSampleLevel(uSource_t, uSource_s, (_e70 + vec2<f32>(0f, -(_e71))), 0f);\n h = _e75.xyz;\n let _e77 = vUv_1;\n let _e78 = r;\n let _e79 = r;\n let _e83 = textureSampleLevel(uSource_t, uSource_s, (_e77 + vec2<f32>(_e78, -(_e79))), 0f);\n i = _e83.xyz;\n let _e85 = e;\n let _e87 = b;\n let _e88 = d;\n let _e90 = f;\n let _e92 = h;\n let _e96 = a;\n let _e97 = c;\n let _e99 = g;\n let _e101 = i;\n sum = (((_e85 * 4f) + ((((_e87 + _e88) + _e90) + _e92) * 2f)) + (((_e96 + _e97) + _e99) + _e101));\n let _e104 = sum;\n let _e105 = (_e104 * 0.0625f);\n fragColor = vec4<f32>(_e105.x, _e105.y, _e105.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";
12
+ export const BLOOM_UPSAMPLE_FRAG_WGSL = "struct Uniforms {\n uScale: vec3<f32>,\n uRadius: f32,\n}\n\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(32) \nvar uSource_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uSource_s: sampler;\nvar<private> vUv_1: vec2<f32>;\nvar<private> fragColor: vec4<f32>;\n\nfn main_1() {\n var r: f32;\n var a: vec3<f32>;\n var b: vec3<f32>;\n var c: vec3<f32>;\n var d: vec3<f32>;\n var e: vec3<f32>;\n var f: vec3<f32>;\n var g: vec3<f32>;\n var h: vec3<f32>;\n var i: vec3<f32>;\n var sum: vec3<f32>;\n\n let _e24 = unnamed.uRadius;\n r = _e24;\n let _e25 = vUv_1;\n let _e26 = r;\n let _e28 = r;\n let _e31 = textureSampleLevel(uSource_t, uSource_s, (_e25 + vec2<f32>(-(_e26), _e28)), 0f);\n a = _e31.xyz;\n let _e33 = vUv_1;\n let _e34 = r;\n let _e37 = textureSampleLevel(uSource_t, uSource_s, (_e33 + vec2<f32>(0f, _e34)), 0f);\n b = _e37.xyz;\n let _e39 = vUv_1;\n let _e40 = r;\n let _e41 = r;\n let _e44 = textureSampleLevel(uSource_t, uSource_s, (_e39 + vec2<f32>(_e40, _e41)), 0f);\n c = _e44.xyz;\n let _e46 = vUv_1;\n let _e47 = r;\n let _e51 = textureSampleLevel(uSource_t, uSource_s, (_e46 + vec2<f32>(-(_e47), 0f)), 0f);\n d = _e51.xyz;\n let _e53 = vUv_1;\n let _e54 = textureSampleLevel(uSource_t, uSource_s, _e53, 0f);\n e = _e54.xyz;\n let _e56 = vUv_1;\n let _e57 = r;\n let _e60 = textureSampleLevel(uSource_t, uSource_s, (_e56 + vec2<f32>(_e57, 0f)), 0f);\n f = _e60.xyz;\n let _e62 = vUv_1;\n let _e63 = r;\n let _e65 = r;\n let _e69 = textureSampleLevel(uSource_t, uSource_s, (_e62 + vec2<f32>(-(_e63), -(_e65))), 0f);\n g = _e69.xyz;\n let _e71 = vUv_1;\n let _e72 = r;\n let _e76 = textureSampleLevel(uSource_t, uSource_s, (_e71 + vec2<f32>(0f, -(_e72))), 0f);\n h = _e76.xyz;\n let _e78 = vUv_1;\n let _e79 = r;\n let _e80 = r;\n let _e84 = textureSampleLevel(uSource_t, uSource_s, (_e78 + vec2<f32>(_e79, -(_e80))), 0f);\n i = _e84.xyz;\n let _e86 = e;\n let _e88 = b;\n let _e89 = d;\n let _e91 = f;\n let _e93 = h;\n let _e97 = a;\n let _e98 = c;\n let _e100 = g;\n let _e102 = i;\n sum = (((_e86 * 4f) + ((((_e88 + _e89) + _e91) + _e93) * 2f)) + (((_e97 + _e98) + _e100) + _e102));\n let _e105 = sum;\n let _e108 = unnamed.uScale;\n let _e109 = ((_e105 * 0.0625f) * _e108);\n fragColor = vec4<f32>(_e109.x, _e109.y, _e109.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";
13
13
 
14
14
  /**
15
15
  * What the transform assigned, so the renderer binds the same numbers.
@@ -48,6 +48,11 @@ export const BLOOM_BINDINGS = {
48
48
  "offset": 8,
49
49
  "size": 4,
50
50
  "type": "float"
51
+ },
52
+ "uRamp": {
53
+ "offset": 12,
54
+ "size": 4,
55
+ "type": "float"
51
56
  }
52
57
  },
53
58
  "textures": {
@@ -62,8 +67,13 @@ export const BLOOM_BINDINGS = {
62
67
  "uniforms": 1,
63
68
  "uniformSize": 16,
64
69
  "fields": {
65
- "uRadius": {
70
+ "uScale": {
66
71
  "offset": 0,
72
+ "size": 12,
73
+ "type": "vec3"
74
+ },
75
+ "uRadius": {
76
+ "offset": 12,
67
77
  "size": 4,
68
78
  "type": "float"
69
79
  }