@driftengine/core 4.8.1 → 4.8.3

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 (159) hide show
  1. package/CHANGELOG.json +142 -0
  2. package/README.md +1 -1
  3. package/dist/index.d.ts +3 -1
  4. package/dist/index.js +8 -0
  5. package/dist/input/actionMap.d.ts +6 -1
  6. package/dist/input/actionMap.js +20 -7
  7. package/dist/input/input.d.ts +28 -0
  8. package/dist/input/input.js +71 -9
  9. package/dist/input/inputHarness.d.ts +9 -0
  10. package/dist/input/inputHarness.js +34 -2
  11. package/dist/render/backend/materialChanges.d.ts +7 -2
  12. package/dist/render/backend/materialChanges.js +8 -3
  13. package/dist/render/backend/webgl2/renderer.d.ts +75 -3
  14. package/dist/render/backend/webgl2/renderer.js +209 -22
  15. package/dist/render/backend/webgpu/buffers.d.ts +2 -0
  16. package/dist/render/backend/webgpu/buffers.js +2 -0
  17. package/dist/render/backend/webgpu/causticsPass.js +2 -1
  18. package/dist/render/backend/webgpu/depthPass.d.ts +13 -3
  19. package/dist/render/backend/webgpu/depthPass.js +4 -3
  20. package/dist/render/backend/webgpu/filmPass.js +2 -1
  21. package/dist/render/backend/webgpu/flatPass.d.ts +5 -0
  22. package/dist/render/backend/webgpu/flatPass.js +18 -8
  23. package/dist/render/backend/webgpu/linePass.js +2 -1
  24. package/dist/render/backend/webgpu/panelPass.js +2 -1
  25. package/dist/render/backend/webgpu/particlePass.js +2 -1
  26. package/dist/render/backend/webgpu/pipelineCache.d.ts +40 -8
  27. package/dist/render/backend/webgpu/pipelineCache.js +76 -9
  28. package/dist/render/backend/webgpu/plumePass.js +2 -1
  29. package/dist/render/backend/webgpu/postPass.d.ts +12 -2
  30. package/dist/render/backend/webgpu/postPass.js +19 -5
  31. package/dist/render/backend/webgpu/renderer.d.ts +66 -2
  32. package/dist/render/backend/webgpu/renderer.js +189 -38
  33. package/dist/render/backend/webgpu/sdfTextPass.js +2 -1
  34. package/dist/render/backend/webgpu/textPass.js +2 -1
  35. package/dist/render/backend/webgpu/waterPass.js +2 -1
  36. package/dist/render/backend/webgpu/windStreakPass.js +2 -1
  37. package/dist/render/boltBatch.js +2 -1
  38. package/dist/render/causticsRenderer.js +2 -1
  39. package/dist/render/cutoutCaster.d.ts +3 -1
  40. package/dist/render/cutoutCaster.js +4 -0
  41. package/dist/render/decalPass.js +2 -1
  42. package/dist/render/globalMediumPass.js +3 -2
  43. package/dist/render/lineBatch.js +5 -1
  44. package/dist/render/mapsWithoutUvs.d.ts +24 -0
  45. package/dist/render/mapsWithoutUvs.js +24 -0
  46. package/dist/render/mesh.d.ts +2 -0
  47. package/dist/render/mesh.js +3 -0
  48. package/dist/render/oitPass.js +2 -1
  49. package/dist/render/particleBatch.js +3 -2
  50. package/dist/render/particlePool.d.ts +21 -2
  51. package/dist/render/particlePool.js +72 -37
  52. package/dist/render/pass.d.ts +12 -0
  53. package/dist/render/plumeRenderer.js +3 -2
  54. package/dist/render/renderQuality.d.ts +16 -8
  55. package/dist/render/sceneCoverage.d.ts +54 -0
  56. package/dist/render/sceneCoverage.js +72 -0
  57. package/dist/render/sdfTextRenderer.js +2 -1
  58. package/dist/render/shaders/depth.js +3 -2
  59. package/dist/render/shaders/flat/glassTint.d.ts +28 -0
  60. package/dist/render/shaders/flat/glassTint.js +31 -0
  61. package/dist/render/shaders/flat/index.d.ts +12 -0
  62. package/dist/render/shaders/flat/index.js +13 -2
  63. package/dist/render/shaders/flat/main.d.ts +1 -1
  64. package/dist/render/shaders/flat/main.js +60 -25
  65. package/dist/render/shaders/flat/surfaceEffects.d.ts +1 -1
  66. package/dist/render/shaders/flat/surfaceEffects.js +6 -2
  67. package/dist/render/shaders/generated/depth.wgsl.d.ts +32 -12
  68. package/dist/render/shaders/generated/depth.wgsl.js +32 -12
  69. package/dist/render/shaders/generated/flat.wgsl.d.ts +89 -0
  70. package/dist/render/shaders/generated/flat.wgsl.js +127 -38
  71. package/dist/render/shaders/generated/line.wgsl.d.ts +1 -1
  72. package/dist/render/shaders/generated/line.wgsl.js +1 -1
  73. package/dist/render/shaders/generated/particle.wgsl.d.ts +3 -3
  74. package/dist/render/shaders/generated/particle.wgsl.js +3 -3
  75. package/dist/render/shaders/generated/rush.wgsl.d.ts +1 -1
  76. package/dist/render/shaders/generated/rush.wgsl.js +1 -1
  77. package/dist/render/shaders/generated/sdfText.wgsl.d.ts +1 -1
  78. package/dist/render/shaders/generated/sdfText.wgsl.js +1 -1
  79. package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +1 -1
  80. package/dist/render/shaders/generated/temporalResolve.wgsl.js +1 -1
  81. package/dist/render/shaders/line.d.ts +1 -1
  82. package/dist/render/shaders/outputTransform.d.ts +14 -1
  83. package/dist/render/shaders/outputTransform.js +23 -1
  84. package/dist/render/shaders/particle.d.ts +3 -3
  85. package/dist/render/shaders/recon/resolve.wgsl.js +15 -1
  86. package/dist/render/shaders/rush.js +13 -2
  87. package/dist/render/shaders/sdfText.d.ts +1 -1
  88. package/dist/render/shaders/temporalResolve.js +12 -5
  89. package/dist/render/ssrPass.js +2 -1
  90. package/dist/render/surfaceTexture.d.ts +13 -0
  91. package/dist/render/surfaceTexture.js +4 -0
  92. package/dist/render/textRenderer.js +2 -1
  93. package/dist/render/vertexDefaults.js +1 -0
  94. package/dist/render/viewModel.d.ts +29 -0
  95. package/dist/render/viewModel.js +35 -0
  96. package/dist/render/waterRenderer.js +2 -1
  97. package/dist/render/windStreakRenderer.js +2 -1
  98. package/package.json +6 -6
  99. package/src/index.ts +22 -1
  100. package/src/input/actionMap.ts +23 -8
  101. package/src/input/input.ts +79 -9
  102. package/src/input/inputHarness.ts +27 -2
  103. package/src/render/backend/materialChanges.ts +8 -3
  104. package/src/render/backend/webgl2/renderer.ts +223 -29
  105. package/src/render/backend/webgpu/buffers.ts +5 -0
  106. package/src/render/backend/webgpu/causticsPass.ts +2 -1
  107. package/src/render/backend/webgpu/depthPass.ts +4 -3
  108. package/src/render/backend/webgpu/filmPass.ts +2 -1
  109. package/src/render/backend/webgpu/flatPass.ts +43 -26
  110. package/src/render/backend/webgpu/linePass.ts +2 -1
  111. package/src/render/backend/webgpu/panelPass.ts +2 -1
  112. package/src/render/backend/webgpu/particlePass.ts +2 -1
  113. package/src/render/backend/webgpu/pipelineCache.ts +82 -8
  114. package/src/render/backend/webgpu/plumePass.ts +2 -1
  115. package/src/render/backend/webgpu/postPass.ts +20 -5
  116. package/src/render/backend/webgpu/renderer.ts +191 -37
  117. package/src/render/backend/webgpu/sdfTextPass.ts +2 -1
  118. package/src/render/backend/webgpu/textPass.ts +2 -1
  119. package/src/render/backend/webgpu/waterPass.ts +2 -1
  120. package/src/render/backend/webgpu/windStreakPass.ts +2 -1
  121. package/src/render/boltBatch.ts +2 -1
  122. package/src/render/causticsRenderer.ts +2 -1
  123. package/src/render/cutoutCaster.ts +15 -2
  124. package/src/render/decalPass.ts +2 -1
  125. package/src/render/globalMediumPass.ts +3 -2
  126. package/src/render/lineBatch.ts +3 -1
  127. package/src/render/mapsWithoutUvs.ts +43 -0
  128. package/src/render/mesh.ts +3 -0
  129. package/src/render/oitPass.ts +2 -1
  130. package/src/render/particleBatch.ts +3 -2
  131. package/src/render/particlePool.ts +107 -56
  132. package/src/render/pass.ts +12 -0
  133. package/src/render/plumeRenderer.ts +3 -2
  134. package/src/render/renderQuality.ts +16 -8
  135. package/src/render/sceneCoverage.ts +78 -0
  136. package/src/render/sdfTextRenderer.ts +2 -1
  137. package/src/render/shaders/depth.ts +3 -2
  138. package/src/render/shaders/flat/glassTint.ts +48 -0
  139. package/src/render/shaders/flat/index.ts +25 -2
  140. package/src/render/shaders/flat/main.ts +60 -25
  141. package/src/render/shaders/flat/surfaceEffects.ts +6 -2
  142. package/src/render/shaders/generated/depth.wgsl.ts +32 -12
  143. package/src/render/shaders/generated/flat.wgsl.ts +127 -38
  144. package/src/render/shaders/generated/line.wgsl.ts +1 -1
  145. package/src/render/shaders/generated/particle.wgsl.ts +3 -3
  146. package/src/render/shaders/generated/rush.wgsl.ts +1 -1
  147. package/src/render/shaders/generated/sdfText.wgsl.ts +1 -1
  148. package/src/render/shaders/generated/temporalResolve.wgsl.ts +1 -1
  149. package/src/render/shaders/outputTransform.ts +24 -1
  150. package/src/render/shaders/recon/resolve.wgsl.ts +15 -1
  151. package/src/render/shaders/rush.ts +13 -2
  152. package/src/render/shaders/temporalResolve.ts +12 -5
  153. package/src/render/ssrPass.ts +2 -1
  154. package/src/render/surfaceTexture.ts +16 -0
  155. package/src/render/textRenderer.ts +2 -1
  156. package/src/render/vertexDefaults.ts +1 -0
  157. package/src/render/viewModel.ts +41 -0
  158. package/src/render/waterRenderer.ts +2 -1
  159. package/src/render/windStreakRenderer.ts +2 -1
