@driftengine/core 4.9.0 → 4.11.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 (231) hide show
  1. package/CHANGELOG.json +133 -11
  2. package/README.md +43 -38
  3. package/dist/index.d.ts +7 -4
  4. package/dist/index.js +5 -4
  5. package/dist/render/ambientHarmonics.d.ts +1 -1
  6. package/dist/render/ambientHarmonics.js +1 -1
  7. package/dist/render/areaLights.d.ts +4 -4
  8. package/dist/render/areaLights.js +1 -1
  9. package/dist/render/backend/api.d.ts +10 -3
  10. package/dist/render/backend/select.js +11 -5
  11. package/dist/render/backend/webgl2/boneAnimations.d.ts +29 -0
  12. package/dist/render/backend/webgl2/boneAnimations.js +80 -0
  13. package/dist/render/backend/webgl2/instanced.d.ts +5 -1
  14. package/dist/render/backend/webgl2/instanced.js +13 -1
  15. package/dist/render/backend/webgl2/renderer.d.ts +189 -4
  16. package/dist/render/backend/webgl2/renderer.js +614 -66
  17. package/dist/render/backend/webgl2/skinPaletteTexture.d.ts +5 -3
  18. package/dist/render/backend/webgl2/skinPaletteTexture.js +6 -4
  19. package/dist/render/backend/webgpu/boneAnimations.d.ts +34 -0
  20. package/dist/render/backend/webgpu/boneAnimations.js +76 -0
  21. package/dist/render/backend/webgpu/buffers.d.ts +24 -4
  22. package/dist/render/backend/webgpu/buffers.js +116 -59
  23. package/dist/render/backend/webgpu/clothKernels.d.ts +8 -0
  24. package/dist/render/backend/webgpu/clothKernels.js +76 -0
  25. package/dist/render/backend/webgpu/clothOps.d.ts +39 -0
  26. package/dist/render/backend/webgpu/clothOps.js +78 -0
  27. package/dist/render/backend/webgpu/clothSetLayout.d.ts +25 -0
  28. package/dist/render/backend/webgpu/clothSetLayout.js +84 -0
  29. package/dist/render/backend/webgpu/clothSetPack.d.ts +33 -0
  30. package/dist/render/backend/webgpu/clothSetPack.js +144 -0
  31. package/dist/render/backend/webgpu/compressedUpload.d.ts +0 -1
  32. package/dist/render/backend/webgpu/compressedUpload.js +53 -8
  33. package/dist/render/backend/webgpu/depthPass.d.ts +59 -3
  34. package/dist/render/backend/webgpu/depthPass.js +49 -14
  35. package/dist/render/backend/webgpu/drawCommand.d.ts +20 -4
  36. package/dist/render/backend/webgpu/drawCommand.js +11 -3
  37. package/dist/render/backend/webgpu/flatPass.d.ts +85 -42
  38. package/dist/render/backend/webgpu/flatPass.js +137 -20
  39. package/dist/render/backend/webgpu/gpuClothSet.d.ts +80 -0
  40. package/dist/render/backend/webgpu/gpuClothSet.js +462 -0
  41. package/dist/render/backend/webgpu/instanced.d.ts +14 -1
  42. package/dist/render/backend/webgpu/instanced.js +24 -1
  43. package/dist/render/backend/webgpu/latePass.js +1 -0
  44. package/dist/render/backend/webgpu/materialStore.d.ts +101 -0
  45. package/dist/render/backend/webgpu/materialStore.js +265 -0
  46. package/dist/render/backend/webgpu/motionPass.js +15 -6
  47. package/dist/render/backend/webgpu/pipelineCache.d.ts +28 -1
  48. package/dist/render/backend/webgpu/pipelineCache.js +46 -1
  49. package/dist/render/backend/webgpu/postPass.d.ts +1 -1
  50. package/dist/render/backend/webgpu/renderer.d.ts +200 -35
  51. package/dist/render/backend/webgpu/renderer.js +993 -168
  52. package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.d.ts +9 -2
  53. package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.js +121 -47
  54. package/dist/render/backend/webgpu/skinPaletteRing.d.ts +7 -3
  55. package/dist/render/backend/webgpu/skinPaletteRing.js +13 -7
  56. package/dist/render/backend/webgpu/skinPaletteTexture.d.ts +6 -0
  57. package/dist/render/backend/webgpu/skinPaletteTexture.js +7 -1
  58. package/dist/render/backend/webgpu/staticBundles.d.ts +125 -0
  59. package/dist/render/backend/webgpu/staticBundles.js +242 -0
  60. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +10 -3
  61. package/dist/render/backend/webgpu/surfaceTexturePass.js +20 -2
  62. package/dist/render/backend/webgpu/uniformRing.d.ts +21 -0
  63. package/dist/render/backend/webgpu/uniformRing.js +9 -1
  64. package/dist/render/backend/webgpu/vertexFormats.d.ts +22 -0
  65. package/dist/render/backend/webgpu/vertexFormats.js +97 -0
  66. package/dist/render/bloomChain.d.ts +3 -3
  67. package/dist/render/boneAnimation.d.ts +92 -0
  68. package/dist/render/boneAnimation.js +133 -0
  69. package/dist/render/compressedSource.d.ts +33 -13
  70. package/dist/render/compressedSource.js +70 -25
  71. package/dist/render/glCompressed.js +83 -0
  72. package/dist/render/globalMediumPass.d.ts +2 -0
  73. package/dist/render/globalMediumPass.js +1 -0
  74. package/dist/render/indexWidth.d.ts +17 -0
  75. package/dist/render/indexWidth.js +23 -0
  76. package/dist/render/instances.d.ts +26 -0
  77. package/dist/render/lightBudget.d.ts +10 -0
  78. package/dist/render/lightBudget.js +10 -0
  79. package/dist/render/lightMatrix.d.ts +11 -0
  80. package/dist/render/lightMatrix.js +14 -0
  81. package/dist/render/lightmap.d.ts +1 -1
  82. package/dist/render/mesh.d.ts +14 -0
  83. package/dist/render/mesh.js +44 -14
  84. package/dist/render/pointLightSelection.d.ts +4 -4
  85. package/dist/render/renderQuality.d.ts +30 -0
  86. package/dist/render/renderQuality.js +5 -0
  87. package/dist/render/rendererHarness.d.ts +7 -0
  88. package/dist/render/rendererHarness.js +12 -0
  89. package/dist/render/screenSpaceReflection.d.ts +2 -1
  90. package/dist/render/shader.d.ts +15 -0
  91. package/dist/render/shader.js +41 -0
  92. package/dist/render/shaders/boneAnimation.d.ts +19 -0
  93. package/dist/render/shaders/boneAnimation.js +63 -0
  94. package/dist/render/shaders/depth.d.ts +7 -0
  95. package/dist/render/shaders/depth.js +35 -10
  96. package/dist/render/shaders/flat/directionalShadow.js +84 -10
  97. package/dist/render/shaders/flat/glassTint.d.ts +1 -1
  98. package/dist/render/shaders/flat/glassTint.js +3 -0
  99. package/dist/render/shaders/flat/index.d.ts +21 -0
  100. package/dist/render/shaders/flat/index.js +42 -7
  101. package/dist/render/shaders/flat/layered.d.ts +19 -0
  102. package/dist/render/shaders/flat/layered.js +115 -0
  103. package/dist/render/shaders/flat/main.d.ts +1 -1
  104. package/dist/render/shaders/flat/main.js +58 -21
  105. package/dist/render/shaders/flat/mapReads.d.ts +10 -0
  106. package/dist/render/shaders/flat/mapReads.js +38 -0
  107. package/dist/render/shaders/flat/models.js +1 -1
  108. package/dist/render/shaders/flat/movingSun.d.ts +21 -0
  109. package/dist/render/shaders/flat/movingSun.js +46 -0
  110. package/dist/render/shaders/flat/normalMap.d.ts +6 -2
  111. package/dist/render/shaders/flat/normalMap.js +14 -3
  112. package/dist/render/shaders/flat/overlay.d.ts +3 -2
  113. package/dist/render/shaders/flat/overlay.js +42 -20
  114. package/dist/render/shaders/flat/pointShadow.js +2 -2
  115. package/dist/render/shaders/flat/preamble.js +59 -27
  116. package/dist/render/shaders/flat/worldUv.d.ts +22 -0
  117. package/dist/render/shaders/flat/worldUv.js +113 -0
  118. package/dist/render/shaders/generated/depth.wgsl.d.ts +93 -0
  119. package/dist/render/shaders/generated/depth.wgsl.js +93 -0
  120. package/dist/render/shaders/generated/flat.wgsl.d.ts +3616 -3042
  121. package/dist/render/shaders/generated/flat.wgsl.js +3688 -3113
  122. package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +8 -3
  123. package/dist/render/shaders/generated/globalMedium.wgsl.js +8 -3
  124. package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +15 -10
  125. package/dist/render/shaders/generated/lightVolume.wgsl.js +16 -11
  126. package/dist/render/shaders/globalMedium.js +9 -1
  127. package/dist/render/shaders/lightVolume.js +9 -1
  128. package/dist/render/shaders/outputTransform.d.ts +7 -0
  129. package/dist/render/shaders/outputTransform.js +28 -14
  130. package/dist/render/shaders/tangentFrame.d.ts +1 -1
  131. package/dist/render/shaders/tangentFrame.js +16 -3
  132. package/dist/render/shaders/vertexChannel.d.ts +7 -0
  133. package/dist/render/shaders/vertexChannel.js +26 -0
  134. package/dist/render/skinnedClothRun.d.ts +28 -0
  135. package/dist/render/skinnedClothRun.js +103 -35
  136. package/dist/render/staticDraws.d.ts +47 -0
  137. package/dist/render/staticDraws.js +43 -0
  138. package/dist/render/surfaceLayers.d.ts +39 -0
  139. package/dist/render/surfaceLayers.js +26 -0
  140. package/dist/render/surfaceOverlay.d.ts +16 -3
  141. package/dist/render/surfaceOverlay.js +11 -6
  142. package/dist/render/surfaceProjection.d.ts +34 -0
  143. package/dist/render/surfaceProjection.js +30 -0
  144. package/dist/render/surfaceTexture.d.ts +68 -7
  145. package/dist/render/surfaceTexture.js +56 -17
  146. package/dist/render/vertexPacking.d.ts +48 -0
  147. package/dist/render/vertexPacking.js +68 -0
  148. package/package.json +6 -6
  149. package/src/index.ts +12 -4
  150. package/src/render/ambientHarmonics.ts +1 -1
  151. package/src/render/areaLights.ts +4 -4
  152. package/src/render/backend/api.ts +13 -3
  153. package/src/render/backend/select.ts +10 -5
  154. package/src/render/backend/webgl2/boneAnimations.ts +105 -0
  155. package/src/render/backend/webgl2/instanced.ts +20 -1
  156. package/src/render/backend/webgl2/renderer.ts +723 -79
  157. package/src/render/backend/webgl2/skinPaletteTexture.ts +6 -4
  158. package/src/render/backend/webgpu/boneAnimations.ts +97 -0
  159. package/src/render/backend/webgpu/buffers.ts +195 -70
  160. package/src/render/backend/webgpu/clothKernels.ts +86 -0
  161. package/src/render/backend/webgpu/clothOps.ts +86 -0
  162. package/src/render/backend/webgpu/clothSetLayout.ts +102 -0
  163. package/src/render/backend/webgpu/clothSetPack.ts +197 -0
  164. package/src/render/backend/webgpu/compressedUpload.ts +59 -9
  165. package/src/render/backend/webgpu/depthPass.ts +51 -10
  166. package/src/render/backend/webgpu/drawCommand.ts +25 -4
  167. package/src/render/backend/webgpu/flatPass.ts +212 -41
  168. package/src/render/backend/webgpu/gpuClothSet.ts +564 -0
  169. package/src/render/backend/webgpu/instanced.ts +32 -1
  170. package/src/render/backend/webgpu/latePass.ts +1 -0
  171. package/src/render/backend/webgpu/materialStore.ts +276 -0
  172. package/src/render/backend/webgpu/motionPass.ts +18 -7
  173. package/src/render/backend/webgpu/pipelineCache.ts +53 -7
  174. package/src/render/backend/webgpu/renderer.ts +1201 -202
  175. package/src/render/backend/webgpu/shaders/clothSolve.wgsl.ts +121 -47
  176. package/src/render/backend/webgpu/skinPaletteRing.ts +13 -7
  177. package/src/render/backend/webgpu/skinPaletteTexture.ts +7 -1
  178. package/src/render/backend/webgpu/staticBundles.ts +364 -0
  179. package/src/render/backend/webgpu/surfaceTexturePass.ts +29 -3
  180. package/src/render/backend/webgpu/uniformRing.ts +10 -1
  181. package/src/render/backend/webgpu/vertexFormats.ts +113 -0
  182. package/src/render/bloomChain.ts +3 -3
  183. package/src/render/boneAnimation.ts +223 -0
  184. package/src/render/compressedSource.ts +121 -29
  185. package/src/render/glCompressed.ts +83 -0
  186. package/src/render/globalMediumPass.ts +7 -0
  187. package/src/render/indexWidth.ts +27 -0
  188. package/src/render/instances.ts +27 -0
  189. package/src/render/lightBudget.ts +11 -0
  190. package/src/render/lightMatrix.ts +15 -0
  191. package/src/render/lightmap.ts +1 -1
  192. package/src/render/mesh.ts +72 -14
  193. package/src/render/pointLightSelection.ts +4 -4
  194. package/src/render/renderQuality.ts +38 -0
  195. package/src/render/rendererHarness.ts +15 -0
  196. package/src/render/screenSpaceReflection.ts +2 -1
  197. package/src/render/shader.ts +59 -0
  198. package/src/render/shaders/boneAnimation.ts +63 -0
  199. package/src/render/shaders/depth.ts +45 -10
  200. package/src/render/shaders/flat/directionalShadow.ts +84 -10
  201. package/src/render/shaders/flat/glassTint.ts +7 -1
  202. package/src/render/shaders/flat/index.ts +63 -7
  203. package/src/render/shaders/flat/layered.ts +115 -0
  204. package/src/render/shaders/flat/main.ts +58 -21
  205. package/src/render/shaders/flat/mapReads.ts +38 -0
  206. package/src/render/shaders/flat/models.ts +1 -1
  207. package/src/render/shaders/flat/movingSun.ts +46 -0
  208. package/src/render/shaders/flat/normalMap.ts +14 -3
  209. package/src/render/shaders/flat/overlay.ts +42 -20
  210. package/src/render/shaders/flat/pointShadow.ts +2 -2
  211. package/src/render/shaders/flat/preamble.ts +59 -27
  212. package/src/render/shaders/flat/worldUv.ts +113 -0
  213. package/src/render/shaders/generated/depth.wgsl.ts +95 -0
  214. package/src/render/shaders/generated/flat.wgsl.ts +3688 -3113
  215. package/src/render/shaders/generated/globalMedium.wgsl.ts +8 -3
  216. package/src/render/shaders/generated/lightVolume.wgsl.ts +16 -11
  217. package/src/render/shaders/globalMedium.ts +9 -1
  218. package/src/render/shaders/lightVolume.ts +9 -1
  219. package/src/render/shaders/outputTransform.ts +30 -14
  220. package/src/render/shaders/tangentFrame.ts +16 -3
  221. package/src/render/shaders/vertexChannel.ts +27 -0
  222. package/src/render/skinnedClothRun.ts +138 -38
  223. package/src/render/staticDraws.ts +95 -0
  224. package/src/render/surfaceLayers.ts +57 -0
  225. package/src/render/surfaceOverlay.ts +24 -7
  226. package/src/render/surfaceProjection.ts +57 -0
  227. package/src/render/surfaceTexture.ts +124 -27
  228. package/src/render/vertexPacking.ts +109 -0
  229. package/dist/render/backend/webgpu/gpuSkinnedCloth.d.ts +0 -74
  230. package/dist/render/backend/webgpu/gpuSkinnedCloth.js +0 -452
  231. package/src/render/backend/webgpu/gpuSkinnedCloth.ts +0 -502
