@driftengine/core 4.8.7 → 4.10.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.
- package/CHANGELOG.json +123 -11
- package/README.md +43 -38
- package/dist/index.d.ts +8 -1
- package/dist/index.js +11 -3
- package/dist/render/ambientHarmonics.d.ts +1 -1
- package/dist/render/ambientHarmonics.js +1 -1
- package/dist/render/areaLights.d.ts +4 -4
- package/dist/render/areaLights.js +1 -1
- package/dist/render/atmosphere.d.ts +13 -0
- package/dist/render/atmosphere.js +9 -1
- package/dist/render/backend/api.d.ts +19 -4
- package/dist/render/backend/createRenderer.d.ts +6 -0
- package/dist/render/backend/createRenderer.js +4 -1
- package/dist/render/backend/select.js +11 -5
- package/dist/render/backend/webgl2/boneAnimations.d.ts +29 -0
- package/dist/render/backend/webgl2/boneAnimations.js +80 -0
- package/dist/render/backend/webgl2/instanced.d.ts +5 -1
- package/dist/render/backend/webgl2/instanced.js +13 -1
- package/dist/render/backend/webgl2/renderer.d.ts +180 -4
- package/dist/render/backend/webgl2/renderer.js +550 -40
- package/dist/render/backend/webgl2/skinPaletteTexture.d.ts +5 -3
- package/dist/render/backend/webgl2/skinPaletteTexture.js +6 -4
- package/dist/render/backend/webgpu/boneAnimations.d.ts +34 -0
- package/dist/render/backend/webgpu/boneAnimations.js +76 -0
- package/dist/render/backend/webgpu/buffers.d.ts +19 -4
- package/dist/render/backend/webgpu/buffers.js +18 -11
- package/dist/render/backend/webgpu/compressedUpload.d.ts +0 -1
- package/dist/render/backend/webgpu/compressedUpload.js +53 -8
- package/dist/render/backend/webgpu/depthPass.d.ts +59 -3
- package/dist/render/backend/webgpu/depthPass.js +49 -14
- package/dist/render/backend/webgpu/device.d.ts +7 -1
- package/dist/render/backend/webgpu/device.js +31 -3
- package/dist/render/backend/webgpu/drawCommand.d.ts +18 -4
- package/dist/render/backend/webgpu/drawCommand.js +10 -3
- package/dist/render/backend/webgpu/flatPass.d.ts +100 -42
- package/dist/render/backend/webgpu/flatPass.js +191 -43
- package/dist/render/backend/webgpu/instanced.d.ts +14 -1
- package/dist/render/backend/webgpu/instanced.js +24 -1
- package/dist/render/backend/webgpu/materialStore.d.ts +101 -0
- package/dist/render/backend/webgpu/materialStore.js +265 -0
- package/dist/render/backend/webgpu/pipelineCache.d.ts +6 -0
- package/dist/render/backend/webgpu/pipelineCache.js +7 -0
- package/dist/render/backend/webgpu/postPass.d.ts +51 -9
- package/dist/render/backend/webgpu/postPass.js +16 -2
- package/dist/render/backend/webgpu/reflectionSurfacePass.d.ts +30 -0
- package/dist/render/backend/webgpu/reflectionSurfacePass.js +100 -0
- package/dist/render/backend/webgpu/renderer.d.ts +283 -37
- package/dist/render/backend/webgpu/renderer.js +1363 -202
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +7 -3
- package/dist/render/backend/webgpu/skinPaletteRing.js +13 -7
- package/dist/render/backend/webgpu/skinPaletteTexture.d.ts +6 -0
- package/dist/render/backend/webgpu/skinPaletteTexture.js +7 -1
- package/dist/render/backend/webgpu/staticBundles.d.ts +125 -0
- package/dist/render/backend/webgpu/staticBundles.js +241 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +10 -3
- package/dist/render/backend/webgpu/surfaceTexturePass.js +20 -2
- package/dist/render/backend/webgpu/uniformRing.d.ts +21 -0
- package/dist/render/backend/webgpu/uniformRing.js +9 -1
- package/dist/render/bloomChain.d.ts +3 -3
- package/dist/render/boneAnimation.d.ts +92 -0
- package/dist/render/boneAnimation.js +133 -0
- package/dist/render/compressedSource.d.ts +33 -13
- package/dist/render/compressedSource.js +70 -25
- package/dist/render/displayRange.d.ts +31 -0
- package/dist/render/displayRange.js +47 -0
- package/dist/render/filmicCurve.d.ts +74 -0
- package/dist/render/filmicCurve.js +203 -0
- package/dist/render/fog.d.ts +4 -1
- package/dist/render/fog.js +12 -2
- package/dist/render/frame/resources.d.ts +2 -2
- package/dist/render/frame/resources.js +6 -0
- package/dist/render/frameReflections.d.ts +40 -0
- package/dist/render/frameReflections.js +48 -0
- package/dist/render/glCompressed.js +83 -0
- package/dist/render/instances.d.ts +26 -0
- package/dist/render/lightBudget.d.ts +10 -0
- package/dist/render/lightBudget.js +10 -0
- package/dist/render/lightmap.d.ts +1 -1
- package/dist/render/mesh.d.ts +5 -0
- package/dist/render/mesh.js +6 -0
- package/dist/render/pass.d.ts +49 -0
- package/dist/render/pointLightSelection.d.ts +4 -4
- package/dist/render/reflectionSurfaceTargets.d.ts +28 -0
- package/dist/render/reflectionSurfaceTargets.js +99 -0
- package/dist/render/renderQuality.d.ts +39 -8
- package/dist/render/renderQuality.js +4 -0
- package/dist/render/sceneTarget.d.ts +5 -0
- package/dist/render/sceneTarget.js +24 -1
- package/dist/render/screenSpaceReflection.d.ts +7 -1
- package/dist/render/screenSpaceReflection.js +5 -0
- package/dist/render/shaders/arcane.d.ts +1 -1
- package/dist/render/shaders/bolt.d.ts +1 -1
- package/dist/render/shaders/boneAnimation.d.ts +19 -0
- package/dist/render/shaders/boneAnimation.js +63 -0
- package/dist/render/shaders/caustics.d.ts +1 -1
- package/dist/render/shaders/depth.d.ts +7 -0
- package/dist/render/shaders/depth.js +35 -10
- package/dist/render/shaders/film.d.ts +1 -1
- package/dist/render/shaders/filmLook.js +2 -1
- package/dist/render/shaders/fire.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.js +2 -0
- package/dist/render/shaders/flat/index.d.ts +16 -0
- package/dist/render/shaders/flat/index.js +33 -5
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +43 -5
- package/dist/render/shaders/flat/models.js +1 -1
- package/dist/render/shaders/flat/overlay.d.ts +16 -0
- package/dist/render/shaders/flat/overlay.js +117 -0
- package/dist/render/shaders/flat/pointShadow.js +3 -3
- package/dist/render/shaders/flat/preamble.js +38 -24
- package/dist/render/shaders/flat/reflectionSurface.d.ts +21 -0
- package/dist/render/shaders/flat/reflectionSurface.js +61 -0
- package/dist/render/shaders/fog.d.ts +1 -1
- package/dist/render/shaders/fog.js +9 -2
- package/dist/render/shaders/fringe.d.ts +29 -0
- package/dist/render/shaders/fringe.js +55 -0
- package/dist/render/shaders/generated/arcane.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/arcane.wgsl.js +1 -1
- package/dist/render/shaders/generated/bolt.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/bolt.wgsl.js +1 -1
- package/dist/render/shaders/generated/caustics.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/caustics.wgsl.js +1 -1
- package/dist/render/shaders/generated/depth.wgsl.d.ts +93 -0
- package/dist/render/shaders/generated/depth.wgsl.js +93 -0
- package/dist/render/shaders/generated/film.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/film.wgsl.js +1 -1
- package/dist/render/shaders/generated/fire.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/fire.wgsl.js +1 -1
- package/dist/render/shaders/generated/flat.wgsl.d.ts +3254 -2920
- package/dist/render/shaders/generated/flat.wgsl.js +3292 -2957
- package/dist/render/shaders/generated/line.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/line.wgsl.js +1 -1
- package/dist/render/shaders/generated/particle.wgsl.d.ts +4 -4
- package/dist/render/shaders/generated/particle.wgsl.js +4 -4
- package/dist/render/shaders/generated/rush.wgsl.d.ts +56 -26
- package/dist/render/shaders/generated/rush.wgsl.js +56 -26
- package/dist/render/shaders/generated/scatter.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/scatter.wgsl.js +1 -1
- package/dist/render/shaders/generated/smoke.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/smoke.wgsl.js +1 -1
- package/dist/render/shaders/generated/ssrResolve.wgsl.d.ts +29 -0
- package/dist/render/shaders/generated/ssrResolve.wgsl.js +29 -0
- package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +22 -2
- package/dist/render/shaders/generated/ssrTrace.wgsl.js +22 -2
- package/dist/render/shaders/generated/water.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/water.wgsl.js +1 -1
- package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +2 -2
- package/dist/render/shaders/gpudriven/fog.wgsl.js +11 -3
- package/dist/render/shaders/line.d.ts +1 -1
- package/dist/render/shaders/outputTransform.d.ts +7 -0
- package/dist/render/shaders/outputTransform.js +28 -14
- package/dist/render/shaders/particle.d.ts +3 -3
- package/dist/render/shaders/rush.js +54 -11
- package/dist/render/shaders/scatter.d.ts +1 -1
- package/dist/render/shaders/smoke.d.ts +1 -1
- package/dist/render/shaders/ssrResolve.d.ts +17 -0
- package/dist/render/shaders/ssrResolve.js +51 -0
- package/dist/render/shaders/ssrTrace.js +26 -0
- package/dist/render/shaders/vertexChannel.d.ts +7 -0
- package/dist/render/shaders/vertexChannel.js +26 -0
- package/dist/render/shaders/water.d.ts +1 -1
- package/dist/render/ssrPass.d.ts +16 -0
- package/dist/render/ssrPass.js +106 -1
- package/dist/render/staticDraws.d.ts +47 -0
- package/dist/render/staticDraws.js +43 -0
- package/dist/render/surfaceOverlay.d.ts +132 -0
- package/dist/render/surfaceOverlay.js +85 -0
- package/dist/render/surfaceTexture.d.ts +57 -7
- package/dist/render/surfaceTexture.js +125 -17
- package/dist/render/temporalAa.d.ts +14 -0
- package/dist/render/temporalAa.js +20 -0
- package/dist/render/vertexDefaults.d.ts +17 -0
- package/dist/render/vertexDefaults.js +24 -0
- package/package.json +6 -6
- package/src/index.ts +24 -2
- package/src/render/ambientHarmonics.ts +1 -1
- package/src/render/areaLights.ts +4 -4
- package/src/render/atmosphere.ts +22 -1
- package/src/render/backend/api.ts +22 -3
- package/src/render/backend/createRenderer.ts +18 -1
- package/src/render/backend/select.ts +10 -5
- package/src/render/backend/webgl2/boneAnimations.ts +105 -0
- package/src/render/backend/webgl2/instanced.ts +20 -1
- package/src/render/backend/webgl2/renderer.ts +672 -37
- package/src/render/backend/webgl2/skinPaletteTexture.ts +6 -4
- package/src/render/backend/webgpu/boneAnimations.ts +97 -0
- package/src/render/backend/webgpu/buffers.ts +42 -16
- package/src/render/backend/webgpu/compressedUpload.ts +59 -9
- package/src/render/backend/webgpu/depthPass.ts +51 -10
- package/src/render/backend/webgpu/device.ts +42 -3
- package/src/render/backend/webgpu/drawCommand.ts +22 -4
- package/src/render/backend/webgpu/flatPass.ts +250 -40
- package/src/render/backend/webgpu/instanced.ts +32 -1
- package/src/render/backend/webgpu/materialStore.ts +276 -0
- package/src/render/backend/webgpu/pipelineCache.ts +7 -0
- package/src/render/backend/webgpu/postPass.ts +18 -0
- package/src/render/backend/webgpu/reflectionSurfacePass.ts +114 -0
- package/src/render/backend/webgpu/renderer.ts +1655 -230
- package/src/render/backend/webgpu/skinPaletteRing.ts +13 -7
- package/src/render/backend/webgpu/skinPaletteTexture.ts +7 -1
- package/src/render/backend/webgpu/staticBundles.ts +363 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +29 -3
- package/src/render/backend/webgpu/uniformRing.ts +10 -1
- package/src/render/bloomChain.ts +3 -3
- package/src/render/boneAnimation.ts +223 -0
- package/src/render/compressedSource.ts +121 -29
- package/src/render/displayRange.ts +61 -0
- package/src/render/filmicCurve.ts +229 -0
- package/src/render/fog.ts +19 -3
- package/src/render/frame/resources.ts +6 -0
- package/src/render/frameReflections.ts +72 -0
- package/src/render/glCompressed.ts +83 -0
- package/src/render/instances.ts +27 -0
- package/src/render/lightBudget.ts +11 -0
- package/src/render/lightmap.ts +1 -1
- package/src/render/mesh.ts +6 -0
- package/src/render/pass.ts +53 -1
- package/src/render/pointLightSelection.ts +4 -4
- package/src/render/reflectionSurfaceTargets.ts +105 -0
- package/src/render/renderQuality.ts +44 -8
- package/src/render/sceneTarget.ts +30 -2
- package/src/render/screenSpaceReflection.ts +7 -1
- package/src/render/shaders/boneAnimation.ts +63 -0
- package/src/render/shaders/depth.ts +45 -10
- package/src/render/shaders/filmLook.ts +2 -1
- package/src/render/shaders/flat/glassTint.ts +5 -1
- package/src/render/shaders/flat/index.ts +49 -5
- package/src/render/shaders/flat/main.ts +43 -5
- package/src/render/shaders/flat/models.ts +1 -1
- package/src/render/shaders/flat/overlay.ts +117 -0
- package/src/render/shaders/flat/pointShadow.ts +3 -3
- package/src/render/shaders/flat/preamble.ts +38 -24
- package/src/render/shaders/flat/reflectionSurface.ts +61 -0
- package/src/render/shaders/fog.ts +9 -2
- package/src/render/shaders/fringe.ts +59 -0
- package/src/render/shaders/generated/arcane.wgsl.ts +1 -1
- package/src/render/shaders/generated/bolt.wgsl.ts +1 -1
- package/src/render/shaders/generated/caustics.wgsl.ts +1 -1
- package/src/render/shaders/generated/depth.wgsl.ts +95 -0
- package/src/render/shaders/generated/film.wgsl.ts +1 -1
- package/src/render/shaders/generated/fire.wgsl.ts +1 -1
- package/src/render/shaders/generated/flat.wgsl.ts +3292 -2957
- package/src/render/shaders/generated/line.wgsl.ts +1 -1
- package/src/render/shaders/generated/particle.wgsl.ts +4 -4
- package/src/render/shaders/generated/rush.wgsl.ts +56 -26
- package/src/render/shaders/generated/scatter.wgsl.ts +1 -1
- package/src/render/shaders/generated/smoke.wgsl.ts +1 -1
- package/src/render/shaders/generated/ssrResolve.wgsl.ts +30 -0
- package/src/render/shaders/generated/ssrTrace.wgsl.ts +22 -2
- package/src/render/shaders/generated/water.wgsl.ts +1 -1
- package/src/render/shaders/gpudriven/fog.wgsl.ts +11 -3
- package/src/render/shaders/outputTransform.ts +30 -14
- package/src/render/shaders/rush.ts +54 -11
- package/src/render/shaders/ssrResolve.ts +52 -0
- package/src/render/shaders/ssrTrace.ts +26 -0
- package/src/render/shaders/vertexChannel.ts +27 -0
- package/src/render/ssrPass.ts +138 -1
- package/src/render/staticDraws.ts +95 -0
- package/src/render/surfaceOverlay.ts +195 -0
- package/src/render/surfaceTexture.ts +161 -27
- package/src/render/temporalAa.ts +20 -0
- package/src/render/vertexDefaults.ts +28 -0
|
@@ -12,6 +12,7 @@ import type { LitSwitch, PipelineCache } from './pipelineCache.ts';
|
|
|
12
12
|
import type { ClothViews } from './clothTextures.ts';
|
|
13
13
|
import { shaderModule } from './shaderModules.ts';
|
|
14
14
|
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.ts';
|
|
15
|
+
import { REFLECTION_SURFACE_FORMAT } from './reflectionSurfacePass.ts';
|
|
15
16
|
|
|
16
17
|
/** The material maps the flat pass reads: `2d-array` colour, filtered, not shadow maps. */
|
|
17
18
|
const SURFACE_MAPS: ReadonlySet<string> = new Set([
|
|
@@ -98,6 +99,20 @@ export interface StageBindings {
|
|
|
98
99
|
readonly textures: Readonly<Record<string, TextureBinding>>;
|
|
99
100
|
/** Each pipeline-overridable constant's id, by the GLSL name it was declared under. */
|
|
100
101
|
readonly overrides?: Readonly<Record<string, number>>;
|
|
102
|
+
/**
|
|
103
|
+
* The second block, of the uniforms marked `// wgsl:material`: its binding, size and fields.
|
|
104
|
+
* Absent from a stage that marks none, which is every stage but the lit fragment's.
|
|
105
|
+
*/
|
|
106
|
+
readonly materialUniforms?: number;
|
|
107
|
+
readonly materialSize?: number;
|
|
108
|
+
readonly materialFields?: StageBindings['fields'];
|
|
109
|
+
/**
|
|
110
|
+
* The vertex stage's view block, of the uniforms marked `// wgsl:view`: the camera, the light's
|
|
111
|
+
* matrix and the wind, which a pass settles. Absent from every stage but the lit vertex one.
|
|
112
|
+
*/
|
|
113
|
+
readonly viewUniforms?: number;
|
|
114
|
+
readonly viewSize?: number;
|
|
115
|
+
readonly viewFields?: StageBindings['fields'];
|
|
101
116
|
}
|
|
102
117
|
|
|
103
118
|
/*
|
|
@@ -129,9 +144,16 @@ const VERTEX_BINDINGS = FLAT_BINDINGS.flatVert as unknown as Readonly<
|
|
|
129
144
|
>;
|
|
130
145
|
|
|
131
146
|
/** The key for a set of vertex flags: the same rule `variantKey` uses, flags on, sorted, joined. */
|
|
132
|
-
export function flatVertexKey(
|
|
147
|
+
export function flatVertexKey(
|
|
148
|
+
skinned: boolean,
|
|
149
|
+
morphed: boolean,
|
|
150
|
+
instanced = false,
|
|
151
|
+
/** Whether an instanced variant plays a bone animation. See `shaders/boneAnimation.ts`. */
|
|
152
|
+
animated = false,
|
|
153
|
+
): string {
|
|
133
154
|
const on: string[] = [];
|
|
134
155
|
/* Alphabetical, because the generator's own `variantKey` sorts and the two keys must agree. */
|
|
156
|
+
if (animated) on.push('animated');
|
|
135
157
|
if (instanced) on.push('instanced');
|
|
136
158
|
if (morphed) on.push('morphed');
|
|
137
159
|
if (skinned) on.push('skinned');
|
|
@@ -143,8 +165,9 @@ export function flatVertexBindings(
|
|
|
143
165
|
skinned: boolean,
|
|
144
166
|
morphed = false,
|
|
145
167
|
instanced = false,
|
|
168
|
+
animated = false,
|
|
146
169
|
): StageBindings {
|
|
147
|
-
const key = flatVertexKey(skinned, morphed, instanced);
|
|
170
|
+
const key = flatVertexKey(skinned, morphed, instanced, animated);
|
|
148
171
|
const found = VERTEX_BINDINGS[key];
|
|
149
172
|
if (found === undefined) throw new Error(`flatPass: no vertex bindings for variant "${key}"`);
|
|
150
173
|
return found;
|
|
@@ -220,6 +243,8 @@ for (const [key, bindings] of Object.entries(VERTEX_BINDINGS)) {
|
|
|
220
243
|
}
|
|
221
244
|
|
|
222
245
|
export const FLAT_VERT_FIELDS = FLAT_BINDINGS.flatVert.none.fields;
|
|
246
|
+
/** The animated instanced variant's block: the instanced fields, and the clip's `uBoneClip`. */
|
|
247
|
+
export const FLAT_ANIMATED_VERT_FIELDS = FLAT_BINDINGS.flatVert['animated+instanced'].fields;
|
|
223
248
|
/**
|
|
224
249
|
* The **largest** variant's block, because one ring serves every draw.
|
|
225
250
|
*
|
|
@@ -232,6 +257,55 @@ export const FLAT_VERT_SIZE = Math.max(
|
|
|
232
257
|
);
|
|
233
258
|
const FLAT_VERT_BINDING = PLAIN_VERTEX.uniforms;
|
|
234
259
|
|
|
260
|
+
/*
|
|
261
|
+
* **The view block may be shorter in a variant, never different.** One slot serves every lit draw
|
|
262
|
+
* of a pass, plain and instanced alike, so every field a variant's view block declares must sit
|
|
263
|
+
* where the plain variant has it. The instanced variant declares no wind, and its block is the plain
|
|
264
|
+
* one's first two matrices.
|
|
265
|
+
*/
|
|
266
|
+
const PLAIN_VIEW_FIELDS = PLAIN_VERTEX.viewFields ?? {};
|
|
267
|
+
for (const [key, bindings] of Object.entries(VERTEX_BINDINGS)) {
|
|
268
|
+
if (bindings.viewUniforms !== PLAIN_VERTEX.viewUniforms) {
|
|
269
|
+
throw new Error(`flatPass: vertex variant "${key}" binds its view block elsewhere`);
|
|
270
|
+
}
|
|
271
|
+
for (const [field, here] of Object.entries(bindings.viewFields ?? {})) {
|
|
272
|
+
if (PLAIN_VIEW_FIELDS[field]?.offset !== here.offset) {
|
|
273
|
+
throw new Error(
|
|
274
|
+
`flatPass: vertex variant "${key}" puts view field ${field} at ${here.offset} where the ` +
|
|
275
|
+
`plain variant has it at ${PLAIN_VIEW_FIELDS[field]?.offset}.`,
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** The view block's fields, binding and size: the largest variant's, as `FLAT_VERT_SIZE` is. */
|
|
282
|
+
export const FLAT_VIEW_FIELDS = PLAIN_VIEW_FIELDS;
|
|
283
|
+
export const FLAT_VIEW_SIZE = Math.max(
|
|
284
|
+
...Object.values(VERTEX_BINDINGS).map((bindings) => bindings.viewSize ?? 0),
|
|
285
|
+
);
|
|
286
|
+
const FLAT_VIEW_BINDING = PLAIN_VERTEX.viewUniforms ?? -1;
|
|
287
|
+
if (FLAT_VIEW_BINDING < 0) throw new Error('flatPass: the lit vertex stage declares no view block');
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* The most sampled textures and distinct samplers any lit variant carrying the environment probe
|
|
291
|
+
* binds in its fragment stage, counted from the generated bindings: what a device must allow per
|
|
292
|
+
* stage before the probe's permutation can be built. A sampler several textures share counts once,
|
|
293
|
+
* which is what `// wgsl:share` buys.
|
|
294
|
+
*/
|
|
295
|
+
export function probeStageCeilings(): { readonly textures: number; readonly samplers: number } {
|
|
296
|
+
let textures = 0;
|
|
297
|
+
let samplers = 0;
|
|
298
|
+
for (const [variant, bindings] of Object.entries(FLAT_BINDINGS.flatFrag)) {
|
|
299
|
+
if (!variant.includes('environmentProbe')) continue;
|
|
300
|
+
const listed = Object.values(
|
|
301
|
+
(bindings as { textures?: Record<string, { sampler: number }> }).textures ?? {},
|
|
302
|
+
);
|
|
303
|
+
textures = Math.max(textures, listed.length);
|
|
304
|
+
samplers = Math.max(samplers, new Set(listed.map((entry) => entry.sampler)).size);
|
|
305
|
+
}
|
|
306
|
+
return { textures, samplers };
|
|
307
|
+
}
|
|
308
|
+
|
|
235
309
|
/** Everything the generator recorded about one permutation of the fragment stage. */
|
|
236
310
|
export function flatFragmentBindings(variant: FlatVariant): StageBindings {
|
|
237
311
|
const found = FRAGMENT_BINDINGS[variant];
|
|
@@ -239,6 +313,46 @@ export function flatFragmentBindings(variant: FlatVariant): StageBindings {
|
|
|
239
313
|
return found;
|
|
240
314
|
}
|
|
241
315
|
|
|
316
|
+
/**
|
|
317
|
+
* The lit fragment stage's two blocks as the renderer keeps them on the CPU: the pass's, then the
|
|
318
|
+
* material's straight after it, in one scratch, with every field at its offset in that scratch.
|
|
319
|
+
*
|
|
320
|
+
* **One scratch rather than two, so no setter has to know which block its field is in.** A setter
|
|
321
|
+
* writes by name, as it always has; the draw copies the material's bytes — `passSize` onwards — into
|
|
322
|
+
* the store and the pass's bytes into a ring slot, each only when something has changed it.
|
|
323
|
+
*/
|
|
324
|
+
export interface FlatFragmentScratch {
|
|
325
|
+
readonly fields: StageBindings['fields'];
|
|
326
|
+
/** Bytes of the pass's block, which is where the material's starts in the scratch. */
|
|
327
|
+
readonly passSize: number;
|
|
328
|
+
readonly passBinding: number;
|
|
329
|
+
readonly materialSize: number;
|
|
330
|
+
readonly materialBinding: number;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export function flatFragmentScratch(variant: FlatVariant): FlatFragmentScratch {
|
|
334
|
+
const bindings = flatFragmentBindings(variant);
|
|
335
|
+
const { materialUniforms, materialSize, materialFields } = bindings;
|
|
336
|
+
if (
|
|
337
|
+
materialUniforms === undefined ||
|
|
338
|
+
materialSize === undefined ||
|
|
339
|
+
materialFields === undefined
|
|
340
|
+
) {
|
|
341
|
+
throw new Error(`flatPass: variant "${variant}" has no material block`);
|
|
342
|
+
}
|
|
343
|
+
const fields: Record<string, StageBindings['fields'][string]> = { ...bindings.fields };
|
|
344
|
+
for (const [name, field] of Object.entries(materialFields)) {
|
|
345
|
+
fields[name] = { ...field, offset: bindings.uniformSize + field.offset };
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
fields,
|
|
349
|
+
passSize: bindings.uniformSize,
|
|
350
|
+
passBinding: bindings.uniforms,
|
|
351
|
+
materialSize,
|
|
352
|
+
materialBinding: materialUniforms,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
242
356
|
/**
|
|
243
357
|
* The lit fragment stage's constants, set from the cache's switches, keyed by each one's **id**.
|
|
244
358
|
*
|
|
@@ -253,6 +367,7 @@ function flatFragmentConstants(
|
|
|
253
367
|
cache: PipelineCache,
|
|
254
368
|
model: SurfaceModelKind | null,
|
|
255
369
|
skinPass: SkinHalf = 'whole',
|
|
370
|
+
reflectionSurface = false,
|
|
256
371
|
): Record<string, number> {
|
|
257
372
|
const overrides = flatFragmentBindings(variant).overrides;
|
|
258
373
|
if (overrides?.['GLASS_SHADOWS'] === undefined) {
|
|
@@ -271,6 +386,11 @@ function flatFragmentConstants(
|
|
|
271
386
|
constants[String(id)] = skinPass !== 'whole' && name === SKIN_HALF_SWITCH[skinPass] ? 1 : 0;
|
|
272
387
|
continue;
|
|
273
388
|
}
|
|
389
|
+
/* The reflection pass's surface half, set from the key too. See `reflectionSurface.ts`. */
|
|
390
|
+
if (name === 'REFLECTION_SURFACE') {
|
|
391
|
+
constants[String(id)] = reflectionSurface ? 1 : 0;
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
274
394
|
if (!(name in cache.litSwitches)) {
|
|
275
395
|
throw new Error(`flatPass: variant "${variant}" declares a switch "${name}" no cache sets`);
|
|
276
396
|
}
|
|
@@ -279,6 +399,14 @@ function flatFragmentConstants(
|
|
|
279
399
|
return constants;
|
|
280
400
|
}
|
|
281
401
|
|
|
402
|
+
/** The material block's binding, which every lit variant declares. */
|
|
403
|
+
function materialBinding(fragment: StageBindings): number {
|
|
404
|
+
if (fragment.materialUniforms === undefined) {
|
|
405
|
+
throw new Error('flatPass: the lit fragment stage declares no material block');
|
|
406
|
+
}
|
|
407
|
+
return fragment.materialUniforms;
|
|
408
|
+
}
|
|
409
|
+
|
|
282
410
|
/** The depth format both backends compare with. */
|
|
283
411
|
/* Re-exported so the twenty passes that already import it from here do not each learn a new
|
|
284
412
|
module; `depthConvention.ts` is where the decision lives and why. */
|
|
@@ -290,15 +418,19 @@ const VISIBILITY_FRAGMENT = 0x2;
|
|
|
290
418
|
/**
|
|
291
419
|
* The layout this variant binds against.
|
|
292
420
|
*
|
|
293
|
-
*
|
|
294
|
-
* from its own slot of one buffer
|
|
295
|
-
*
|
|
421
|
+
* All four blocks are **dynamic**: the vertex block because every draw supplies its own model
|
|
422
|
+
* matrix and tint from its own slot of one buffer; the fragment stage's pass block — the lights, the
|
|
423
|
+
* fog, the camera — and the vertex stage's view block because a frame binds more than one pass; and
|
|
424
|
+
* the material block because a material changes between draws. Their dynamic offsets go in binding
|
|
425
|
+
* order: the draw's, the pass's, the material's, the view's.
|
|
296
426
|
*/
|
|
297
427
|
export function createFlatBindGroupLayout(
|
|
298
428
|
device: GPUDevice,
|
|
299
429
|
variant: FlatVariant,
|
|
300
430
|
skinned = false,
|
|
301
431
|
morphed = false,
|
|
432
|
+
/** The instanced variant that plays a bone animation: its three vertex textures. */
|
|
433
|
+
animated = false,
|
|
302
434
|
): GPUBindGroupLayout {
|
|
303
435
|
const fragment = flatFragmentBindings(variant);
|
|
304
436
|
const entries: GPUBindGroupLayoutEntry[] = [
|
|
@@ -307,15 +439,31 @@ export function createFlatBindGroupLayout(
|
|
|
307
439
|
visibility: VISIBILITY_VERTEX,
|
|
308
440
|
buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: FLAT_VERT_SIZE },
|
|
309
441
|
},
|
|
442
|
+
{
|
|
443
|
+
binding: FLAT_VIEW_BINDING,
|
|
444
|
+
visibility: VISIBILITY_VERTEX,
|
|
445
|
+
/* Dynamic, a slot a pass, for the reason the fragment stage's pass block is. */
|
|
446
|
+
buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: FLAT_VIEW_SIZE },
|
|
447
|
+
},
|
|
310
448
|
{
|
|
311
449
|
binding: fragment.uniforms,
|
|
312
450
|
visibility: VISIBILITY_FRAGMENT,
|
|
313
451
|
/*
|
|
314
|
-
* Dynamic, because
|
|
315
|
-
*
|
|
452
|
+
* Dynamic, because a pass's lights and camera change between passes of one frame — a
|
|
453
|
+
* mirror's, a capture's — and one buffer cannot hold two answers. See `WebGPURenderer.passRing`.
|
|
316
454
|
*/
|
|
317
455
|
buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: fragment.uniformSize },
|
|
318
456
|
},
|
|
457
|
+
{
|
|
458
|
+
binding: materialBinding(fragment),
|
|
459
|
+
visibility: VISIBILITY_FRAGMENT,
|
|
460
|
+
/* Dynamic, because a material changes between draws. See `MaterialStore`. */
|
|
461
|
+
buffer: {
|
|
462
|
+
type: 'uniform',
|
|
463
|
+
hasDynamicOffset: true,
|
|
464
|
+
minBindingSize: fragment.materialSize ?? 0,
|
|
465
|
+
},
|
|
466
|
+
},
|
|
319
467
|
];
|
|
320
468
|
|
|
321
469
|
/** What each sampler binding was declared as, so a shared one is declared once and agrees. */
|
|
@@ -462,12 +610,43 @@ export function createFlatBindGroupLayout(
|
|
|
462
610
|
}
|
|
463
611
|
}
|
|
464
612
|
|
|
613
|
+
/* A bone animation's places, turns and the batch's clocks, read by index as the palette is. */
|
|
614
|
+
if (animated) {
|
|
615
|
+
for (const binding of animationBindings()) {
|
|
616
|
+
entries.push({
|
|
617
|
+
binding,
|
|
618
|
+
visibility: VISIBILITY_VERTEX,
|
|
619
|
+
texture: { sampleType: 'unfilterable-float' },
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
465
624
|
return device.createBindGroupLayout({
|
|
466
|
-
label: `flat.layout:${variant}|${flatVertexKey(skinned, morphed)}`,
|
|
625
|
+
label: `flat.layout:${variant}|${flatVertexKey(skinned, morphed, animated, animated)}`,
|
|
467
626
|
entries,
|
|
468
627
|
});
|
|
469
628
|
}
|
|
470
629
|
|
|
630
|
+
/** The three textures a bone animation binds, in the order `AnimationViews` holds them. */
|
|
631
|
+
function animationBindings(): [number, number, number] {
|
|
632
|
+
const textures = flatVertexBindings(false, false, true, true).textures;
|
|
633
|
+
const at = (name: string): number => {
|
|
634
|
+
const found = textures[name];
|
|
635
|
+
if (found === undefined) {
|
|
636
|
+
throw new Error(`flatPass: the animated vertex shader declares no ${name}`);
|
|
637
|
+
}
|
|
638
|
+
return found.texture;
|
|
639
|
+
};
|
|
640
|
+
return [at('uBonePlaces'), at('uBoneTurns'), at('uInstanceClocks')];
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/** What an animated draw binds besides its material: the clip's two textures and its batch's clocks. */
|
|
644
|
+
export interface AnimationViews {
|
|
645
|
+
readonly places: GPUTextureView;
|
|
646
|
+
readonly turns: GPUTextureView;
|
|
647
|
+
readonly clocks: GPUTextureView;
|
|
648
|
+
}
|
|
649
|
+
|
|
471
650
|
/**
|
|
472
651
|
* Bind the buffers and one view per declared texture.
|
|
473
652
|
*
|
|
@@ -482,7 +661,9 @@ export function createFlatBindGroup(
|
|
|
482
661
|
layout: GPUBindGroupLayout,
|
|
483
662
|
variant: FlatVariant,
|
|
484
663
|
perDraw: GPUBuffer,
|
|
485
|
-
|
|
664
|
+
passes: GPUBuffer,
|
|
665
|
+
materials: GPUBuffer,
|
|
666
|
+
views: GPUBuffer,
|
|
486
667
|
resolve: (name: string) => { view: GPUTextureView; sampler: GPUSampler },
|
|
487
668
|
/** The palette view for a skinned bind group, or null for an unskinned one. */
|
|
488
669
|
palette: GPUTextureView | null = null,
|
|
@@ -490,6 +671,8 @@ export function createFlatBindGroup(
|
|
|
490
671
|
deltas: GPUTextureView | null = null,
|
|
491
672
|
/** A skinned bind group's cloth views — the draw's, or the stand-in where it sets none. */
|
|
492
673
|
cloth: ClothViews | null = null,
|
|
674
|
+
/** An animated instanced group's views. See `AnimationViews`. */
|
|
675
|
+
animation: AnimationViews | null = null,
|
|
493
676
|
): GPUBindGroup {
|
|
494
677
|
const fragment = flatFragmentBindings(variant);
|
|
495
678
|
const entries: GPUBindGroupEntry[] = [
|
|
@@ -497,7 +680,12 @@ export function createFlatBindGroup(
|
|
|
497
680
|
binding: FLAT_VERT_BINDING,
|
|
498
681
|
resource: { buffer: perDraw, size: FLAT_VERT_SIZE },
|
|
499
682
|
},
|
|
500
|
-
{ binding:
|
|
683
|
+
{ binding: FLAT_VIEW_BINDING, resource: { buffer: views, size: FLAT_VIEW_SIZE } },
|
|
684
|
+
{ binding: fragment.uniforms, resource: { buffer: passes, size: fragment.uniformSize } },
|
|
685
|
+
{
|
|
686
|
+
binding: materialBinding(fragment),
|
|
687
|
+
resource: { buffer: materials, size: fragment.materialSize ?? 0 },
|
|
688
|
+
},
|
|
501
689
|
];
|
|
502
690
|
|
|
503
691
|
/* The same dedupe the layout does, and for the same reason: the shadow bindings share one
|
|
@@ -536,8 +724,15 @@ export function createFlatBindGroup(
|
|
|
536
724
|
entries.push({ binding: restAt, resource: cloth.rest });
|
|
537
725
|
}
|
|
538
726
|
|
|
727
|
+
if (animation !== null) {
|
|
728
|
+
const [places, turns, clocks] = animationBindings();
|
|
729
|
+
entries.push({ binding: places, resource: animation.places });
|
|
730
|
+
entries.push({ binding: turns, resource: animation.turns });
|
|
731
|
+
entries.push({ binding: clocks, resource: animation.clocks });
|
|
732
|
+
}
|
|
733
|
+
|
|
539
734
|
return device.createBindGroup({
|
|
540
|
-
label: `flat.bindGroup:${variant}|${flatVertexKey(palette !== null, deltas !== null)}`,
|
|
735
|
+
label: `flat.bindGroup:${variant}|${flatVertexKey(palette !== null, deltas !== null, animation !== null, animation !== null)}`,
|
|
541
736
|
layout,
|
|
542
737
|
entries,
|
|
543
738
|
});
|
|
@@ -609,6 +804,13 @@ export function flatPipeline(
|
|
|
609
804
|
model: SurfaceModelKind | null = null,
|
|
610
805
|
/** Which half of a skin it draws. The key must carry it: `|ss`, `|sd` or `|sa`. See `SkinHalf`. */
|
|
611
806
|
skinPass: SkinHalf = 'whole',
|
|
807
|
+
/**
|
|
808
|
+
* The reflection pass's surface half: the draw again, against its own depth, into the two
|
|
809
|
+
* targets `reflectionSurfacePass.ts` holds. The key must carry it: `|rs`.
|
|
810
|
+
*/
|
|
811
|
+
reflectionSurface = false,
|
|
812
|
+
/** An instanced pipeline that plays a bone animation. The key must carry it: `|anim`. */
|
|
813
|
+
animated = false,
|
|
612
814
|
): GPURenderPipeline {
|
|
613
815
|
return cache.get(
|
|
614
816
|
key,
|
|
@@ -633,6 +835,8 @@ export function flatPipeline(
|
|
|
633
835
|
cloth,
|
|
634
836
|
model,
|
|
635
837
|
skinPass,
|
|
838
|
+
reflectionSurface,
|
|
839
|
+
animated,
|
|
636
840
|
),
|
|
637
841
|
true,
|
|
638
842
|
);
|
|
@@ -765,10 +969,14 @@ function flatDescriptor(
|
|
|
765
969
|
cloth = false,
|
|
766
970
|
model: SurfaceModelKind | null = null,
|
|
767
971
|
skinPass: SkinHalf = 'whole',
|
|
972
|
+
reflectionSurface = false,
|
|
973
|
+
/** An instanced pipeline that plays a bone animation. See `shaders/boneAnimation.ts`. */
|
|
974
|
+
animated = false,
|
|
768
975
|
): GPURenderPipelineDescriptor {
|
|
769
976
|
const offset = depthOffsetForLayer(depthLayer);
|
|
770
|
-
/* The diffuse and colour halves are the same surface again, into the blur's targets
|
|
771
|
-
|
|
977
|
+
/* The diffuse and colour halves are the same surface again, into the blur's targets; and so is
|
|
978
|
+
the reflection pass's surface half, into its two. */
|
|
979
|
+
const diffuseAlone = skinPass === 'diffuse' || skinPass === 'albedo' || reflectionSurface;
|
|
772
980
|
return {
|
|
773
981
|
label: key,
|
|
774
982
|
layout: device.createPipelineLayout({ bindGroupLayouts: [layout] }),
|
|
@@ -779,13 +987,13 @@ function flatDescriptor(
|
|
|
779
987
|
* layout validates, draws, and is wrong, exactly as this file's header says.
|
|
780
988
|
*/
|
|
781
989
|
module: shaderModule(device, {
|
|
782
|
-
label: `flat.vert:${flatVertexKey(skinned, morphed, instanced)}`,
|
|
783
|
-
code: FLAT_VERT_WGSL[flatVertexKey(skinned, morphed, instanced)] ?? '',
|
|
990
|
+
label: `flat.vert:${flatVertexKey(skinned, morphed, instanced, animated)}`,
|
|
991
|
+
code: FLAT_VERT_WGSL[flatVertexKey(skinned, morphed, instanced, animated)] ?? '',
|
|
784
992
|
}),
|
|
785
993
|
entryPoint: 'main',
|
|
786
994
|
buffers: vertexBufferLayouts(present, instanced),
|
|
787
995
|
constants: vertexConstants(
|
|
788
|
-
flatVertexBindings(skinned, morphed, instanced),
|
|
996
|
+
flatVertexBindings(skinned, morphed, instanced, animated),
|
|
789
997
|
skinEight,
|
|
790
998
|
cloth,
|
|
791
999
|
model === 'lightmap',
|
|
@@ -798,31 +1006,33 @@ function flatDescriptor(
|
|
|
798
1006
|
}),
|
|
799
1007
|
entryPoint: 'main',
|
|
800
1008
|
/* Every variant declares it, so every lit pipeline may set it: see `PipelineCache`. */
|
|
801
|
-
constants: flatFragmentConstants(variant, cache, model, skinPass),
|
|
802
|
-
targets:
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
: translucent
|
|
813
|
-
? {
|
|
814
|
-
format: cache.format,
|
|
815
|
-
blend: {
|
|
816
|
-
color: {
|
|
817
|
-
srcFactor: 'src-alpha',
|
|
818
|
-
dstFactor: 'one-minus-src-alpha',
|
|
819
|
-
operation: 'add',
|
|
1009
|
+
constants: flatFragmentConstants(variant, cache, model, skinPass, reflectionSurface),
|
|
1010
|
+
targets: reflectionSurface
|
|
1011
|
+
? [null, { format: REFLECTION_SURFACE_FORMAT }, { format: REFLECTION_SURFACE_FORMAT }]
|
|
1012
|
+
: [
|
|
1013
|
+
oitTarget(oit) ??
|
|
1014
|
+
(translucent === 'additive'
|
|
1015
|
+
? {
|
|
1016
|
+
format: cache.format,
|
|
1017
|
+
blend: {
|
|
1018
|
+
color: { srcFactor: 'src-alpha', dstFactor: 'one', operation: 'add' },
|
|
1019
|
+
alpha: { srcFactor: 'zero', dstFactor: 'one', operation: 'add' },
|
|
820
1020
|
},
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
1021
|
+
}
|
|
1022
|
+
: translucent
|
|
1023
|
+
? {
|
|
1024
|
+
format: cache.format,
|
|
1025
|
+
blend: {
|
|
1026
|
+
color: {
|
|
1027
|
+
srcFactor: 'src-alpha',
|
|
1028
|
+
dstFactor: 'one-minus-src-alpha',
|
|
1029
|
+
operation: 'add',
|
|
1030
|
+
},
|
|
1031
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
1032
|
+
},
|
|
1033
|
+
}
|
|
1034
|
+
: { format: cache.format }),
|
|
1035
|
+
],
|
|
826
1036
|
},
|
|
827
1037
|
primitive: { topology: 'triangle-list', cullMode: doubleSided ? 'none' : 'back' },
|
|
828
1038
|
/* Coverage only where a sample count can carry it: WebGPU refuses it at one sample. */
|
|
@@ -4,6 +4,8 @@ import { destroySlot } from './instanceCullPass.ts';
|
|
|
4
4
|
import type { CullSlot } from './instanceCullPass.ts';
|
|
5
5
|
import type { MeshInstances } from '../../instances.ts';
|
|
6
6
|
import type { GpuMesh } from './buffers.ts';
|
|
7
|
+
import { packInstanceClocks } from '../../boneAnimation.ts';
|
|
8
|
+
import { GpuInstanceClocks, type GpuBoneAnimation } from './boneAnimations.ts';
|
|
7
9
|
|
|
8
10
|
/** VERTEX | COPY_DST, spelled the way every other pass here spells it. */
|
|
9
11
|
const USAGE_VERTEX = 0x0020 | 0x0008;
|
|
@@ -36,10 +38,34 @@ export class GpuInstancedBatch {
|
|
|
36
38
|
slotFrame = -1;
|
|
37
39
|
slotsTaken = 0;
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
/** The bone animation every instance plays, and its clocks; null for a batch that plays none. */
|
|
42
|
+
readonly animation: GpuBoneAnimation | null;
|
|
43
|
+
readonly clocks: GpuInstanceClocks | null;
|
|
44
|
+
/**
|
|
45
|
+
* An animated batch's own groups — its lit twins by the material group they were built beside, its
|
|
46
|
+
* shadow groups by what they cut with — and the renderer's group epoch they were built in, after
|
|
47
|
+
* which every one is dropped. See `WebGPURenderer.animatedGroup`.
|
|
48
|
+
*/
|
|
49
|
+
readonly litGroups = new Map<GPUBindGroup, GPUBindGroup>();
|
|
50
|
+
readonly depthGroups = new Map<unknown, GPUBindGroup>();
|
|
51
|
+
readonly depthPeelGroups = new Map<unknown, GPUBindGroup>();
|
|
52
|
+
groupEpoch = -1;
|
|
53
|
+
|
|
54
|
+
constructor(
|
|
55
|
+
device: GPUDevice,
|
|
56
|
+
mesh: GpuMesh,
|
|
57
|
+
capacity: number,
|
|
58
|
+
label: string,
|
|
59
|
+
cull = false,
|
|
60
|
+
animation: GpuBoneAnimation | null = null,
|
|
61
|
+
) {
|
|
40
62
|
this.mesh = mesh;
|
|
41
63
|
this.capacity = capacity;
|
|
64
|
+
/* An animated batch is culled whole and never by instance: see `submitInstanced`. */
|
|
42
65
|
this.cull = cull;
|
|
66
|
+
this.animation = animation;
|
|
67
|
+
this.clocks =
|
|
68
|
+
animation === null ? null : new GpuInstanceClocks(device, capacity, `${label}.clocks`);
|
|
43
69
|
this.staging = new Float32Array(capacity * INSTANCE_FLOATS);
|
|
44
70
|
this.buffer = device.createBuffer({
|
|
45
71
|
/*
|
|
@@ -83,11 +109,16 @@ export class GpuInstancedBatch {
|
|
|
83
109
|
if (count === 0) return;
|
|
84
110
|
packInstances(data, this.staging);
|
|
85
111
|
queue.writeBuffer(this.buffer, 0, this.staging, 0, count * INSTANCE_FLOATS);
|
|
112
|
+
if (this.clocks !== null) {
|
|
113
|
+
packInstanceClocks(data, this.clocks.staging);
|
|
114
|
+
this.clocks.upload(queue, count);
|
|
115
|
+
}
|
|
86
116
|
}
|
|
87
117
|
|
|
88
118
|
dispose(): void {
|
|
89
119
|
this.previousBuffer?.destroy();
|
|
90
120
|
this.buffer.destroy();
|
|
121
|
+
this.clocks?.dispose();
|
|
91
122
|
for (const slot of this.slots) destroySlot(slot);
|
|
92
123
|
}
|
|
93
124
|
}
|