@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
@@ -52,9 +52,13 @@ const FRAGMENT_BINDINGS = FLAT_BINDINGS.flatFrag;
52
52
  */
53
53
  const VERTEX_BINDINGS = FLAT_BINDINGS.flatVert;
54
54
  /** The key for a set of vertex flags: the same rule `variantKey` uses, flags on, sorted, joined. */
55
- export function flatVertexKey(skinned, morphed, instanced = false) {
55
+ export function flatVertexKey(skinned, morphed, instanced = false,
56
+ /** Whether an instanced variant plays a bone animation. See `shaders/boneAnimation.ts`. */
57
+ animated = false) {
56
58
  const on = [];
57
59
  /* Alphabetical, because the generator's own `variantKey` sorts and the two keys must agree. */
60
+ if (animated)
61
+ on.push('animated');
58
62
  if (instanced)
59
63
  on.push('instanced');
60
64
  if (morphed)
@@ -64,8 +68,8 @@ export function flatVertexKey(skinned, morphed, instanced = false) {
64
68
  return on.length === 0 ? 'none' : on.join('+');
65
69
  }
66
70
  /** Everything the generator recorded about one variant of the vertex stage. */
67
- export function flatVertexBindings(skinned, morphed = false, instanced = false) {
68
- const key = flatVertexKey(skinned, morphed, instanced);
71
+ export function flatVertexBindings(skinned, morphed = false, instanced = false, animated = false) {
72
+ const key = flatVertexKey(skinned, morphed, instanced, animated);
69
73
  const found = VERTEX_BINDINGS[key];
70
74
  if (found === undefined)
71
75
  throw new Error(`flatPass: no vertex bindings for variant "${key}"`);
@@ -136,6 +140,8 @@ for (const [key, bindings] of Object.entries(VERTEX_BINDINGS)) {
136
140
  }
137
141
  }
138
142
  export const FLAT_VERT_FIELDS = FLAT_BINDINGS.flatVert.none.fields;
143
+ /** The animated instanced variant's block: the instanced fields, and the clip's `uBoneClip`. */
144
+ export const FLAT_ANIMATED_VERT_FIELDS = FLAT_BINDINGS.flatVert['animated+instanced'].fields;
139
145
  /**
140
146
  * The **largest** variant's block, because one ring serves every draw.
141
147
  *
@@ -145,6 +151,30 @@ export const FLAT_VERT_FIELDS = FLAT_BINDINGS.flatVert.none.fields;
145
151
  */
146
152
  export const FLAT_VERT_SIZE = Math.max(...Object.values(VERTEX_BINDINGS).map((bindings) => bindings.uniformSize));
147
153
  const FLAT_VERT_BINDING = PLAIN_VERTEX.uniforms;
154
+ /*
155
+ * **The view block may be shorter in a variant, never different.** One slot serves every lit draw
156
+ * of a pass, plain and instanced alike, so every field a variant's view block declares must sit
157
+ * where the plain variant has it. The instanced variant declares no wind, and its block is the plain
158
+ * one's first two matrices.
159
+ */
160
+ const PLAIN_VIEW_FIELDS = PLAIN_VERTEX.viewFields ?? {};
161
+ for (const [key, bindings] of Object.entries(VERTEX_BINDINGS)) {
162
+ if (bindings.viewUniforms !== PLAIN_VERTEX.viewUniforms) {
163
+ throw new Error(`flatPass: vertex variant "${key}" binds its view block elsewhere`);
164
+ }
165
+ for (const [field, here] of Object.entries(bindings.viewFields ?? {})) {
166
+ if (PLAIN_VIEW_FIELDS[field]?.offset !== here.offset) {
167
+ throw new Error(`flatPass: vertex variant "${key}" puts view field ${field} at ${here.offset} where the ` +
168
+ `plain variant has it at ${PLAIN_VIEW_FIELDS[field]?.offset}.`);
169
+ }
170
+ }
171
+ }
172
+ /** The view block's fields, binding and size: the largest variant's, as `FLAT_VERT_SIZE` is. */
173
+ export const FLAT_VIEW_FIELDS = PLAIN_VIEW_FIELDS;
174
+ export const FLAT_VIEW_SIZE = Math.max(...Object.values(VERTEX_BINDINGS).map((bindings) => bindings.viewSize ?? 0));
175
+ const FLAT_VIEW_BINDING = PLAIN_VERTEX.viewUniforms ?? -1;
176
+ if (FLAT_VIEW_BINDING < 0)
177
+ throw new Error('flatPass: the lit vertex stage declares no view block');
148
178
  /**
149
179
  * The most sampled textures and distinct samplers any lit variant carrying the environment probe
150
180
  * binds in its fragment stage, counted from the generated bindings: what a device must allow per
@@ -170,6 +200,26 @@ export function flatFragmentBindings(variant) {
170
200
  throw new Error(`flatPass: no bindings for variant "${variant}"`);
171
201
  return found;
172
202
  }
203
+ export function flatFragmentScratch(variant) {
204
+ const bindings = flatFragmentBindings(variant);
205
+ const { materialUniforms, materialSize, materialFields } = bindings;
206
+ if (materialUniforms === undefined ||
207
+ materialSize === undefined ||
208
+ materialFields === undefined) {
209
+ throw new Error(`flatPass: variant "${variant}" has no material block`);
210
+ }
211
+ const fields = { ...bindings.fields };
212
+ for (const [name, field] of Object.entries(materialFields)) {
213
+ fields[name] = { ...field, offset: bindings.uniformSize + field.offset };
214
+ }
215
+ return {
216
+ fields,
217
+ passSize: bindings.uniformSize,
218
+ passBinding: bindings.uniforms,
219
+ materialSize,
220
+ materialBinding: materialUniforms,
221
+ };
222
+ }
173
223
  /**
174
224
  * The lit fragment stage's constants, set from the cache's switches, keyed by each one's **id**.
175
225
  *
@@ -209,6 +259,13 @@ function flatFragmentConstants(variant, cache, model, skinPass = 'whole', reflec
209
259
  }
210
260
  return constants;
211
261
  }
262
+ /** The material block's binding, which every lit variant declares. */
263
+ function materialBinding(fragment) {
264
+ if (fragment.materialUniforms === undefined) {
265
+ throw new Error('flatPass: the lit fragment stage declares no material block');
266
+ }
267
+ return fragment.materialUniforms;
268
+ }
212
269
  /** The depth format both backends compare with. */
213
270
  /* Re-exported so the twenty passes that already import it from here do not each learn a new
214
271
  module; `depthConvention.ts` is where the decision lives and why. */
@@ -218,11 +275,15 @@ const VISIBILITY_FRAGMENT = 0x2;
218
275
  /**
219
276
  * The layout this variant binds against.
220
277
  *
221
- * The vertex block is **dynamic**, because every draw supplies its own model matrix and tint
222
- * from its own slot of one buffer. The fragment block is not: it holds the lights, the fog
223
- * and the camera, settled once by `bindMeshPass` and unchanged between draws.
278
+ * All four blocks are **dynamic**: the vertex block because every draw supplies its own model
279
+ * matrix and tint from its own slot of one buffer; the fragment stage's pass block — the lights, the
280
+ * fog, the camera — and the vertex stage's view block because a frame binds more than one pass; and
281
+ * the material block because a material changes between draws. Their dynamic offsets go in binding
282
+ * order: the draw's, the pass's, the material's, the view's.
224
283
  */
225
- export function createFlatBindGroupLayout(device, variant, skinned = false, morphed = false) {
284
+ export function createFlatBindGroupLayout(device, variant, skinned = false, morphed = false,
285
+ /** The instanced variant that plays a bone animation: its three vertex textures. */
286
+ animated = false) {
226
287
  const fragment = flatFragmentBindings(variant);
227
288
  const entries = [
228
289
  {
@@ -230,15 +291,31 @@ export function createFlatBindGroupLayout(device, variant, skinned = false, morp
230
291
  visibility: VISIBILITY_VERTEX,
231
292
  buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: FLAT_VERT_SIZE },
232
293
  },
294
+ {
295
+ binding: FLAT_VIEW_BINDING,
296
+ visibility: VISIBILITY_VERTEX,
297
+ /* Dynamic, a slot a pass, for the reason the fragment stage's pass block is. */
298
+ buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: FLAT_VIEW_SIZE },
299
+ },
233
300
  {
234
301
  binding: fragment.uniforms,
235
302
  visibility: VISIBILITY_FRAGMENT,
236
303
  /*
237
- * Dynamic, because this block carries the material and a material changes between draws.
238
- * See `WebGPURenderer.perFrame` for why one buffer cannot hold two answers.
304
+ * Dynamic, because a pass's lights and camera change between passes of one frame — a
305
+ * mirror's, a capture's — and one buffer cannot hold two answers. See `WebGPURenderer.passRing`.
239
306
  */
240
307
  buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: fragment.uniformSize },
241
308
  },
309
+ {
310
+ binding: materialBinding(fragment),
311
+ visibility: VISIBILITY_FRAGMENT,
312
+ /* Dynamic, because a material changes between draws. See `MaterialStore`. */
313
+ buffer: {
314
+ type: 'uniform',
315
+ hasDynamicOffset: true,
316
+ minBindingSize: fragment.materialSize ?? 0,
317
+ },
318
+ },
242
319
  ];
243
320
  /** What each sampler binding was declared as, so a shared one is declared once and agrees. */
244
321
  const samplerKind = new Map();
@@ -379,11 +456,33 @@ export function createFlatBindGroupLayout(device, variant, skinned = false, morp
379
456
  });
380
457
  }
381
458
  }
