@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.
- package/CHANGELOG.json +133 -11
- package/README.md +43 -38
- package/dist/index.d.ts +7 -4
- package/dist/index.js +5 -4
- 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/backend/api.d.ts +10 -3
- 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 +189 -4
- package/dist/render/backend/webgl2/renderer.js +614 -66
- 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 +24 -4
- package/dist/render/backend/webgpu/buffers.js +116 -59
- package/dist/render/backend/webgpu/clothKernels.d.ts +8 -0
- package/dist/render/backend/webgpu/clothKernels.js +76 -0
- package/dist/render/backend/webgpu/clothOps.d.ts +39 -0
- package/dist/render/backend/webgpu/clothOps.js +78 -0
- package/dist/render/backend/webgpu/clothSetLayout.d.ts +25 -0
- package/dist/render/backend/webgpu/clothSetLayout.js +84 -0
- package/dist/render/backend/webgpu/clothSetPack.d.ts +33 -0
- package/dist/render/backend/webgpu/clothSetPack.js +144 -0
- 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/drawCommand.d.ts +20 -4
- package/dist/render/backend/webgpu/drawCommand.js +11 -3
- package/dist/render/backend/webgpu/flatPass.d.ts +85 -42
- package/dist/render/backend/webgpu/flatPass.js +137 -20
- package/dist/render/backend/webgpu/gpuClothSet.d.ts +80 -0
- package/dist/render/backend/webgpu/gpuClothSet.js +462 -0
- package/dist/render/backend/webgpu/instanced.d.ts +14 -1
- package/dist/render/backend/webgpu/instanced.js +24 -1
- package/dist/render/backend/webgpu/latePass.js +1 -0
- package/dist/render/backend/webgpu/materialStore.d.ts +101 -0
- package/dist/render/backend/webgpu/materialStore.js +265 -0
- package/dist/render/backend/webgpu/motionPass.js +15 -6
- package/dist/render/backend/webgpu/pipelineCache.d.ts +28 -1
- package/dist/render/backend/webgpu/pipelineCache.js +46 -1
- package/dist/render/backend/webgpu/postPass.d.ts +1 -1
- package/dist/render/backend/webgpu/renderer.d.ts +200 -35
- package/dist/render/backend/webgpu/renderer.js +993 -168
- package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.d.ts +9 -2
- package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.js +121 -47
- 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 +242 -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/backend/webgpu/vertexFormats.d.ts +22 -0
- package/dist/render/backend/webgpu/vertexFormats.js +97 -0
- 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/glCompressed.js +83 -0
- package/dist/render/globalMediumPass.d.ts +2 -0
- package/dist/render/globalMediumPass.js +1 -0
- package/dist/render/indexWidth.d.ts +17 -0
- package/dist/render/indexWidth.js +23 -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/lightMatrix.d.ts +11 -0
- package/dist/render/lightMatrix.js +14 -0
- package/dist/render/lightmap.d.ts +1 -1
- package/dist/render/mesh.d.ts +14 -0
- package/dist/render/mesh.js +44 -14
- package/dist/render/pointLightSelection.d.ts +4 -4
- package/dist/render/renderQuality.d.ts +30 -0
- package/dist/render/renderQuality.js +5 -0
- package/dist/render/rendererHarness.d.ts +7 -0
- package/dist/render/rendererHarness.js +12 -0
- package/dist/render/screenSpaceReflection.d.ts +2 -1
- package/dist/render/shader.d.ts +15 -0
- package/dist/render/shader.js +41 -0
- package/dist/render/shaders/boneAnimation.d.ts +19 -0
- package/dist/render/shaders/boneAnimation.js +63 -0
- package/dist/render/shaders/depth.d.ts +7 -0
- package/dist/render/shaders/depth.js +35 -10
- package/dist/render/shaders/flat/directionalShadow.js +84 -10
- package/dist/render/shaders/flat/glassTint.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.js +3 -0
- package/dist/render/shaders/flat/index.d.ts +21 -0
- package/dist/render/shaders/flat/index.js +42 -7
- package/dist/render/shaders/flat/layered.d.ts +19 -0
- package/dist/render/shaders/flat/layered.js +115 -0
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +58 -21
- package/dist/render/shaders/flat/mapReads.d.ts +10 -0
- package/dist/render/shaders/flat/mapReads.js +38 -0
- package/dist/render/shaders/flat/models.js +1 -1
- package/dist/render/shaders/flat/movingSun.d.ts +21 -0
- package/dist/render/shaders/flat/movingSun.js +46 -0
- package/dist/render/shaders/flat/normalMap.d.ts +6 -2
- package/dist/render/shaders/flat/normalMap.js +14 -3
- package/dist/render/shaders/flat/overlay.d.ts +3 -2
- package/dist/render/shaders/flat/overlay.js +42 -20
- package/dist/render/shaders/flat/pointShadow.js +2 -2
- package/dist/render/shaders/flat/preamble.js +59 -27
- package/dist/render/shaders/flat/worldUv.d.ts +22 -0
- package/dist/render/shaders/flat/worldUv.js +113 -0
- 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/flat.wgsl.d.ts +3616 -3042
- package/dist/render/shaders/generated/flat.wgsl.js +3688 -3113
- package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +8 -3
- package/dist/render/shaders/generated/globalMedium.wgsl.js +8 -3
- package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +15 -10
- package/dist/render/shaders/generated/lightVolume.wgsl.js +16 -11
- package/dist/render/shaders/globalMedium.js +9 -1
- package/dist/render/shaders/lightVolume.js +9 -1
- package/dist/render/shaders/outputTransform.d.ts +7 -0
- package/dist/render/shaders/outputTransform.js +28 -14
- package/dist/render/shaders/tangentFrame.d.ts +1 -1
- package/dist/render/shaders/tangentFrame.js +16 -3
- package/dist/render/shaders/vertexChannel.d.ts +7 -0
- package/dist/render/shaders/vertexChannel.js +26 -0
- package/dist/render/skinnedClothRun.d.ts +28 -0
- package/dist/render/skinnedClothRun.js +103 -35
- package/dist/render/staticDraws.d.ts +47 -0
- package/dist/render/staticDraws.js +43 -0
- package/dist/render/surfaceLayers.d.ts +39 -0
- package/dist/render/surfaceLayers.js +26 -0
- package/dist/render/surfaceOverlay.d.ts +16 -3
- package/dist/render/surfaceOverlay.js +11 -6
- package/dist/render/surfaceProjection.d.ts +34 -0
- package/dist/render/surfaceProjection.js +30 -0
- package/dist/render/surfaceTexture.d.ts +68 -7
- package/dist/render/surfaceTexture.js +56 -17
- package/dist/render/vertexPacking.d.ts +48 -0
- package/dist/render/vertexPacking.js +68 -0
- package/package.json +6 -6
- package/src/index.ts +12 -4
- package/src/render/ambientHarmonics.ts +1 -1
- package/src/render/areaLights.ts +4 -4
- package/src/render/backend/api.ts +13 -3
- 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 +723 -79
- 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 +195 -70
- package/src/render/backend/webgpu/clothKernels.ts +86 -0
- package/src/render/backend/webgpu/clothOps.ts +86 -0
- package/src/render/backend/webgpu/clothSetLayout.ts +102 -0
- package/src/render/backend/webgpu/clothSetPack.ts +197 -0
- package/src/render/backend/webgpu/compressedUpload.ts +59 -9
- package/src/render/backend/webgpu/depthPass.ts +51 -10
- package/src/render/backend/webgpu/drawCommand.ts +25 -4
- package/src/render/backend/webgpu/flatPass.ts +212 -41
- package/src/render/backend/webgpu/gpuClothSet.ts +564 -0
- package/src/render/backend/webgpu/instanced.ts +32 -1
- package/src/render/backend/webgpu/latePass.ts +1 -0
- package/src/render/backend/webgpu/materialStore.ts +276 -0
- package/src/render/backend/webgpu/motionPass.ts +18 -7
- package/src/render/backend/webgpu/pipelineCache.ts +53 -7
- package/src/render/backend/webgpu/renderer.ts +1201 -202
- package/src/render/backend/webgpu/shaders/clothSolve.wgsl.ts +121 -47
- 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 +364 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +29 -3
- package/src/render/backend/webgpu/uniformRing.ts +10 -1
- package/src/render/backend/webgpu/vertexFormats.ts +113 -0
- package/src/render/bloomChain.ts +3 -3
- package/src/render/boneAnimation.ts +223 -0
- package/src/render/compressedSource.ts +121 -29
- package/src/render/glCompressed.ts +83 -0
- package/src/render/globalMediumPass.ts +7 -0
- package/src/render/indexWidth.ts +27 -0
- package/src/render/instances.ts +27 -0
- package/src/render/lightBudget.ts +11 -0
- package/src/render/lightMatrix.ts +15 -0
- package/src/render/lightmap.ts +1 -1
- package/src/render/mesh.ts +72 -14
- package/src/render/pointLightSelection.ts +4 -4
- package/src/render/renderQuality.ts +38 -0
- package/src/render/rendererHarness.ts +15 -0
- package/src/render/screenSpaceReflection.ts +2 -1
- package/src/render/shader.ts +59 -0
- package/src/render/shaders/boneAnimation.ts +63 -0
- package/src/render/shaders/depth.ts +45 -10
- package/src/render/shaders/flat/directionalShadow.ts +84 -10
- package/src/render/shaders/flat/glassTint.ts +7 -1
- package/src/render/shaders/flat/index.ts +63 -7
- package/src/render/shaders/flat/layered.ts +115 -0
- package/src/render/shaders/flat/main.ts +58 -21
- package/src/render/shaders/flat/mapReads.ts +38 -0
- package/src/render/shaders/flat/models.ts +1 -1
- package/src/render/shaders/flat/movingSun.ts +46 -0
- package/src/render/shaders/flat/normalMap.ts +14 -3
- package/src/render/shaders/flat/overlay.ts +42 -20
- package/src/render/shaders/flat/pointShadow.ts +2 -2
- package/src/render/shaders/flat/preamble.ts +59 -27
- package/src/render/shaders/flat/worldUv.ts +113 -0
- package/src/render/shaders/generated/depth.wgsl.ts +95 -0
- package/src/render/shaders/generated/flat.wgsl.ts +3688 -3113
- package/src/render/shaders/generated/globalMedium.wgsl.ts +8 -3
- package/src/render/shaders/generated/lightVolume.wgsl.ts +16 -11
- package/src/render/shaders/globalMedium.ts +9 -1
- package/src/render/shaders/lightVolume.ts +9 -1
- package/src/render/shaders/outputTransform.ts +30 -14
- package/src/render/shaders/tangentFrame.ts +16 -3
- package/src/render/shaders/vertexChannel.ts +27 -0
- package/src/render/skinnedClothRun.ts +138 -38
- package/src/render/staticDraws.ts +95 -0
- package/src/render/surfaceLayers.ts +57 -0
- package/src/render/surfaceOverlay.ts +24 -7
- package/src/render/surfaceProjection.ts +57 -0
- package/src/render/surfaceTexture.ts +124 -27
- package/src/render/vertexPacking.ts +109 -0
- package/dist/render/backend/webgpu/gpuSkinnedCloth.d.ts +0 -74
- package/dist/render/backend/webgpu/gpuSkinnedCloth.js +0 -452
- package/src/render/backend/webgpu/gpuSkinnedCloth.ts +0 -502
|
@@ -22,16 +22,18 @@ export class SkinPaletteTexture {
|
|
|
22
22
|
/**
|
|
23
23
|
* Upload a palette, reallocating only when the joint count changes.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* **The texture grows and never shrinks**, so the steady state is one `texSubImage2D` whatever
|
|
26
|
+
* mix of rigs a frame draws. It was rebuilt whenever the joint count changed, which with one
|
|
27
|
+
* texture for every skinned draw meant a character and a prop drawn in turn reallocated it at
|
|
28
|
+
* every draw: a GPU allocation in the frame loop. The shader reads joints by index, so a texture
|
|
29
|
+
* wider than the rig is read exactly as one that fits.
|
|
28
30
|
*/
|
|
29
31
|
update(gl: WebGL2RenderingContext, palette: Float32Array): void {
|
|
30
32
|
validateSkinPalette(palette);
|
|
31
33
|
const joints = palette.length / 16;
|
|
32
34
|
const width = paletteTextureWidth(joints);
|
|
33
35
|
|
|
34
|
-
if (this.texture === null ||
|
|
36
|
+
if (this.texture === null || joints > this.joints) {
|
|
35
37
|
if (this.texture !== null) gl.deleteTexture(this.texture);
|
|
36
38
|
const created = gl.createTexture();
|
|
37
39
|
if (created === null) throw new Error('skin palette: failed to create the palette texture');
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A bone animation's textures on this backend, and a batch's clocks: what
|
|
3
|
+
* `shaders/boneAnimation.ts` reads by index, made once and never filtered.
|
|
4
|
+
*
|
|
5
|
+
* **`rgba32float` places and turns, and `rg32float` clocks**, all read with `textureLoad` and bound
|
|
6
|
+
* `unfilterable-float`, as the joint palette is: a turn in half floats moves a crowd's hands by a
|
|
7
|
+
* thousandth of their reach, a jitter at the frame's rate, and the bytes are a clip's, once.
|
|
8
|
+
*/
|
|
9
|
+
import {
|
|
10
|
+
CLOCK_TEXTURE_WIDTH,
|
|
11
|
+
type BoneAnimationHandle,
|
|
12
|
+
type BoneAnimationTexels,
|
|
13
|
+
} from '../../boneAnimation.ts';
|
|
14
|
+
|
|
15
|
+
const USAGE_TEXTURE = 0x4 | 0x2; // TEXTURE_BINDING | COPY_DST
|
|
16
|
+
|
|
17
|
+
/** A clip on the device, from `createBoneAnimation`. */
|
|
18
|
+
export class GpuBoneAnimation implements BoneAnimationHandle {
|
|
19
|
+
readonly bones: number;
|
|
20
|
+
readonly frames: number;
|
|
21
|
+
readonly framesPerSecond: number;
|
|
22
|
+
readonly boneScale: number;
|
|
23
|
+
readonly placesView: GPUTextureView;
|
|
24
|
+
readonly turnsView: GPUTextureView;
|
|
25
|
+
disposed = false;
|
|
26
|
+
private readonly places: GPUTexture;
|
|
27
|
+
private readonly turns: GPUTexture;
|
|
28
|
+
|
|
29
|
+
constructor(device: GPUDevice, texels: BoneAnimationTexels) {
|
|
30
|
+
this.bones = texels.bones;
|
|
31
|
+
this.frames = texels.frames;
|
|
32
|
+
this.framesPerSecond = texels.framesPerSecond;
|
|
33
|
+
this.boneScale = texels.boneScale;
|
|
34
|
+
const make = (label: string, data: Float32Array): GPUTexture => {
|
|
35
|
+
const texture = device.createTexture({
|
|
36
|
+
label,
|
|
37
|
+
size: [texels.bones, texels.frames],
|
|
38
|
+
format: 'rgba32float',
|
|
39
|
+
usage: USAGE_TEXTURE,
|
|
40
|
+
});
|
|
41
|
+
device.queue.writeTexture(
|
|
42
|
+
{ texture },
|
|
43
|
+
data,
|
|
44
|
+
{ bytesPerRow: texels.bones * 16, rowsPerImage: texels.frames },
|
|
45
|
+
[texels.bones, texels.frames],
|
|
46
|
+
);
|
|
47
|
+
return texture;
|
|
48
|
+
};
|
|
49
|
+
this.places = make('bones.places', texels.places);
|
|
50
|
+
this.turns = make('bones.turns', texels.turns);
|
|
51
|
+
this.placesView = this.places.createView();
|
|
52
|
+
this.turnsView = this.turns.createView();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
dispose(): void {
|
|
56
|
+
this.disposed = true;
|
|
57
|
+
this.places.destroy();
|
|
58
|
+
this.turns.destroy();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** A batch's clocks: two floats an instance, wrapped onto rows `CLOCK_TEXTURE_WIDTH` wide. */
|
|
63
|
+
export class GpuInstanceClocks {
|
|
64
|
+
readonly view: GPUTextureView;
|
|
65
|
+
readonly staging: Float32Array;
|
|
66
|
+
private readonly texture: GPUTexture;
|
|
67
|
+
private readonly width: number;
|
|
68
|
+
|
|
69
|
+
constructor(device: GPUDevice, capacity: number, label: string) {
|
|
70
|
+
this.width = Math.max(1, Math.min(capacity, CLOCK_TEXTURE_WIDTH));
|
|
71
|
+
const rows = Math.max(1, Math.ceil(capacity / this.width));
|
|
72
|
+
this.staging = new Float32Array(this.width * rows * 2);
|
|
73
|
+
this.texture = device.createTexture({
|
|
74
|
+
label,
|
|
75
|
+
size: [this.width, rows],
|
|
76
|
+
format: 'rg32float',
|
|
77
|
+
usage: USAGE_TEXTURE,
|
|
78
|
+
});
|
|
79
|
+
this.view = this.texture.createView();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The rows that hold the first `count` instances, from `staging`. */
|
|
83
|
+
upload(queue: GPUQueue, count: number): void {
|
|
84
|
+
if (count <= 0) return;
|
|
85
|
+
const rows = Math.ceil(count / this.width);
|
|
86
|
+
queue.writeTexture(
|
|
87
|
+
{ texture: this.texture },
|
|
88
|
+
this.staging,
|
|
89
|
+
{ bytesPerRow: this.width * 8, rowsPerImage: rows },
|
|
90
|
+
[this.width, rows],
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
dispose(): void {
|
|
95
|
+
this.texture.destroy();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -6,6 +6,16 @@ import type { MeshData } from '../../mesh.ts';
|
|
|
6
6
|
import { ABSENT_ATTRIBUTE } from '../../vertexDefaults.ts';
|
|
7
7
|
import { UPLOAD_BYTES_PER_STEP } from '../../uploadStep.ts';
|
|
8
8
|
import { INSTANCE_STRIDE } from '../../instances.ts';
|
|
9
|
+
import { compactIndices } from '../../indexWidth.ts';
|
|
10
|
+
import {
|
|
11
|
+
SNORM16_ONE,
|
|
12
|
+
UNORM16_ONE,
|
|
13
|
+
packingFor,
|
|
14
|
+
sharedValue,
|
|
15
|
+
vertexPackingOf,
|
|
16
|
+
type AttributePacking,
|
|
17
|
+
} from '../../vertexPacking.ts';
|
|
18
|
+
import { formatBytes, interleaveFixed, packedFormat, packingIn } from './vertexFormats.ts';
|
|
9
19
|
|
|
10
20
|
/**
|
|
11
21
|
* Mesh geometry as WebGPU buffers.
|
|
@@ -172,8 +182,13 @@ export interface GpuMesh {
|
|
|
172
182
|
/** The second four influences' offsets, or -1 for a mesh with four. */
|
|
173
183
|
readonly joints2: number;
|
|
174
184
|
readonly weights2: number;
|
|
185
|
+
/** How the weights are read: floats, or sixteen-bit fixed point (`vertexPacking.ts`). */
|
|
186
|
+
readonly weightsFormat: GPUVertexFormat;
|
|
187
|
+
readonly weights2Format: GPUVertexFormat;
|
|
175
188
|
} | null;
|
|
176
189
|
readonly indexBuffer: GPUBuffer;
|
|
190
|
+
/** Sixteen or thirty-two bits an index: every pass that binds `indexBuffer` says which. */
|
|
191
|
+
readonly indexFormat: GPUIndexFormat;
|
|
177
192
|
/**
|
|
178
193
|
* How many indices the mesh draws. **Zero is a mesh with nothing to draw, and no pass draws it**:
|
|
179
194
|
* a level can hold none of some kind of geometry, and a draw of zero indices does nothing but
|
|
@@ -258,18 +273,37 @@ export interface GpuMesh {
|
|
|
258
273
|
device: GPUDevice,
|
|
259
274
|
positions: Float32Array,
|
|
260
275
|
normals?: Float32Array,
|
|
261
|
-
|
|
276
|
+
staged?: StagedRewrite | null,
|
|
262
277
|
) => void)
|
|
263
278
|
| null;
|
|
264
279
|
/**
|
|
265
|
-
* A dynamic mesh's motion state, which the renderer owns: a buffer for last frame's positions
|
|
266
|
-
*
|
|
267
|
-
*
|
|
280
|
+
* A dynamic mesh's motion state, which the renderer owns: a buffer for last frame's positions and
|
|
281
|
+
* one the new positions are staged in, each made the first time a reconstructing renderer
|
|
282
|
+
* rewrites the mesh, and the frame of the last rewrite. Null on a mesh created without
|
|
283
|
+
* `{ dynamic: true }`, which never moves a vertex.
|
|
268
284
|
*/
|
|
269
|
-
readonly motion: {
|
|
285
|
+
readonly motion: {
|
|
286
|
+
previous: GPUBuffer | null;
|
|
287
|
+
staging: GPUBuffer | null;
|
|
288
|
+
changed: number;
|
|
289
|
+
} | null;
|
|
270
290
|
dispose(): void;
|
|
271
291
|
}
|
|
272
292
|
|
|
293
|
+
/**
|
|
294
|
+
* A rewrite a reconstructing renderer stages rather than writes, so last frame's positions can be
|
|
295
|
+
* kept with no submit of the rewrite's own: the new positions are written into `staging`, and two
|
|
296
|
+
* copies are recorded into `encoder` — the live positions into `previous` first, where the frame's
|
|
297
|
+
* first rewrite keeps them, then the staged ones in. The renderer submits that encoder at the head
|
|
298
|
+
* of the frame's next submit, which is what keeps both copies ahead of every draw that reads the
|
|
299
|
+
* mesh. A `writeBuffer` straight to the live positions would land before the copy aside could run.
|
|
300
|
+
*/
|
|
301
|
+
export interface StagedRewrite {
|
|
302
|
+
encoder: GPUCommandEncoder;
|
|
303
|
+
staging: GPUBuffer;
|
|
304
|
+
previous: GPUBuffer | null;
|
|
305
|
+
}
|
|
306
|
+
|
|
273
307
|
/** A mesh on its way to the device, and the iterator that gets it there. */
|
|
274
308
|
export interface IncrementalGpuMesh {
|
|
275
309
|
/**
|
|
@@ -338,17 +372,31 @@ export function createGpuMeshIncremental(
|
|
|
338
372
|
const bounds = boundsOfPositions(data.positions, createBounds());
|
|
339
373
|
const vertexCount = data.positions.length / 3;
|
|
340
374
|
const layered = data.layers !== undefined;
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
(!attribute.optional || data[attribute.name as keyof MeshData] !== undefined) &&
|
|
344
|
-
!(dynamic && isStreamed(attribute)),
|
|
345
|
-
).map((attribute) => laidOut(attribute, layered));
|
|
375
|
+
/* How each attribute travels, which the pipeline key says too: `vertexPacking.ts`. */
|
|
376
|
+
const packing = vertexPackingOf(data, dynamic);
|
|
346
377
|
|
|
347
378
|
/* Interleaved: one stride holding every attribute the mesh actually supplied — less a dynamic
|
|
348
|
-
mesh's positions and normals, which are buffers of their own
|
|
349
|
-
|
|
350
|
-
const
|
|
351
|
-
|
|
379
|
+
mesh's positions and normals, which are buffers of their own, and any attribute every vertex
|
|
380
|
+
shares, which is a constant. */
|
|
381
|
+
const fields: Field[] = [];
|
|
382
|
+
let stride = 0;
|
|
383
|
+
for (const declared of VERTEX_LAYOUT) {
|
|
384
|
+
if (declared.optional && data[declared.name as keyof MeshData] === undefined) continue;
|
|
385
|
+
if (dynamic && isStreamed(declared)) continue;
|
|
386
|
+
const attribute = laidOut(declared, layered);
|
|
387
|
+
const how = packingFor(packing, attribute.name);
|
|
388
|
+
if (how === 'constant') continue;
|
|
389
|
+
const format = packedFormat(attribute.format, how);
|
|
390
|
+
fields.push({ attribute, packing: how, format, offset: stride });
|
|
391
|
+
stride += formatBytes(format);
|
|
392
|
+
}
|
|
393
|
+
const buffer = new ArrayBuffer(stride * vertexCount);
|
|
394
|
+
const rows: Rows = {
|
|
395
|
+
floats: new Float32Array(buffer),
|
|
396
|
+
signed: new Int16Array(buffer),
|
|
397
|
+
unsigned: new Uint16Array(buffer),
|
|
398
|
+
bytes: new Uint8Array(buffer),
|
|
399
|
+
};
|
|
352
400
|
|
|
353
401
|
/*
|
|
354
402
|
* **Refused here, in one sentence, rather than by the driver a hundred times.**
|
|
@@ -364,7 +412,7 @@ export function createGpuMeshIncremental(
|
|
|
364
412
|
* whose adapter caps at the default, and it deserves a sentence naming the model's size and
|
|
365
413
|
* the device's rather than a wall of validation.
|
|
366
414
|
*/
|
|
367
|
-
const byteLength = align4(
|
|
415
|
+
const byteLength = align4(buffer.byteLength);
|
|
368
416
|
const ceiling = device.limits.maxBufferSize;
|
|
369
417
|
if (typeof ceiling === 'number' && byteLength > ceiling) {
|
|
370
418
|
throw new Error(
|
|
@@ -401,11 +449,20 @@ export function createGpuMeshIncremental(
|
|
|
401
449
|
if (value === undefined) continue;
|
|
402
450
|
absent.set(value, slot * (CONSTANT_SLOT / 4));
|
|
403
451
|
}
|
|
452
|
+
/* And what every vertex shares, where a mesh's attribute is one value: `vertexPacking.ts`. */
|
|
453
|
+
for (let slot = 0; slot < VERTEX_LAYOUT.length; slot++) {
|
|
454
|
+
const attribute = VERTEX_LAYOUT[slot] as VertexAttribute;
|
|
455
|
+
if (packingFor(packing, attribute.name) !== 'constant') continue;
|
|
456
|
+
const values = data[attribute.name as keyof MeshData] as Float32Array;
|
|
457
|
+
absent.set(sharedValue(values, attribute.components), slot * (CONSTANT_SLOT / 4));
|
|
458
|
+
}
|
|
404
459
|
device.queue.writeBuffer(constants, 0, absent);
|
|
405
460
|
|
|
461
|
+
/* Sixteen bits where every vertex fits, which every draw of this mesh says: indexWidth.ts. */
|
|
462
|
+
const indices = compactIndices(data.indices, vertexCount);
|
|
406
463
|
const indexBuffer = device.createBuffer({
|
|
407
464
|
label: 'mesh.indices',
|
|
408
|
-
size: align4(
|
|
465
|
+
size: align4(indices.byteLength),
|
|
409
466
|
usage: USAGE.INDEX | USAGE.COPY_DST,
|
|
410
467
|
});
|
|
411
468
|
|
|
@@ -434,11 +491,12 @@ export function createGpuMeshIncremental(
|
|
|
434
491
|
1,
|
|
435
492
|
Math.floor(UPLOAD_BYTES_PER_STEP / (stride + (dynamic ? 24 : 0))),
|
|
436
493
|
);
|
|
437
|
-
|
|
438
|
-
const
|
|
494
|
+
/* Whole four-byte words a step, which is all a queue writes: two sixteen-bit indices to one. */
|
|
495
|
+
const indexWidth = indices.BYTES_PER_ELEMENT;
|
|
496
|
+
const indicesPerStep = Math.max(1, Math.floor(UPLOAD_BYTES_PER_STEP / 4)) * (4 / indexWidth);
|
|
439
497
|
const totalSteps =
|
|
440
498
|
Math.max(1, Math.ceil(vertexCount / verticesPerStep)) +
|
|
441
|
-
Math.max(1, Math.ceil(
|
|
499
|
+
Math.max(1, Math.ceil(indices.length / indicesPerStep));
|
|
442
500
|
|
|
443
501
|
/*
|
|
444
502
|
* **The mesh is assembled out here, by functions of its own, and that is the fix for a copy
|
|
@@ -455,6 +513,7 @@ export function createGpuMeshIncremental(
|
|
|
455
513
|
constants,
|
|
456
514
|
streams,
|
|
457
515
|
indexBuffer,
|
|
516
|
+
indexFormat: indices instanceof Uint16Array ? 'uint16' : 'uint32',
|
|
458
517
|
stride: streams === null ? stride : 12,
|
|
459
518
|
indexCount: data.indices.length,
|
|
460
519
|
bounds,
|
|
@@ -464,7 +523,7 @@ export function createGpuMeshIncremental(
|
|
|
464
523
|
isSkinnedEight: data.joints !== undefined && data.joints2 !== undefined,
|
|
465
524
|
vertexCount,
|
|
466
525
|
hasUvs: data.uvs !== undefined,
|
|
467
|
-
skinOffsets: streams === null ? skinOffsetsOf(
|
|
526
|
+
skinOffsets: streams === null ? skinOffsetsOf(fields) : null,
|
|
468
527
|
hasChannel: data.channel !== undefined,
|
|
469
528
|
morph:
|
|
470
529
|
data.morphTargets === undefined || data.morphTargetCount === undefined
|
|
@@ -483,14 +542,14 @@ export function createGpuMeshIncremental(
|
|
|
483
542
|
|
|
484
543
|
const job: UploadJob = {
|
|
485
544
|
data,
|
|
486
|
-
|
|
545
|
+
indices,
|
|
546
|
+
rows,
|
|
487
547
|
device,
|
|
488
|
-
|
|
548
|
+
fields,
|
|
489
549
|
streams,
|
|
490
550
|
vertices,
|
|
491
551
|
indexBuffer,
|
|
492
552
|
vertexCount,
|
|
493
|
-
step,
|
|
494
553
|
stride,
|
|
495
554
|
verticesPerStep,
|
|
496
555
|
indicesPerStep,
|
|
@@ -500,20 +559,38 @@ export function createGpuMeshIncremental(
|
|
|
500
559
|
return { mesh, upload: uploadSteps(job) };
|
|
501
560
|
}
|
|
502
561
|
|
|
562
|
+
/** One attribute as a mesh interleaves it: how it travels, the format it is read with, where. */
|
|
563
|
+
interface Field {
|
|
564
|
+
readonly attribute: VertexAttribute;
|
|
565
|
+
readonly packing: AttributePacking;
|
|
566
|
+
readonly format: GPUVertexFormat;
|
|
567
|
+
/** Bytes into the vertex. */
|
|
568
|
+
readonly offset: number;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/** The interleaved rows, viewed as each field's type writes them. */
|
|
572
|
+
interface Rows {
|
|
573
|
+
readonly floats: Float32Array;
|
|
574
|
+
readonly signed: Int16Array;
|
|
575
|
+
readonly unsigned: Uint16Array;
|
|
576
|
+
readonly bytes: Uint8Array;
|
|
577
|
+
}
|
|
578
|
+
|
|
503
579
|
/**
|
|
504
580
|
* What an upload reads, held by the upload alone and let go when it finishes — so a caller that
|
|
505
581
|
* keeps its iterator, as a streamer keeps the handle it was given, keeps nothing through it.
|
|
506
582
|
*/
|
|
507
583
|
interface UploadJob {
|
|
508
584
|
data: MeshData | null;
|
|
509
|
-
|
|
585
|
+
/** The mesh's indices at the width its buffer holds them: `compactIndices`. */
|
|
586
|
+
indices: Uint16Array | Uint32Array | null;
|
|
587
|
+
rows: Rows | null;
|
|
510
588
|
readonly device: GPUDevice;
|
|
511
|
-
readonly
|
|
589
|
+
readonly fields: readonly Field[];
|
|
512
590
|
readonly streams: { readonly positions: GPUBuffer; readonly normals: GPUBuffer } | null;
|
|
513
591
|
readonly vertices: GPUBuffer;
|
|
514
592
|
readonly indexBuffer: GPUBuffer;
|
|
515
593
|
readonly vertexCount: number;
|
|
516
|
-
readonly step: number;
|
|
517
594
|
readonly stride: number;
|
|
518
595
|
readonly verticesPerStep: number;
|
|
519
596
|
readonly indicesPerStep: number;
|
|
@@ -522,33 +599,64 @@ interface UploadJob {
|
|
|
522
599
|
}
|
|
523
600
|
|
|
524
601
|
function* uploadSteps(job: UploadJob): Generator<void, void, void> {
|
|
525
|
-
const { device,
|
|
602
|
+
const { device, fields, vertices, indexBuffer, vertexCount, stride } = job;
|
|
603
|
+
/* Floats and halves a vertex: every field is whole words, so both divide. */
|
|
604
|
+
const step = stride / 4;
|
|
605
|
+
const halves = stride / 2;
|
|
526
606
|
let taken = 0;
|
|
527
607
|
for (let from = 0; from < vertexCount; from += job.verticesPerStep) {
|
|
528
608
|
const data = job.data as MeshData;
|
|
529
|
-
const
|
|
609
|
+
const rows = job.rows as Rows;
|
|
530
610
|
const to = Math.min(from + job.verticesPerStep, vertexCount);
|
|
531
|
-
|
|
532
|
-
|
|
611
|
+
for (const field of fields) {
|
|
612
|
+
const attribute = field.attribute;
|
|
533
613
|
const source = data[attribute.name as keyof MeshData] as Float32Array;
|
|
534
|
-
if (
|
|
614
|
+
if (field.packing === 'snorm16') {
|
|
615
|
+
interleaveFixed(
|
|
616
|
+
rows.signed,
|
|
617
|
+
source,
|
|
618
|
+
attribute.components,
|
|
619
|
+
halves,
|
|
620
|
+
field.offset / 2,
|
|
621
|
+
from,
|
|
622
|
+
to,
|
|
623
|
+
SNORM16_ONE,
|
|
624
|
+
);
|
|
625
|
+
} else if (field.packing === 'unorm16') {
|
|
626
|
+
interleaveFixed(
|
|
627
|
+
rows.unsigned,
|
|
628
|
+
source,
|
|
629
|
+
attribute.components,
|
|
630
|
+
halves,
|
|
631
|
+
field.offset / 2,
|
|
632
|
+
from,
|
|
633
|
+
to,
|
|
634
|
+
UNORM16_ONE,
|
|
635
|
+
);
|
|
636
|
+
} else if (attribute === LAYERED_UVS) {
|
|
535
637
|
/* (u, v) from the coordinates and the layer after them, one field of three. */
|
|
536
|
-
|
|
638
|
+
const at = field.offset / 4;
|
|
639
|
+
interleaveField(rows.floats, source, 2, step, at, from, to);
|
|
640
|
+
interleaveField(rows.floats, data.layers as Float32Array, 1, step, at + 2, from, to);
|
|
641
|
+
} else {
|
|
537
642
|
interleaveField(
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
643
|
+
rows.floats,
|
|
644
|
+
source,
|
|
645
|
+
attribute.components,
|
|
541
646
|
step,
|
|
542
|
-
|
|
647
|
+
field.offset / 4,
|
|
543
648
|
from,
|
|
544
649
|
to,
|
|
545
650
|
);
|
|
546
|
-
} else {
|
|
547
|
-
interleaveField(interleaved, source, attribute.components, step, fieldOffset, from, to);
|
|
548
651
|
}
|
|
549
|
-
fieldOffset += attribute.components;
|
|
550
652
|
}
|
|
551
|
-
device.queue.writeBuffer(
|
|
653
|
+
device.queue.writeBuffer(
|
|
654
|
+
vertices,
|
|
655
|
+
from * stride,
|
|
656
|
+
rows.bytes,
|
|
657
|
+
from * stride,
|
|
658
|
+
(to - from) * stride,
|
|
659
|
+
);
|
|
552
660
|
if (job.streams !== null) {
|
|
553
661
|
const count = (to - from) * 3;
|
|
554
662
|
device.queue.writeBuffer(job.streams.positions, from * 12, data.positions, from * 3, count);
|
|
@@ -558,7 +666,7 @@ function* uploadSteps(job: UploadJob): Generator<void, void, void> {
|
|
|
558
666
|
if (taken < job.totalSteps) yield;
|
|
559
667
|
}
|
|
560
668
|
|
|
561
|
-
const indices =
|
|
669
|
+
const indices = job.indices as Uint16Array | Uint32Array;
|
|
562
670
|
const indexWidth = indices.BYTES_PER_ELEMENT;
|
|
563
671
|
for (let from = 0; from < indices.length; from += job.indicesPerStep) {
|
|
564
672
|
const to = Math.min(from + job.indicesPerStep, indices.length);
|
|
@@ -568,7 +676,8 @@ function* uploadSteps(job: UploadJob): Generator<void, void, void> {
|
|
|
568
676
|
}
|
|
569
677
|
|
|
570
678
|
job.data = null;
|
|
571
|
-
job.
|
|
679
|
+
job.indices = null;
|
|
680
|
+
job.rows = null;
|
|
572
681
|
job.progress.uploaded = true;
|
|
573
682
|
}
|
|
574
683
|
|
|
@@ -619,23 +728,30 @@ function interleaveField(
|
|
|
619
728
|
* Where the joints and weights sit in a vertex of `supplied`, the attributes a mesh interleaves in
|
|
620
729
|
* layout order; null unless it supplied both.
|
|
621
730
|
*/
|
|
622
|
-
function skinOffsetsOf(
|
|
623
|
-
let floats = 0;
|
|
731
|
+
function skinOffsetsOf(fields: readonly Field[]): GpuMesh['skinOffsets'] {
|
|
624
732
|
let joints = -1;
|
|
625
733
|
let weights = -1;
|
|
626
734
|
let joints2 = -1;
|
|
627
735
|
let weights2 = -1;
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
if (
|
|
633
|
-
|
|
736
|
+
let weightsFormat: GPUVertexFormat = 'float32x4';
|
|
737
|
+
let weights2Format: GPUVertexFormat = 'float32x4';
|
|
738
|
+
for (const field of fields) {
|
|
739
|
+
const name = field.attribute.name;
|
|
740
|
+
if (name === 'joints') joints = field.offset;
|
|
741
|
+
if (name === 'joints2') joints2 = field.offset;
|
|
742
|
+
if (name === 'weights') {
|
|
743
|
+
weights = field.offset;
|
|
744
|
+
weightsFormat = field.format;
|
|
745
|
+
}
|
|
746
|
+
if (name === 'weights2') {
|
|
747
|
+
weights2 = field.offset;
|
|
748
|
+
weights2Format = field.format;
|
|
749
|
+
}
|
|
634
750
|
}
|
|
635
751
|
if (joints < 0 || weights < 0) return null;
|
|
636
752
|
return joints2 >= 0 && weights2 >= 0
|
|
637
|
-
? { joints, weights, joints2, weights2 }
|
|
638
|
-
: { joints, weights, joints2: -1, weights2: -1 };
|
|
753
|
+
? { joints, weights, joints2, weights2, weightsFormat, weights2Format }
|
|
754
|
+
: { joints, weights, joints2: -1, weights2: -1, weightsFormat, weights2Format };
|
|
639
755
|
}
|
|
640
756
|
|
|
641
757
|
/** The handle, made where it can see only what it hands out. */
|
|
@@ -644,6 +760,7 @@ function gpuMeshOf(parts: {
|
|
|
644
760
|
readonly constants: GPUBuffer;
|
|
645
761
|
readonly streams: { readonly positions: GPUBuffer; readonly normals: GPUBuffer } | null;
|
|
646
762
|
readonly indexBuffer: GPUBuffer;
|
|
763
|
+
readonly indexFormat: GPUIndexFormat;
|
|
647
764
|
readonly stride: number;
|
|
648
765
|
readonly indexCount: number;
|
|
649
766
|
readonly bounds: Bounds;
|
|
@@ -658,7 +775,10 @@ function gpuMeshOf(parts: {
|
|
|
658
775
|
readonly morph: MorphTexture | null;
|
|
659
776
|
readonly update: GpuMesh['update'];
|
|
660
777
|
}): GpuMesh {
|
|
661
|
-
const motion =
|
|
778
|
+
const motion =
|
|
779
|
+
parts.update === null
|
|
780
|
+
? null
|
|
781
|
+
: { previous: null as GPUBuffer | null, staging: null as GPUBuffer | null, changed: -1 };
|
|
662
782
|
const { vertices, constants, streams, indexBuffer, progress } = parts;
|
|
663
783
|
return {
|
|
664
784
|
vertexBuffers:
|
|
@@ -668,6 +788,7 @@ function gpuMeshOf(parts: {
|
|
|
668
788
|
vertexStride: parts.stride,
|
|
669
789
|
skinOffsets: parts.skinOffsets,
|
|
670
790
|
indexBuffer,
|
|
791
|
+
indexFormat: parts.indexFormat,
|
|
671
792
|
indexCount: parts.indexCount,
|
|
672
793
|
bounds: parts.bounds,
|
|
673
794
|
get complete(): boolean {
|
|
@@ -684,6 +805,7 @@ function gpuMeshOf(parts: {
|
|
|
684
805
|
motion,
|
|
685
806
|
dispose(): void {
|
|
686
807
|
motion?.previous?.destroy();
|
|
808
|
+
motion?.staging?.destroy();
|
|
687
809
|
streams?.positions.destroy();
|
|
688
810
|
streams?.normals.destroy();
|
|
689
811
|
vertices.destroy();
|
|
@@ -700,9 +822,9 @@ function isStreamed(attribute: VertexAttribute): boolean {
|
|
|
700
822
|
|
|
701
823
|
/**
|
|
702
824
|
* A dynamic mesh's `update`: the caller's positions, and its normals where it has them, each
|
|
703
|
-
* written to its own buffer as it came
|
|
704
|
-
*
|
|
705
|
-
* of
|
|
825
|
+
* written to its own buffer as it came — or, where a reconstruction keeps last frame's positions,
|
|
826
|
+
* the positions staged and copied in on the device behind the copy aside (`StagedRewrite`), so no
|
|
827
|
+
* CPU copy of anything is kept and the rewrite submits nothing of its own.
|
|
706
828
|
*/
|
|
707
829
|
function streamUpdate(
|
|
708
830
|
positionsBuffer: GPUBuffer,
|
|
@@ -715,7 +837,7 @@ function streamUpdate(
|
|
|
715
837
|
target: GPUDevice,
|
|
716
838
|
positions: Float32Array,
|
|
717
839
|
normals?: Float32Array,
|
|
718
|
-
|
|
840
|
+
staged: StagedRewrite | null = null,
|
|
719
841
|
): void => {
|
|
720
842
|
for (const [name, values] of [
|
|
721
843
|
['update', positions],
|
|
@@ -728,15 +850,18 @@ function streamUpdate(
|
|
|
728
850
|
'every other attribute are sized against it.',
|
|
729
851
|
);
|
|
730
852
|
}
|
|
731
|
-
if (previous !== null) {
|
|
732
|
-
const encoder = target.createCommandEncoder({ label: 'mesh.previousPositions' });
|
|
733
|
-
encoder.copyBufferToBuffer(positionsBuffer, 0, previous, 0, streamBytes);
|
|
734
|
-
target.queue.submit([encoder.finish()]);
|
|
735
|
-
}
|
|
736
853
|
/* Everything that decides whether this is on screen starts from the bounds, so a cloth
|
|
737
854
|
that blew sideways out of its original box would be culled while still visible. */
|
|
738
855
|
boundsOfPositions(positions, bounds);
|
|
739
|
-
|
|
856
|
+
if (staged === null) {
|
|
857
|
+
target.queue.writeBuffer(positionsBuffer, 0, positions);
|
|
858
|
+
} else {
|
|
859
|
+
target.queue.writeBuffer(staged.staging, 0, positions);
|
|
860
|
+
if (staged.previous !== null) {
|
|
861
|
+
staged.encoder.copyBufferToBuffer(positionsBuffer, 0, staged.previous, 0, streamBytes);
|
|
862
|
+
}
|
|
863
|
+
staged.encoder.copyBufferToBuffer(staged.staging, 0, positionsBuffer, 0, streamBytes);
|
|
864
|
+
}
|
|
740
865
|
if (normals !== undefined) target.queue.writeBuffer(normalsBuffer, 0, normals);
|
|
741
866
|
};
|
|
742
867
|
}
|
|
@@ -818,7 +943,10 @@ export function vertexBufferLayouts(
|
|
|
818
943
|
* in the interleaved one. A *skinned* mesh interleaves them, so removing them would shift
|
|
819
944
|
* the stride under every other attribute — which is why `createInstanced` refuses one.
|
|
820
945
|
*/
|
|
821
|
-
|
|
946
|
+
/* One value every vertex shares sits with the absent ones: `vertexPacking.ts`. */
|
|
947
|
+
const packing = packingIn(present, String(attribute.name));
|
|
948
|
+
const supplied =
|
|
949
|
+
(!attribute.optional || present[String(attribute.name)] === true) && packing !== 'constant';
|
|
822
950
|
if (instanced && INSTANCE_LOCATIONS.has(attribute.shaderLocation)) {
|
|
823
951
|
/*
|
|
824
952
|
* **Free to drop only because the mesh does not supply it.** An absent optional attribute
|
|
@@ -840,12 +968,9 @@ export function vertexBufferLayouts(
|
|
|
840
968
|
return;
|
|
841
969
|
}
|
|
842
970
|
if (supplied) {
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
format: attribute.format,
|
|
847
|
-
});
|
|
848
|
-
offset += attribute.components * 4;
|
|
971
|
+
const format = packedFormat(attribute.format, packing);
|
|
972
|
+
interleaved.push({ shaderLocation: attribute.shaderLocation, offset, format });
|
|
973
|
+
offset += formatBytes(format);
|
|
849
974
|
return;
|
|
850
975
|
}
|
|
851
976
|
constants.push({
|