@@ -0,0 +1,72 @@
1
+ /**
2
+ * What a blended draw into the scene does to its alpha, which holds how much of each pixel is still
3
+ * the opaque surface — the share ambient occlusion is allowed to darken.
4
+ *
5
+ * **Occlusion is applied in the composite, from the depth the opaque world left**, after every
6
+ * translucent draw has landed, and a particle or a pane writes no depth: so a puff of smoke in front
7
+ * of a wall was darkened by the corner behind it. Reported from a game as walls and two figures
8
+ * standing behind a cloud showing through it as outlines, and nothing at all with occlusion off.
9
+ *
10
+ * So the scene's alpha is a running share. The frame clears it to 1 and an opaque draw writes 1,
11
+ * which is the whole of the surface; then each draw blended in front of it says which of three
12
+ * things it is, and the composite darkens `share` of the pixel and leaves the rest:
13
+ *
14
+ * - **It covers**: glass, smoke, water, a line, text in the world, a panel. The share falls by what
15
+ * the draw lets through, `share * (1 - a)`.
16
+ * - **It transmits**: the medium, the order-independent composite. Its alpha already *is* what gets
17
+ * through, `share * a`.
18
+ * - **It keeps**: light added to the surface or a layer of the surface itself — caustics, a light
19
+ * volume, a bolt, a wet film, a decal, a reflection. The share is unchanged.
20
+ *
21
+ * **What it gives up** is added light in front of an occluded corner: a glow or a spark adds to the
22
+ * pixel and keeps the share, so the composite darkens what it added along with the surface — which
23
+ * is how every blended draw behaved before this, and one multiply cannot tell the two apart. **What
24
+ * would make it wrong** is an opaque pass writing an alpha below 1: its surface would then take less
25
+ * occlusion than it should, which is the safe direction, and is the lit shader's own case at a
26
+ * cutout's edge or under a per-vertex alpha lane.
27
+ *
28
+ * **It survives the temporal passes.** A temporal resolve passes the frame's alpha through, since
29
+ * it is a fact about this frame and takes no history; a reconstruction reads it from the scene it
30
+ * rebuilt into the picture it shows, and the blended draws that land after it cover that picture.
31
+ *
32
+ * **One pipeline does not take part**: the GPU-driven pass blends its own surfaces into a target
33
+ * whose alpha is the mask its blit reads to tell a drawn pixel from an undrawn one, and that blit
34
+ * writes the share back to 1. Its panes still take the occlusion of what they cover. What would
35
+ * close it is a channel for that mask other than alpha.
36
+ *
37
+ * A contributed pass drawing something blended into the scene states the same thing for its own
38
+ * pipeline with `SCENE_ALPHA_COVERS`, `SCENE_ALPHA_TRANSMITS` or `SCENE_ALPHA_KEEPS`.
39
+ */
40
+ /** A blended draw that covers the surface by its alpha: `share * (1 - a)`. */
41
+ export const SCENE_ALPHA_COVERS = {
42
+ srcFactor: 'zero',
43
+ dstFactor: 'one-minus-src-alpha',
44
+ operation: 'add',
45
+ };
46
+ /** A draw whose alpha is what gets through it, a transmittance or a revealage: `share * a`. */
47
+ export const SCENE_ALPHA_TRANSMITS = {
48
+ srcFactor: 'zero',
49
+ dstFactor: 'src-alpha',
50
+ operation: 'add',
51
+ };
52
+ /** Light added to the surface, or a layer of it: the share unchanged. */
53
+ export const SCENE_ALPHA_KEEPS = {
54
+ srcFactor: 'zero',
55
+ dstFactor: 'one',
56
+ operation: 'add',
57
+ };
58
+ /**
59
+ * The same three on WebGL2, as the alpha half of `blendFuncSeparate` beside the colour half a
60
+ * caller already had. `src` and `dst` are the colour factors.
61
+ */
62
+ export function blendCovering(gl, src, dst) {
63
+ gl.blendFuncSeparate(src, dst, gl.ZERO, gl.ONE_MINUS_SRC_ALPHA);
64
+ }
65
+ /** `SCENE_ALPHA_TRANSMITS` on WebGL2, beside the colour factors `src` and `dst`. */
66
+ export function blendTransmitting(gl, src, dst) {
67
+ gl.blendFuncSeparate(src, dst, gl.ZERO, gl.SRC_ALPHA);
68
+ }
69
+ /** `SCENE_ALPHA_KEEPS` on WebGL2, beside the colour factors `src` and `dst`. */
70
+ export function blendKeeping(gl, src, dst) {
71
+ gl.blendFuncSeparate(src, dst, gl.ZERO, gl.ONE);
72
+ }
@@ -2,6 +2,7 @@ import { SdfTextLayout } from './sdfTextLayout.js';
2
2
  import { compileProgram, uniformLocations } from './shader.js';