459
+ /* A bone animation's places, turns and the batch's clocks, read by index as the palette is. */
460
+ if (animated) {
461
+ for (const binding of animationBindings()) {
462
+ entries.push({
463
+ binding,
464
+ visibility: VISIBILITY_VERTEX,
465
+ texture: { sampleType: 'unfilterable-float' },
466
+ });
467
+ }
468
+ }
382
469
  return device.createBindGroupLayout({
383
- label: `flat.layout:${variant}|${flatVertexKey(skinned, morphed)}`,
470
+ label: `flat.layout:${variant}|${flatVertexKey(skinned, morphed, animated, animated)}`,
384
471
  entries,
385
472
  });
386
473
  }
474
+ /** The three textures a bone animation binds, in the order `AnimationViews` holds them. */
475
+ function animationBindings() {
476
+ const textures = flatVertexBindings(false, false, true, true).textures;
477
+ const at = (name) => {
478
+ const found = textures[name];
479
+ if (found === undefined) {
480
+ throw new Error(`flatPass: the animated vertex shader declares no ${name}`);
481
+ }
482
+ return found.texture;
483
+ };
484
+ return [at('uBonePlaces'), at('uBoneTurns'), at('uInstanceClocks')];
485
+ }
387
486
  /**
388
487
  * Bind the buffers and one view per declared texture.
389
488
  *
@@ -393,20 +492,27 @@ export function createFlatBindGroupLayout(device, variant, skinned = false, morp
393
492
  * and WebGPU still requires something there, which is why `renderer.ts` keeps an
394
493
  * `emptyTexture2D` for the same reason on the other side.
395
494
  */