@@ -3,6 +3,13 @@
3
3
  import { MorphTexture } from './backend/webgl2/morphTexture.ts';
4
4
  import { ABSENT_ATTRIBUTE } from './vertexDefaults.ts';
5
5
  import { UPLOAD_BYTES_PER_STEP } from './uploadStep.ts';
6
+ import { compactIndices } from './indexWidth.ts';
7
+ import {
8
+ fixedArray,
9
+ sharedValue,
10
+ vertexPackingOf,
11
+ type AttributePacking,
12
+ } from './vertexPacking.ts';
6
13
 
7
14
  /*
8
15
  * `MeshData` and its validator live in `@driftengine/drft`, because the container's whole
@@ -92,7 +99,14 @@ export class Mesh {
92
99
  private readonly vao: WebGLVertexArrayObject;
93
100
  private readonly buffers: WebGLBuffer[] = [];
94
101
  /** Every attribute bound from a buffer, so a batch can build a vertex array of its own. */
95
- private readonly layout: { location: number; buffer: WebGLBuffer; size: number }[] = [];
102
+ private readonly layout: {
103
+ location: number;
104
+ buffer: WebGLBuffer;
105
+ size: number;
106
+ /** `FLOAT`, or a sixteen-bit type read normalised: `vertexPacking.ts`. */
107
+ type: number;
108
+ normalized: boolean;
109
+ }[] = [];
96
110
  private indexBuffer: WebGLBuffer | null = null;