3
3
  import { SDF_TEXT_FRAG, SDF_TEXT_VERT } from './shaders/sdfText.js';
4
4
  import { SDF_TEXT_TEXTURE_UNIT } from './lightBudget.js';
5
+ import { blendCovering } from './sceneCoverage.js';
5
6
  /**
6
7
  * Text from a signed distance field, on WebGL2.
7
8
  *
@@ -126,7 +127,7 @@ export class SdfTextRenderer {
126
127
  */
127
128
  gl.depthMask(false);
128
129
  gl.enable(gl.BLEND);
129
- gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
130
+ blendCovering(gl, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
130
131
  this.atlas.bind(gl, SDF_TEXT_TEXTURE_UNIT);
131
132
  const u = this.uniforms;
132
133
  gl.uniform1i(u['uOutputTransform'] ?? null, outputTransform);
@@ -59,12 +59,13 @@ ${CHANNEL_BEND}
59
59
 
60
60
  #if CUTOUT
61
61
  /*
62
- * **What a cutout caster adds, and where.** The UV at location 5, where every mesh carries it; two
62
+ * **What a cutout caster adds, and where.** The UV at location 5, where every mesh carries it; three
63
63
  * uniforms declared after every other, so no field of the plain variant moves and a binder written
64
64
  * against it stays right for this one; and two outputs after vLightPosition, which keeps location 0.
65
65
  */
66
66
  layout(location = 5) in vec3 aUv;
67
67
  uniform vec2 uUvScale;
68
+ uniform vec2 uUvOffset;
68
69
  uniform float uAlphaCutout;
69
70
  #endif
70
71
 
@@ -103,7 +104,7 @@ void main() {
103
104
  vLightPosition = uLightViewProj * vec4(bent, world.w);
104
105
  gl_Position = vLightPosition;
105
106
  #if CUTOUT
106
- vUv = vec3(aUv.xy * uUvScale, aUv.z);
107
+ vUv = vec3(aUv.xy * uUvScale + uUvOffset, aUv.z);
107
108
  vAlphaCutout = uAlphaCutout;
108
109
  #endif
109
110
  #if GLASS
@@ -4,3 +4,31 @@
4
4
  * outside every conditional, so each lookup can call it whichever shadows a permutation compiles.
5
5
  */
6
6
  export declare function glassTintGlsl(glassShadows: boolean): string;
7
+ /**
8
+ * The lit stage's switches, by the name of the constant each is: the decision both backends make
9
+ * about which optional code a lit program carries. See `litSwitchesGlsl`.
10
+ */
11
+ export type LitSwitch = 'GLASS_SHADOWS' | 'CLUSTERED_LIGHTS' | 'LIGHT_FIXTURES' | 'SURFACE_EFFECTS' | 'DRIFT_LIGHT';
12
+ /** Every switch off: what a renderer starts from before its profile and its content say otherwise. */
13
+ export declare function noLitSwitches(): Record<LitSwitch, boolean>;
14
+ /** Which of the lit stage's optional features a build reads. See `litSwitchesGlsl`. */
15
+ export interface LitSwitches {
16
+ readonly clusteredLights: boolean;
17
+ readonly lightFixtures: boolean;
18
+ readonly surfaceEffects: boolean;
19
+ readonly driftLight: boolean;
20
+ }
21
+ /**
22
+ * The lit stage's other switches, declared after `GLASS_SHADOWS` so that one keeps the id 0 the
23
+ * pipelines and their tests already name, each a pipeline-overridable constant on the generated
24
+ * WGSL and a written-in value on WebGL2 — the arrangement `GLASS_SHADOWS` has, for its reason:
25
+ * code a branch never runs still costs a shader its registers, and the device compiles it away
26
+ * only where the switch is a constant.
27
+ *
28
+ * **Clustering is the profile's and fixed.** The other three are content, off until a consumer
29
+ * first uses them — a measured profile or a cookie, a material with an effects table, a DriftLight
30
+ * volume — and then on for good; see `PipelineCache.enable` and the WebGL2 renderer's rebuild.
31
+ * Measured on RADV against the lit shader with glass already out: 6,852 instructions and 120
32
+ * registers, 4,641 and 96 with all four out.
33
+ */
34
+ export declare function litSwitchesGlsl(switches: LitSwitches): string;
@@ -23,3 +23,34 @@ vec4 glassUnmix(vec4 mip, float centreClarity) {
23
23
  }
24
24
  `;
25
25
  }
26
+ /** Every switch off: what a renderer starts from before its profile and its content say otherwise. */
27
+ export function noLitSwitches() {
28
+ return {
29
+ GLASS_SHADOWS: false,
30
+ CLUSTERED_LIGHTS: false,
31
+ LIGHT_FIXTURES: false,
32
+ SURFACE_EFFECTS: false,
33
+ DRIFT_LIGHT: false,
34
+ };
35
+ }
36
+ /**
37
+ * The lit stage's other switches, declared after `GLASS_SHADOWS` so that one keeps the id 0 the
38
+ * pipelines and their tests already name, each a pipeline-overridable constant on the generated
39
+ * WGSL and a written-in value on WebGL2 — the arrangement `GLASS_SHADOWS` has, for its reason:
40
+ * code a branch never runs still costs a shader its registers, and the device compiles it away
41
+ * only where the switch is a constant.
42
+ *
43
+ * **Clustering is the profile's and fixed.** The other three are content, off until a consumer
44
+ * first uses them — a measured profile or a cookie, a material with an effects table, a DriftLight
45
+ * volume — and then on for good; see `PipelineCache.enable` and the WebGL2 renderer's rebuild.
46
+ * Measured on RADV against the lit shader with glass already out: 6,852 instructions and 120
47
+ * registers, 4,641 and 96 with all four out.
48
+ */
49
+ export function litSwitchesGlsl(switches) {
50
+ return /* glsl */ `
51
+ const bool CLUSTERED_LIGHTS = ${switches.clusteredLights ? 'true' : 'false'}; // wgsl:override
52
+ const bool LIGHT_FIXTURES = ${switches.lightFixtures ? 'true' : 'false'}; // wgsl:override
53
+ const bool SURFACE_EFFECTS = ${switches.surfaceEffects ? 'true' : 'false'}; // wgsl:override
54
+ const bool DRIFT_LIGHT = ${switches.driftLight ? 'true' : 'false'}; // wgsl:override
55
+ `;
56
+ }
@@ -92,6 +92,18 @@ export interface FlatShaderOptions {
92
92
  * courtyard at night, measured, and nothing once compiled out.
93
93
  */
94
94
  readonly glassShadows?: boolean;
95
+ /**
96
+ * Whether this build has the clustered arm of the light loop: `clusteredLights`, fixed per
97
+ * renderer. True when absent, which is what the generated WGSL is built with. See
98
+ * `litSwitchesGlsl`.
99
+ */
100
+ readonly clusteredLights?: boolean;
101
+ /** Whether it reads measured profiles and cookies. True when absent. See `litSwitchesGlsl`. */
102
+ readonly lightFixtures?: boolean;
103
+ /** Whether it reads a material's effects table. True when absent. See `litSwitchesGlsl`. */
104
+ readonly surfaceEffects?: boolean;
105
+ /** Whether it reads a DriftLight volume. True when absent. See `litSwitchesGlsl`. */
106
+ readonly driftLight?: boolean;
95
107
  /**
96
108
  * How many point lights this build declares room for. `MAX_POINT_LIGHTS` when absent.
97
109
  *
@@ -7,7 +7,7 @@ import { preambleGlsl } from './preamble.js';
7
7
  import { LOBES_GLSL } from './lobes.js';
8
8
  import { POINTSHADOW_GLSL } from './pointShadow.js';
9
9
  import { DIRECTIONALSHADOW_GLSL } from './directionalShadow.js';
10
- import { glassTintGlsl } from './glassTint.js';
10
+ import { glassTintGlsl, litSwitchesGlsl } from './glassTint.js';
11
11
  import { MORPH_GLSL } from '../morph.js';
12
12
  import { SKINNING_GLSL } from '../skinning.js';
13
13
  import { SURFACE_GLSL } from './surface.js';
@@ -61,6 +61,11 @@ uniform mat4 uLightViewProj;
61
61
  * when no texture is bound.
62
62
  */
63
63
  uniform vec2 uUvScale;
64
+ /**
65
+ * Where the texture starts, per axis, added after the scale: \`uv * uUvScale + uUvOffset\`. What
66
+ * picks a cell of a flipbook or an atlas through the material. See \`SurfaceMaterial.uOffset\`.
67
+ */
68
+ uniform vec2 uUvOffset;
64
69
 
65
70
  /*
66
71
  * **Placement and tint are declared last of the shared uniforms, and the position is the
@@ -243,7 +248,7 @@ void main() {
243
248
  vColor = aColor * tint;
244
249
  vEmissive = aEmissive;
245
250
  vSpecular = aSpecular;
246
- vUv = vec3(aUv.xy * uUvScale, aUv.z);
251
+ vUv = vec3(aUv.xy * uUvScale + uUvOffset, aUv.z);
247
252
  vEmissiveColor = aEmissiveColor;
248
253
  vRoughness = aRoughness;
249
254
  vGrain = aGrain;
@@ -359,6 +364,12 @@ export function flatFrag(options) {
359
364
  /* Depth zero as well: both glass lookups, sun and lamps, call it, and every permutation
360
365
  declares its switch, which the pipelines set whether the permutation reads it or not. */
361
366
  glassTintGlsl(options.glassShadows ?? true),
367
+ litSwitchesGlsl({
368
+ clusteredLights: options.clusteredLights ?? true,
369
+ lightFixtures: options.lightFixtures ?? true,
370
+ surfaceEffects: options.surfaceEffects ?? true,
371
+ driftLight: options.driftLight ?? true,
372
+ }),
362
373
  LOBES_GLSL,
363
374
  POINTSHADOW_GLSL,
364
375
  DIRECTIONALSHADOW_GLSL,