396
- export function createFlatBindGroup(device, layout, variant, perDraw, perFrame, resolve,
495
+ export function createFlatBindGroup(device, layout, variant, perDraw, passes, materials, views, resolve,
397
496
  /** The palette view for a skinned bind group, or null for an unskinned one. */
398
497
  palette = null,
399
498
  /** The delta view for a morphed bind group, or null for an unmorphed one. */
400
499
  deltas = null,
401
500
  /** A skinned bind group's cloth views — the draw's, or the stand-in where it sets none. */
402
- cloth = null) {
501
+ cloth = null,
502
+ /** An animated instanced group's views. See `AnimationViews`. */
503
+ animation = null) {
403
504
  const fragment = flatFragmentBindings(variant);
404
505
  const entries = [
405
506
  {
406
507
  binding: FLAT_VERT_BINDING,
407
508
  resource: { buffer: perDraw, size: FLAT_VERT_SIZE },
408
509
  },
409
- { binding: fragment.uniforms, resource: { buffer: perFrame, size: fragment.uniformSize } },
510
+ { binding: FLAT_VIEW_BINDING, resource: { buffer: views, size: FLAT_VIEW_SIZE } },
511
+ { binding: fragment.uniforms, resource: { buffer: passes, size: fragment.uniformSize } },
512
+ {
513
+ binding: materialBinding(fragment),
514
+ resource: { buffer: materials, size: fragment.materialSize ?? 0 },
515
+ },
410
516
  ];
411
517
  /* The same dedupe the layout does, and for the same reason: the shadow bindings share one
412
518
  sampler, and a bind group that filled it fifteen times would be rejected. Every member
@@ -441,8 +547,14 @@ cloth = null) {
441
547
  entries.push({ binding: particlesAt, resource: cloth.particles });
442
548
  entries.push({ binding: restAt, resource: cloth.rest });
443
549
  }
550
+ if (animation !== null) {
551
+ const [places, turns, clocks] = animationBindings();
552
+ entries.push({ binding: places, resource: animation.places });
553
+ entries.push({ binding: turns, resource: animation.turns });
554
+ entries.push({ binding: clocks, resource: animation.clocks });
555
+ }
444
556
  return device.createBindGroup({
445
- label: `flat.bindGroup:${variant}|${flatVertexKey(palette !== null, deltas !== null)}`,
557
+ label: `flat.bindGroup:${variant}|${flatVertexKey(palette !== null, deltas !== null, animation !== null, animation !== null)}`,
446
558
  layout,
447
559
  entries,
448
560
  });
@@ -510,8 +622,11 @@ skinPass = 'whole',
510
622
  * The reflection pass's surface half: the draw again, against its own depth, into the two
511
623
  * targets `reflectionSurfacePass.ts` holds. The key must carry it: `|rs`.
512
624
  */
513
- reflectionSurface = false) {
514
- return cache.get(key, () => flatDescriptor(cache, device, layout, variant, key, present, translucent, skinned, morphed, depthWrite, depthLayer, instanced, oit, doubleSided, alphaToCoverage, skinEight, cloth, model, skinPass, reflectionSurface), true);
625
+ reflectionSurface = false,
626
+ /** An instanced pipeline that plays a bone animation. The key must carry it: `|anim`. */
627
+ animated = false) {
628
+ /* None where draws skip a compile and this one has not landed: see `PipelineCache.lit`. */
629
+ return cache.lit(key, () => flatDescriptor(cache, device, layout, variant, key, present, translucent, skinned, morphed, depthWrite, depthLayer, instanced, oit, doubleSided, alphaToCoverage, skinEight, cloth, model, skinPass, reflectionSurface, animated));
515
630
  }
516
631
  /**
517
632
  * The same pipeline, compiled off the main thread.
@@ -591,7 +706,9 @@ oit = 'none',
591
706
  /** Culls nothing: a surface seen from both faces. */
592
707
  doubleSided = false, alphaToCoverage = false, skinEight = false,
593
708
  /** Whether its vertex stage places vertices by a cloth binding. See `clothBinding.ts`. */
594
- cloth = false, model = null, skinPass = 'whole', reflectionSurface = false) {
709
+ cloth = false, model = null, skinPass = 'whole', reflectionSurface = false,
710
+ /** An instanced pipeline that plays a bone animation. See `shaders/boneAnimation.ts`. */
711
+ animated = false) {
595
712
  const offset = depthOffsetForLayer(depthLayer);
596
713
  /* The diffuse and colour halves are the same surface again, into the blur's targets; and so is
597
714
  the reflection pass's surface half, into its two. */
@@ -606,12 +723,12 @@ cloth = false, model = null, skinPass = 'whole', reflectionSurface = false) {
606
723
  * layout validates, draws, and is wrong, exactly as this file's header says.
607
724
  */
608
725
  module: shaderModule(device, {
609
- label: `flat.vert:${flatVertexKey(skinned, morphed, instanced)}`,
610
- code: FLAT_VERT_WGSL[flatVertexKey(skinned, morphed, instanced)] ?? '',
726
+ label: `flat.vert:${flatVertexKey(skinned, morphed, instanced, animated)}`,
727
+ code: FLAT_VERT_WGSL[flatVertexKey(skinned, morphed, instanced, animated)] ?? '',
611
728
  }),
612
729
  entryPoint: 'main',
613
730
  buffers: vertexBufferLayouts(present, instanced),
614
- constants: vertexConstants(flatVertexBindings(skinned, morphed, instanced), skinEight, cloth, model === 'lightmap'),
731
+ constants: vertexConstants(flatVertexBindings(skinned, morphed, instanced, animated), skinEight, cloth, model === 'lightmap'),
615
732
  },