97
111
  /**
98
112
  * The position and normal buffers, kept so `update` can rewrite them.
@@ -110,6 +124,8 @@ export class Mesh {
110
124
  * same frame.
111
125
  */
112
126
  readonly indexCount: number;
127
+ /** `UNSIGNED_SHORT` or `UNSIGNED_INT`, as `compactIndices` stored them: every draw says which. */
128
+ private readonly indexType: number;
113
129
  /**
114
130
  * The constant values this mesh's *absent* attributes are shaded with, re-applied on
115
131
  * every draw.
@@ -149,6 +165,11 @@ export class Mesh {
149
165
  readonly isSkinnedEight: boolean;
150
166
  /** Whether it has texture coordinates, without which a material's maps read one texel. */
151
167
  readonly hasUvs: boolean;
168
+ /**
169
+ * Whether it carries a grain lane, which is where second coordinates ride (`lightmap.ts`): what
170
+ * a bone animation reads each vertex's bone from.
171
+ */
172
+ readonly hasGrain: boolean;
152
173
  /** How many vertices it has, which a cloth binding is checked against. */
153
174
  readonly vertexCount: number;
154
175
 
@@ -221,11 +242,13 @@ export class Mesh {
221
242
  * that has been told a lie every frame is the shape of a stall nobody can find.
222
243
  */
223
244
  const usage = dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;
245
+ /* How each attribute travels: sixteen-bit fixed point, or one value as a constant. */
246
+ const packing = vertexPackingOf(data, dynamic);
224
247
  const positions = this.attachAttribute(gl, ATTR_POSITION, data.positions, 3, usage);
225
- const normals = this.attachAttribute(gl, ATTR_NORMAL, data.normals, 3, usage);
248
+ const normals = this.attachAttribute(gl, ATTR_NORMAL, data.normals, 3, usage, packing.normals);
226
249
  if (dynamic) this.deformable = { positions, normals };
227
- this.attachAttribute(gl, ATTR_COLOR, data.colors, 3);
228
- this.attachAttribute(gl, ATTR_EMISSIVE, data.emissive, 1);
250
+ this.attachShared(gl, ATTR_COLOR, data.colors, 3, packing.colors);
251
+ this.attachShared(gl, ATTR_EMISSIVE, data.emissive, 1, packing.emissive);
229
252
  /*
230
253
  * Absent means "not shiny", supplied as a constant rather than as a buffer of
231
254
  * zeroes. `vertexAttrib1f` sets the value a *disabled* attribute reads, so this
@@ -299,7 +322,7 @@ export class Mesh {
299
322
  this.constants.push({ location: ATTR_WEIGHTS, value: ABSENT_ATTRIBUTE['weights'] });
300
323
  } else {
301
324
  this.attachAttribute(gl, ATTR_JOINTS, data.joints, 4);
302
- this.attachAttribute(gl, ATTR_WEIGHTS, data.weights, 4);
325
+ this.attachAttribute(gl, ATTR_WEIGHTS, data.weights, 4, gl.STATIC_DRAW, packing.weights);
303
326
  }
304
327
  /* The fifth to eighth influences, or zeros, which add nothing. See `isSkinnedEight`. */
305
328
  this.isSkinnedEight = this.isSkinned && data.joints2 !== undefined;
@@ -308,7 +331,7 @@ export class Mesh {
308
331
  this.constants.push({ location: ATTR_WEIGHTS2, value: ABSENT_ATTRIBUTE['weights2'] });
309
332
  } else {
310
333
  this.attachAttribute(gl, ATTR_JOINTS2, data.joints2, 4);
311
- this.attachAttribute(gl, ATTR_WEIGHTS2, data.weights2, 4);
334
+ this.attachAttribute(gl, ATTR_WEIGHTS2, data.weights2, 4, gl.STATIC_DRAW, packing.weights2);
312
335
  }
313
336
 
314
337
  this.hasTangents = data.tangents !== undefined;
@@ -316,9 +339,10 @@ export class Mesh {
316
339
  gl.disableVertexAttribArray(ATTR_TANGENT);
317
340
  this.constants.push({ location: ATTR_TANGENT, value: ABSENT_ATTRIBUTE['tangents'] });
318
341
  } else {
319
- this.attachAttribute(gl, ATTR_TANGENT, data.tangents, 4);
342
+ this.attachAttribute(gl, ATTR_TANGENT, data.tangents, 4, gl.STATIC_DRAW, packing.tangents);
320
343
  }
321
344
 
345
+ this.hasGrain = data.grain !== undefined;
322
346
  if (data.grain === undefined) {
323
347
  gl.disableVertexAttribArray(ATTR_GRAIN);
324
348
  this.constants.push({ location: ATTR_GRAIN, value: ABSENT_ATTRIBUTE['grain'] });
@@ -345,7 +369,9 @@ export class Mesh {
345
369
  this.buffers.push(indexBuffer);
346
370
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
347
371
  this.indexBuffer = indexBuffer;
348
- this.allocate(gl, gl.ELEMENT_ARRAY_BUFFER, indexBuffer, data.indices, gl.STATIC_DRAW);
372
+ const indices = compactIndices(data.indices, this.vertexCount);
373
+ this.indexType = indices instanceof Uint16Array ? gl.UNSIGNED_SHORT : gl.UNSIGNED_INT;
374
+ this.allocate(gl, gl.ELEMENT_ARRAY_BUFFER, indexBuffer, indices, gl.STATIC_DRAW);
349
375
 
350
376
  gl.bindVertexArray(null);
351
377
  }
@@ -364,7 +390,7 @@ export class Mesh {
364
390
  const value = constant.value;
365
391
  applyConstant(gl, constant.location, value);
366
392
  }
367
- gl.drawElements(gl.TRIANGLES, this.indexCount, gl.UNSIGNED_INT, 0);
393
+ gl.drawElements(gl.TRIANGLES, this.indexCount, this.indexType, 0);
368
394
  }
369
395
 
370
396
  /**
@@ -388,7 +414,14 @@ export class Mesh {
388
414
  for (const attribute of this.layout) {
389
415
  gl.bindBuffer(gl.ARRAY_BUFFER, attribute.buffer);
390
416
  gl.enableVertexAttribArray(attribute.location);
391
- gl.vertexAttribPointer(attribute.location, attribute.size, gl.FLOAT, false, 0, 0);
417
+ gl.vertexAttribPointer(
418
+ attribute.location,
419
+ attribute.size,
420
+ attribute.type,
421
+ attribute.normalized,
422
+ 0,
423
+ 0,
424
+ );
392
425
  }
393
426
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
394
427
  gl.bindBuffer(gl.ARRAY_BUFFER, instances);
@@ -418,7 +451,7 @@ export class Mesh {
418
451
  const value = constant.value;
419
452
  applyConstant(gl, constant.location, value);
420
453
  }
421
- gl.drawElementsInstanced(gl.TRIANGLES, this.indexCount, gl.UNSIGNED_INT, 0, count);
454
+ gl.drawElementsInstanced(gl.TRIANGLES, this.indexCount, this.indexType, 0, count);
422
455
  }
423
456
 
424
457
  dispose(gl: WebGL2RenderingContext): void {
@@ -462,24 +495,49 @@ export class Mesh {
462
495
  }
463
496
  }
464
497
 
498
+ /**
499
+ * One attribute's buffer, as floats or in its sixteen-bit fixed point (`vertexPacking.ts`), which
500
+ * WebGL2 reads back through a normalised `SHORT` or `UNSIGNED_SHORT`: three lanes wide where
501
+ * WebGPU needs four, so a normal costs six bytes here.
502
+ */
465
503
  private attachAttribute(
466
504
  gl: WebGL2RenderingContext,
467
505
  location: number,
468
506
  data: Float32Array,
469
507
  size: number,
470
508
  usage: number = gl.STATIC_DRAW,
509
+ packing: AttributePacking = 'float',
471
510
  ): WebGLBuffer {
472
511
  const buffer = gl.createBuffer();
473
512
  if (buffer === null) throw new Error('createBuffer failed');
474
513
  this.buffers.push(buffer);
475
514
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
476
- this.allocate(gl, gl.ARRAY_BUFFER, buffer, data, usage);
515
+ const fixed = packing === 'snorm16' || packing === 'unorm16';
516
+ this.allocate(gl, gl.ARRAY_BUFFER, buffer, fixed ? fixedArray(data, packing) : data, usage);
517
+ const type =
518
+ packing === 'snorm16' ? gl.SHORT : packing === 'unorm16' ? gl.UNSIGNED_SHORT : gl.FLOAT;
477
519
  gl.enableVertexAttribArray(location);
478
- gl.vertexAttribPointer(location, size, gl.FLOAT, false, 0, 0);
479
- this.layout.push({ location, buffer, size });
520
+ gl.vertexAttribPointer(location, size, type, fixed, 0, 0);
521
+ this.layout.push({ location, buffer, size, type, normalized: fixed });
480
522
  return buffer;
481
523
  }
482
524
 
525
+ /** A buffer, or the one value every vertex shares as a constant, as the packing says. */
526
+ private attachShared(
527
+ gl: WebGL2RenderingContext,
528
+ location: number,
529
+ data: Float32Array,
530
+ size: number,
531
+ packing: AttributePacking,
532
+ ): void {
533
+ if (packing !== 'constant') {
534
+ this.attachAttribute(gl, location, data, size, gl.STATIC_DRAW, packing);
535
+ return;
536
+ }
537
+ gl.disableVertexAttribArray(location);
538
+ this.constants.push({ location, value: sharedValue(data, size) });
539
+ }
540
+
483
541
  /**
484
542
  * Give a bound buffer its storage, and its contents now or later.
485
543
  *
@@ -204,10 +204,10 @@ export interface PointLightSource {
204
204
  inLightField?: boolean;
205
205
  /**
206
206
  * How the light fades with distance when it names its own way: `(1 - (d/R)^2)^n` with no distance
207
- * term, `R` its radius and `n` this. Unreal's falloff for a light without inverse-square falloff,
208
- * so a rig authored there — a fill of brightness 160 across 164 m, a key at exponent 8 — lights
209
- * the space it was authored for rather than one that ends a few metres out. Absent or 0, the
210
- * frame's own falloff (`pointLightFalloff`), which is every light before 4.8.7.
207
+ * term, `R` its radius and `n` this. The usual falloff for a light without inverse-square
208
+ * falloff, so a rig authored that way — a fill of brightness 160 across 164 m, a key at exponent
209
+ * 8 — lights the space it was authored for rather than one that ends a few metres out. Absent or
210
+ * 0, the frame's own falloff (`pointLightFalloff`), which is every light before 4.8.7.
211
211
  */
212
212
  falloffExponent?: number;
213
213
  }
@@ -50,6 +50,9 @@ export type ShadowFilterTaps = 4 | 8 | 12;
50
50
  export type DirectionalShadowDepthLayers = 1 | 2;
51
51
  export type WaterReflectionFilterTaps = 1 | 5 | 9;
52
52
 
53
+ /** What a draw does when its pipeline has not compiled yet: see `RenderQuality.pipelineCompile`. */
54
+ export type PipelineCompile = 'wait' | 'skip';
55
+
53
56
  /** How light through glass is coloured: see `RenderQuality.glassShadows`. */
54
57
  export type GlassShadows = 'full' | 'half' | 'off';
55
58
 
@@ -220,6 +223,34 @@ export interface RenderQuality {
220
223
  * lot of glass; that is what `'half'` is for. See `glassShadow.ts`.
221
224
  */
222
225
  readonly glassShadows: GlassShadows;
226
+ /**
227
+ * What a lit draw does when the pipeline it needs has not compiled: one first needed inside a
228
+ * frame, by a material's own state — two-sided, cut out, a surface model — or a draw state a
229
+ * mesh's creation did not warm.
230
+ *
231
+ * **`'wait'`, the default**: the pipeline is built where the draw asks for it, and on WebGPU the
232
+ * browser compiles it on its GPU process's main thread, holding the frame — 130 to 400 ms a
233
+ * pipeline was reported on a phone, for a material first drawn mid-scene. **`'skip'`** starts the
234
+ * compile off that thread and leaves the draw out until it lands, a few frames to a few dozen,
235
+ * and the draw then appears; nothing waits. Static draws always wait, since a recorded list keeps
236
+ * what it recorded, and a compile that fails is built where it is next asked for, so the device
237
+ * says why rather than the draw vanishing for good.
238
+ *
239
+ * **The way to have neither** is to draw what a scene will use once, behind a loading screen, and
240
+ * await `ready()`, which waits for every compile started — whichever this says. What would make
241
+ * `'skip'` wrong is a frame that must hold everything it was given, such as a capture of the first
242
+ * frame of a scene not awaited.
243
+ *
244
+ * **Measured on a desktop GPU** (`demo/dev/pipelineCompile.html`, eight new variants at once): on
245
+ * WebGPU the frame that met them took 700 to 3,700 ms waiting and 17 ms skipping, the draws
246
+ * landing 21 to 26 frames later. WebGL2 compiles its lit programs when it is made, all but a
247
+ * surface model's, which it compiles at the first draw that wants one: there `'skip'` asks the
248
+ * driver through `KHR_parallel_shader_compile` and waits where a context does not offer it — which
249
+ * ANGLE on Vulkan does not. Where it is offered, ANGLE on OpenGL, the longest frame went from 820 to
250
+ * 1,120 ms to 630 to 700 ms: the driver still finishes its own compile at the program's first
251
+ * draw, which nothing above it can move.
252
+ */
253
+ readonly pipelineCompile: PipelineCompile;
223
254
  /**
224
255
  * How light that scatters beneath skin is drawn, for a material whose model is `skinModel`.
225
256
  *
@@ -973,6 +1004,7 @@ export const DEFAULT_RENDER_QUALITY: Readonly<RenderQuality> = Object.freeze({
973
1004
  lightVolumeSamples: 32,
974
1005
  directionalShadowDepthLayers: 2,
975
1006
  glassShadows: 'full',
1007
+ pipelineCompile: 'wait',
976
1008
  skinScattering: 'pre-integrated',
977
1009
  directionalShadowMaxDistance: 6,
978
1010
  directionalShadowMaxSlope: 3,
@@ -1140,6 +1172,7 @@ export function resolveRenderQuality(options: RenderQualityOptions = {}): Readon
1140
1172
  directionalShadowDepthLayers:
1141
1173
  options.directionalShadowDepthLayers ?? DEFAULT_RENDER_QUALITY.directionalShadowDepthLayers,
1142
1174
  glassShadows: options.glassShadows ?? DEFAULT_RENDER_QUALITY.glassShadows,
1175
+ pipelineCompile: options.pipelineCompile ?? DEFAULT_RENDER_QUALITY.pipelineCompile,
1143
1176
  skinScattering: options.skinScattering ?? DEFAULT_RENDER_QUALITY.skinScattering,
1144
1177
  directionalShadowMaxDistance:
1145
1178
  options.directionalShadowMaxDistance ?? DEFAULT_RENDER_QUALITY.directionalShadowMaxDistance,
@@ -1298,6 +1331,11 @@ export function resolveRenderQuality(options: RenderQualityOptions = {}): Readon
1298
1331
  `RenderQuality.glassShadows must be 'full', 'half' or 'off', got ${String(quality.glassShadows)}`,
1299
1332
  );
1300
1333
  }
1334
+ if (quality.pipelineCompile !== 'wait' && quality.pipelineCompile !== 'skip') {
1335
+ throw new Error(
1336
+ `RenderQuality.pipelineCompile must be 'wait' or 'skip', got ${String(quality.pipelineCompile)}`,
1337
+ );
1338
+ }
1301
1339
  if (quality.skinScattering !== 'pre-integrated' && quality.skinScattering !== 'screen-space') {
1302
1340
  throw new Error(
1303
1341
  `RenderQuality.skinScattering must be 'pre-integrated' or 'screen-space', got ${String(quality.skinScattering)}`,
@@ -58,8 +58,14 @@ export function recordingGl(
58
58
  * recording.
59
59
  */
60
60
  readonly uniforms?: readonly string[];
61
+ /**
62
+ * Whether a program started under `KHR_parallel_shader_compile` has finished, which the test
63
+ * flips: `COMPLETION_STATUS_KHR` answers `done`. Finished by default, as every program here is.
64
+ */
65
+ readonly compiling?: { done: boolean };
61
66
  } = {},