616
733
  fragment: {
617
734
  module: shaderModule(device, {
@@ -0,0 +1,80 @@
1
+ import type { SkinnedClothSetup } from '@driftengine/physics';
2
+ import { GpuClothParticles } from './clothTextures.ts';
3
+ export declare class GpuClothSet {
4
+ private readonly device;
5
+ private readonly garments;
6
+ private readonly packed;
7
+ private readonly kernels;
8
+ private readonly buffers;
9
+ private readonly state;
10
+ private readonly frameData;
11
+ private readonly paces;
12
+ private readonly group;
13
+ /** One round's records, every garment's: the head an op's, the rest each garment's own. */
14
+ private readonly staging;
15
+ private readonly stagingWords;
16
+ private readonly stagingFloats;
17
+ /** Each kind's first batch slot, and the first garment's publishing slot. */
18
+ private readonly batchSlot;
19
+ private readonly groups;
20
+ private readonly substeps;
21
+ private readonly iterations;
22
+ private encoder;
23
+ private pass;
24
+ private round;
25
+ constructor(device: GPUDevice, setups: readonly SkinnedClothSetup[]);
26
+ /** How many garments the set holds. */
27
+ get size(): number;
28
+ /** Garment `g`'s particles, what `setCloth` draws its bound meshes by. */
29
+ particles(g: number): GpuClothParticles;
30
+ /** Garment `g`'s rig for the steps to come; see `ClothControl.setPose`. */
31
+ setPose(g: number, globals: Float32Array, model: Float32Array): void;
32
+ /** The frame's sample of the scene's wind for garment `g`. See `SkinnedCloth.setWind`. */
33
+ setWind(g: number, x: number, y: number, z: number): void;
34
+ /** Garment `g` back to its skinned pose, settled; the next `step` publishes it. */
35
+ reset(g: number): void;
36
+ /**
37
+ * `dt` of the caller's time in whole fixed steps for every garment, and each garment's particles
38
+ * at its `alpha` published for the draws that follow, as the particles of `frame`.
39
+ */
40
+ step(dt: number, frame: number): void;
41
+ /**
42
+ * Garment `g`'s particles where its last step left them, three floats each: for the parity check,
43
+ * which compares them with the CPU solver's positions. Not for a frame — it waits on the device.
44
+ */
45
+ read(g: number): Promise<Float32Array>;
46
+ /** Its buffers; the particle textures are the renderer's to retire with the frame. */
47
+ dispose(): void;
48
+ private at;
49
+ /** Garment `g`: its schedule over a device that queues, its particles and its own numbers. */
50
+ private garment;
51
+ /**
52
+ * A garment's own words of its record, which every round carries: its colliders, its texture's
53
+ * width and its constants. Its limits ride in the head beside `live`, written as it joins a round.
54
+ */
55
+ private writeOwn;
56
+ /** Garments that cannot step together, refused by the first number they disagree on. */
57
+ private refuseStrangers;
58
+ private targetsChanged;
59
+ private queueOp;
60
+ private queueStep;
61
+ /** Every op every garment is waiting on, a round of one kind at a time, in each garment's order. */
62
+ private run;
63
+ /** Whether any garment has `kind` next. */
64
+ private waiting;
65
+ /** One round: every garment with `kind` next takes part, and the rest sit it out. */
66
+ private runRound;
67
+ private stepRound;
68
+ /** Every colour of one kind across the set, in colour order, each a dispatch over its range. */
69
+ private batches;
70
+ private dispatch;
71
+ private passFor;
72
+ /** A round's slot, sending what is recorded first where the slots are spent: its byte offset. */
73
+ private takeRound;
74
+ /** Where the records of the round at `roundAt` sit in `paces`. */
75
+ private paceOffset;
76
+ /** Send what has been recorded: every slot it reads was written ahead of it on the queue. */
77
+ private flush;
78
+ /** A garment's skin matrices — or its model, with no rig — and its colliders, into the set's. */
79
+ private writeFrameData;
80
+ }