62
67
  ) {
68
+ const compiling = options.compiling ?? { done: true };
63
69
  const extensions = new Set(options.extensions ?? []);
64
70
  const uniforms = options.uniforms ?? [];
65
71
  /* What `clearDepth` last set, so a module that borrows the value can be seen to put it back. */
@@ -136,6 +142,13 @@ export function recordingGl(
136
142
  HALF_FLOAT: 0x140b,
137
143
  DEPTH_COMPONENT: 0x1902,
138
144
  UNSIGNED_INT: 0x1405,
145
+ /* Named so a mesh's index width and each attribute's type can be read back: the buffer its
146
+ indices fill, the type every draw of it names, and how each attribute is read. See
147
+ `mesh.test.ts`. */
148
+ UNSIGNED_SHORT: 0x1403,
149
+ SHORT: 0x1402,
150
+ FLOAT: 0x1406,
151
+ ELEMENT_ARRAY_BUFFER: 0x8893,
139
152
  LINEAR: 0x2601,
140
153
  COLOR_BUFFER_BIT: 0x00004000,
141
154
  /* Named so a test can tell a mesh that declared itself deforming from one that did not. */
@@ -173,6 +186,7 @@ export function recordingGl(
173
186
  if (name === 'EXT_clip_control') {
174
187
  return { LOWER_LEFT_EXT: 0x8ca1, ZERO_TO_ONE_EXT: 0x935f, clipControlEXT: () => undefined };
175
188
  }
189
+ if (name === 'KHR_parallel_shader_compile') return { COMPLETION_STATUS_KHR: 0x91b1 };
176
190
  return {};
177
191
  },
178
192
  getShaderParameter: () => true,
@@ -200,6 +214,7 @@ export function recordingGl(
200
214
  /* Linked yes; zero active uniforms and attributes, which ends every reflection loop at once
201
215
  and is why this harness does not have to know a single uniform name. */
202
216
  getProgramParameter: (program: unknown, pname: unknown) => {
217
+ if (pname === 0x91b1) return compiling.done;
203
218
  if (pname === constants.ACTIVE_UNIFORMS) return uniforms.length;
204
219
  if (pname === constants.ACTIVE_ATTRIBUTES) return 0;
205
220
  if (pname !== constants.LINK_STATUS) return true;
@@ -370,7 +370,8 @@ export interface ReflectiveSurfaceOptions extends DecalBox {
370
370
  * box. Each pixel then returns `F0 · A + B` of what its ray finds, the split-sum environment BRDF
371
371
  * at its own view and `roughness` — Karis's fit, the one the lit stage reflects its environment
372
372
  * by — so a floor returns more toward the horizon than underfoot, and the share follows the
373
- * camera as Unreal weighs its reflections. **False by default**, the one share as before.
373
+ * camera as a physically based renderer weighs its reflections. **False by default**, the one
374
+ * share as before.
374
375
  *
375
376
  * **What it gives up**: the pass has no material buffer, so the roughness and F0 are the box's,
376
377
  * not each pixel's, and nothing occludes the reflection where the lit stage's ambient occlusion
@@ -26,6 +26,65 @@ export function compileProgram(
26
26
  return program;
27
27
  }
28
28
 
29
+ /**
30
+ * A program compiled and linked without asking whether that worked, since asking waits for the
31
+ * driver to finish: for a context offering `KHR_parallel_shader_compile`, whose
32
+ * `COMPLETION_STATUS_KHR` says when asking no longer waits. `finishProgram` asks then, and fails
33
+ * as loudly as `compileProgram` does; the stages are kept until it does, for their logs.
34
+ */
35
+ export interface StartedProgram {
36
+ readonly program: WebGLProgram;
37
+ readonly vertex: WebGLShader;
38
+ readonly fragment: WebGLShader;
39
+ readonly label: string;
40
+ }
41
+
42
+ export function startProgram(
43
+ gl: WebGL2RenderingContext,
44
+ vertexSource: string,
45
+ fragmentSource: string,
46
+ label: string,
47
+ ): StartedProgram {
48
+ const stage = (type: number, source: string, name: string): WebGLShader => {
49
+ const shader = gl.createShader(type);
50
+ if (shader === null) throw new Error(`[${label}.${name}] createShader failed`);
51
+ gl.shaderSource(shader, source);
52
+ gl.compileShader(shader);
53
+ return shader;
54
+ };
55
+ const vertex = stage(gl.VERTEX_SHADER, vertexSource, 'vert');
56
+ const fragment = stage(gl.FRAGMENT_SHADER, fragmentSource, 'frag');
57
+ const program = gl.createProgram();
58
+ if (program === null) throw new Error(`[${label}] createProgram failed`);
59
+ gl.attachShader(program, vertex);
60
+ gl.attachShader(program, fragment);
61
+ gl.linkProgram(program);
62
+ return { program, vertex, fragment, label };
63
+ }
64
+
65
+ /** A started program, checked as `compileProgram` checks one: its stages, then its link. */
66
+ export function finishProgram(gl: WebGL2RenderingContext, started: StartedProgram): WebGLProgram {
67
+ const { program, vertex, fragment, label } = started;
68
+ const fail = (what: string, log: string | null): never => {
69
+ gl.deleteShader(vertex);
70
+ gl.deleteShader(fragment);
71
+ gl.deleteProgram(program);
72
+ throw new Error(`[${label}${what}] ${log ?? 'no log'}`);
73
+ };
74
+ if (!gl.getShaderParameter(vertex, gl.COMPILE_STATUS)) {
75
+ fail('.vert compile failed:', gl.getShaderInfoLog(vertex));
76
+ }
77
+ if (!gl.getShaderParameter(fragment, gl.COMPILE_STATUS)) {
78
+ fail('.frag compile failed:', gl.getShaderInfoLog(fragment));
79
+ }
80
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
81
+ fail(' link failed:', gl.getProgramInfoLog(program));
82
+ }
83
+ gl.deleteShader(vertex);
84
+ gl.deleteShader(fragment);
85
+ return program;
86
+ }
87
+
29
88
  /**
30
89
  * Whether a uniform lookup that cannot reach the GPU is reported.
31
90
  *
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The vertex-stage bone animation: a crowd instance's vertex turned and placed by its bone, at its
3
+ * instance's moment of the clip — the GLSL of `boneAnimation.ts`'s `animateBoneVertex`, line for
4
+ * line. Shared by the lit stage and the depth stage, so a crowd's shadow moves with it.
5
+ *
6
+ * **Three textures, read by index and never filtered**: the places and the turns, a texel a bone a
7
+ * frame (bones across, frames down, sizes read with `textureSize` so no uniform says them), and the
8
+ * batch's clocks, two floats an instance wrapped onto rows, read at `gl_InstanceID`. The clip's speed
9
+ * and its bone scale are the one uniform, `uBoneClip`; the scene's time is the pass's `uSceneTime`.
10
+ *
11
+ * **The bone is read from the grain lane**, which is where a mesh's second coordinates ride, stored
12
+ * as `-1 - u` (`lightmap.ts`). An instanced batch reads no grain of its own from that lane: a crowd's
13
+ * mesh carries second coordinates, which is what makes it one.
14
+ *
15
+ * Integer arithmetic for the lattice, by the 2026-09-20 rule, except where a float is clamped onto
16
+ * it: the first frame is `min(floor(wrapped), frames - 1)`, so the wrap that division-by-reciprocal
17
+ * lands on `frames` is the last frame fully blended into the first — the first, which is right.
18
+ */
19
+ export const BONE_ANIMATION_GLSL = `
20
+ uniform highp sampler2D uBonePlaces;
21
+ uniform highp sampler2D uBoneTurns;
22
+ uniform highp sampler2D uInstanceClocks;
23
+ /** x the clip's frames a second, y how many bones one unit of the second coordinates' u counts. */
24
+ uniform vec2 uBoneClip;
25
+
26
+ /** v turned by the unit quaternion q. */
27
+ vec3 boneTurn(vec4 q, vec3 v) {
28
+ return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);
29
+ }
30
+
31
+ /**
32
+ * Where the clip puts this vertex, from its place at rest; its normal and tangent turned with it.
33
+ */
34
+ vec3 boneAnimate(vec3 position, inout vec3 normal, inout vec3 tangent) {
35
+ ivec2 size = textureSize(uBonePlaces, 0);
36
+ int clocksWidth = textureSize(uInstanceClocks, 0).x;
37
+ vec2 clock = texelFetch(
38
+ uInstanceClocks,
39
+ ivec2(gl_InstanceID % clocksWidth, gl_InstanceID / clocksWidth),
40
+ 0
41
+ ).xy;
42
+ float moment = (uSceneTime * clock.y + clock.x) * uBoneClip.x;
43
+ float frames = float(size.y);
44
+ float wrapped = moment - frames * floor(moment / frames);
45
+ int first = min(int(floor(wrapped)), size.y - 1);
46
+ int second = first + 1 == size.y ? 0 : first + 1;
47
+ float blend = clamp(wrapped - float(first), 0.0, 1.0);
48
+ int bone = clamp(int(floor((-1.0 - aGrain) * uBoneClip.y + 0.5)), 0, size.x - 1);
49
+ vec4 q0 = texelFetch(uBoneTurns, ivec2(bone, first), 0);
50
+ vec4 q1 = texelFetch(uBoneTurns, ivec2(bone, second), 0);
51
+ /* The shorter arc: a quaternion and its negation are one turn. */
52
+ if (dot(q0, q1) < 0.0) q1 = -q1;
53
+ vec4 q = normalize(mix(q0, q1, blend));
54
+ vec3 place = mix(
55
+ texelFetch(uBonePlaces, ivec2(bone, first), 0).xyz,
56
+ texelFetch(uBonePlaces, ivec2(bone, second), 0).xyz,
57
+ blend
58
+ );
59
+ normal = boneTurn(q, normal);
60
+ tangent = boneTurn(q, tangent);
61
+ return boneTurn(q, position) + place;
62
+ }
63
+ `;
@@ -5,6 +5,7 @@ import { CUTOUT_DITHER_GLSL } from '../cutoutDither.ts';
5
5
  import { SKINNING_GLSL } from './skinning.ts';
6
6
  import { CLOTH_BINDING_GLSL } from './clothBinding.ts';
7
7
  import { CHANNEL_ATTRIBUTE, CHANNEL_BEND } from './vertexChannel.ts';
8
+ import { BONE_ANIMATION_GLSL } from './boneAnimation.ts';
8
9
 
9
10
  /**
10
11
  * Depth-only shadow pass. Its optional peel mode rejects the first recorded
@@ -78,6 +79,17 @@ uniform vec2 uUvOffset;
78
79
  uniform vec2 uAlphaCutout;
79
80
  #endif
80
81
 
82
+ #if ANIMATED
83
+ /*
84
+ * **A bone animation's, after every other declaration** so no field of the variants before it
85
+ * moves: the grain lane the vertex's bone rides in, the scene's clock, and the chunk the colour
86
+ * pass runs — the same expression, or a crowd's shadow stands still while the crowd moves.
87
+ */
88
+ layout(location = 8) in float aGrain;
89
+ uniform float uSceneTime;
90
+ ${BONE_ANIMATION_GLSL}
91
+ #endif
92
+
81
93
  out vec4 vLightPosition;
82
94
  #if CUTOUT
83
95
  /* The texture coordinate and, in z, the texture-array layer the face wears. */
@@ -99,6 +111,12 @@ void main() {
99
111
  #else
100
112
  vec4 local = vec4(aPosition, 1.0);
101
113
  #endif
114
+ #if ANIMATED
115
+ /* Turned and placed as the colour pass turns and places it; its normal and tangent unused. */
116
+ vec3 animatedNormal = vec3(0.0, 1.0, 0.0);
117
+ vec3 animatedTangent = vec3(1.0, 0.0, 0.0);
118
+ local = vec4(boneAnimate(local.xyz, animatedNormal, animatedTangent), 1.0);
119
+ #endif
102
120
  #if INSTANCED
103
121
  mat4 model = mat4(aInstanceModel0, aInstanceModel1, aInstanceModel2, aInstanceModel3);
104
122
  /* The bottom row is the instance's texture cell, rebuilt as the row it stands for: see flat. */
@@ -148,14 +166,14 @@ void main() {
148
166
  /** The rigid variant: the world, a prop, a mesh with no rig behind it. */
149
167
  export const DEPTH_VERT = resolveConditionals(
150
168
  DEPTH_VERT_SOURCE,
151
- { SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: false },
169
+ { SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: false, ANIMATED: false },
152
170
  'depth',
153
171
  );
154
172
 
155
173
  /** The skinned variant, which reads a joint palette and moves the vertex by it. */
156
174
  export const DEPTH_SKINNED_VERT = resolveConditionals(
157
175
  DEPTH_VERT_SOURCE,
158
- { SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: false },
176
+ { SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: false, ANIMATED: false },
159
177
  'depth-skinned',
160
178
  );
161
179
 
@@ -169,7 +187,7 @@ export const DEPTH_SKINNED_VERT = resolveConditionals(
169
187
  */
170
188
  export const DEPTH_INSTANCED_VERT = resolveConditionals(
171
189
  DEPTH_VERT_SOURCE,
172
- { SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: false },
190
+ { SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: false, ANIMATED: false },
173
191
  'depth-instanced',
174
192
  );
175
193
 
@@ -185,16 +203,33 @@ export const DEPTH_INSTANCED_VERT = resolveConditionals(
185
203
  */
186
204
  export const DEPTH_CUTOUT_VERT = resolveConditionals(
187
205
  DEPTH_VERT_SOURCE,
188
- { SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: false },
206
+ { SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: false, ANIMATED: false },
189
207
  'depth-cutout',
190
208
  );
191
209
 
192
210
  export const DEPTH_INSTANCED_CUTOUT_VERT = resolveConditionals(
193
211
  DEPTH_VERT_SOURCE,
194
- { SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: false },
212
+ { SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: false, ANIMATED: false },
195
213
  'depth-instanced-cutout',
196
214
  );
197
215
 
216
+ /**
217
+ * The variants a crowd casts through: an instanced batch playing a bone animation, its vertices
218
+ * where the clip puts them at each instance's moment. See `shaders/boneAnimation.ts`. No glass
219
+ * variant: a crowd is not glass, and a glass batch that animates casts its tint from rest.
220
+ */
221
+ export const DEPTH_INSTANCED_ANIMATED_VERT = resolveConditionals(
222
+ DEPTH_VERT_SOURCE,
223
+ { SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: false, ANIMATED: true },
224
+ 'depth-instanced-animated',
225
+ );
226
+
227
+ export const DEPTH_INSTANCED_ANIMATED_CUTOUT_VERT = resolveConditionals(
228
+ DEPTH_VERT_SOURCE,
229
+ { SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: false, ANIMATED: true },
230
+ 'depth-instanced-animated-cutout',
231
+ );
232
+
198
233
  export const DEPTH_FRAG = `#version 300 es
199
234
  precision highp float;
200
235
  in vec4 vLightPosition;
@@ -269,27 +304,27 @@ void main() {
269
304
  */
270
305
  export const GLASS_TINT_VERT = resolveConditionals(
271
306
  DEPTH_VERT_SOURCE,
272
- { SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: true },
307
+ { SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: true, ANIMATED: false },
273
308
  'glass-tint',
274
309
  );
275
310
  export const GLASS_TINT_SKINNED_VERT = resolveConditionals(
276
311
  DEPTH_VERT_SOURCE,
277
- { SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: true },
312
+ { SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: true, ANIMATED: false },
278
313
  'glass-tint-skinned',
279
314
  );
280
315
  export const GLASS_TINT_INSTANCED_VERT = resolveConditionals(
281
316
  DEPTH_VERT_SOURCE,
282
- { SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: true },
317
+ { SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: true, ANIMATED: false },
283
318
  'glass-tint-instanced',
284
319
  );
285
320
  export const GLASS_TINT_CUTOUT_VERT = resolveConditionals(
286
321
  DEPTH_VERT_SOURCE,
287
- { SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: true },
322
+ { SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: true, ANIMATED: false },
288
323
  'glass-tint-cutout',
289
324
  );
290
325
  export const GLASS_TINT_INSTANCED_CUTOUT_VERT = resolveConditionals(
291
326
  DEPTH_VERT_SOURCE,
292
- { SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: true },
327
+ { SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: true, ANIMATED: false },
293
328
  'glass-tint-instanced-cutout',
294
329
  );
295
330