@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
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { DYNAMIC_ALIGNMENT, MAX_RING_BYTES } from './uniformRing.js';
|
|
2
|
+
/**
|
|
3
|
+
* The lit stage's material blocks, each kept in its slot for as long as later draws ask for the
|
|
4
|
+
* same numbers, so a material that has not changed since the last frame costs no upload at all.
|
|
5
|
+
*
|
|
6
|
+
* **Keyed by content, because nothing else names a material.** A material here is whatever the
|
|
7
|
+
* setters left in the block when a draw took it — a consumer never hands over an object that could
|
|
8
|
+
* carry an identity — so the block's own words are the key: hashed to find a bucket, compared word
|
|
9
|
+
* for word to accept a match, and bound by the slot's offset. What it gives up is a hash and a
|
|
10
|
+
* compare of a few hundred bytes per material change, against copying and uploading the whole
|
|
11
|
+
* block every frame, which a stage of four hundred materials measured at megabytes a frame.
|
|
12
|
+
*
|
|
13
|
+
* **A slot the frame has asked for is never given away within it**, for the reason `UniformRing`
|
|
14
|
+
* exists: a queue write does not interleave with recorded draws, so rewriting a slot a recorded draw
|
|
15
|
+
* reads would hand that draw the new numbers. A frame asking for more distinct blocks than there are
|
|
16
|
+
* slots is refused, counted and skipped, as the ring was. Across frames rewriting is safe, because a
|
|
17
|
+
* write issued after a submit is ordered after the commands in it.
|
|
18
|
+
*
|
|
19
|
+
* **What a new block displaces is a slot nobody asked for this frame or the last**, found by a hand
|
|
20
|
+
* that sweeps the slots in turn; only when every slot was asked for recently does it take one the
|
|
21
|
+
* last frame used. What would make that wrong is a scene whose distinct materials a frame approach
|
|
22
|
+
* the store's size: it then rewrites some of its steady materials every frame, which costs their
|
|
23
|
+
* upload and nothing else.
|
|
24
|
+
*/
|
|
25
|
+
export class MaterialStore {
|
|
26
|
+
device;
|
|
27
|
+
usage;
|
|
28
|
+
label;
|
|
29
|
+
budget;
|
|
30
|
+
/** Replaced by `growTo`, so every bind group over it is rebuilt when that says so. */
|
|
31
|
+
buffer;
|
|
32
|
+
/** Bytes per slot, rounded up to the alignment a dynamic offset requires. */
|
|
33
|
+
slotSize;
|
|
34
|
+
words;
|
|
35
|
+
stride;
|
|
36
|
+
capacity;
|
|
37
|
+
staging;
|
|
38
|
+
ints;
|
|
39
|
+
/** Per slot: its block's hash, the next slot in its bucket or -1, and whether it holds one. */
|
|
40
|
+
hashes;
|
|
41
|
+
next;
|
|
42
|
+
held;
|
|
43
|
+
/** Per slot: the frame that last asked for it, and whether it was written since the last flush. */
|
|
44
|
+
askedIn;
|
|
45
|
+
pending;
|
|
46
|
+
/** Per slot: how many holders pinned it. A pinned slot is never displaced. */
|
|
47
|
+
pins;
|
|
48
|
+
/**
|
|
49
|
+
* How many times the store has forgotten everything it held, which growth does: a holder of an
|
|
50
|
+
* offset compares this, because an offset from before is a slot of a buffer that is gone.
|
|
51
|
+
*/
|
|
52
|
+
epoch = 0;
|
|
53
|
+
/** Per bucket: its first slot, or -1. A power of two at least twice the slots. */
|
|
54
|
+
heads;
|
|
55
|
+
mask;
|
|
56
|
+
lowPending;
|
|
57
|
+
highPending = -1;
|
|
58
|
+
hand = 0;
|
|
59
|
+
/** Starts past zero, so a slot never asked for reads as long unasked. */
|
|
60
|
+
frame = 2;
|
|
61
|
+
constructor(device, bytesPerBlock, slots, usage, label = 'materials.store', budget = null) {
|
|
62
|
+
this.device = device;
|
|
63
|
+
this.usage = usage;
|
|
64
|
+
this.label = label;
|
|
65
|
+
this.budget = budget;
|
|
66
|
+
this.words = Math.ceil(bytesPerBlock / 4);
|
|
67
|
+
this.slotSize = Math.ceil(bytesPerBlock / DYNAMIC_ALIGNMENT) * DYNAMIC_ALIGNMENT;
|
|
68
|
+
this.stride = this.slotSize / 4;
|
|
69
|
+
this.capacity = slots;
|
|
70
|
+
this.lowPending = slots;
|
|
71
|
+
this.staging = new ArrayBuffer(this.slotSize * slots);
|
|
72
|
+
this.ints = new Int32Array(this.staging);
|
|
73
|
+
this.hashes = new Int32Array(slots);
|
|
74
|
+
this.next = new Int32Array(slots);
|
|
75
|
+
this.held = new Uint8Array(slots);
|
|
76
|
+
this.askedIn = new Int32Array(slots);
|
|
77
|
+
this.pending = new Uint8Array(slots);
|
|
78
|
+
this.pins = new Int32Array(slots);
|
|
79
|
+
this.heads = new Int32Array(bucketsFor(slots)).fill(-1);
|
|
80
|
+
this.mask = this.heads.length - 1;
|
|
81
|
+
this.buffer = device.createBuffer({ label, size: this.staging.byteLength, usage });
|
|
82
|
+
}
|
|
83
|
+
/** How many distinct blocks a frame may hold. */
|
|
84
|
+
get slots() {
|
|
85
|
+
return this.capacity;
|
|
86
|
+
}
|
|
87
|
+
/** Start a frame: every slot the last one asked for may be displaced from here on, last. */
|
|
88
|
+
beginFrame() {
|
|
89
|
+
this.frame += 1;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The byte offset of a slot holding exactly `block`, written there if no slot did, or null when
|
|
93
|
+
* every slot is one this frame has asked for. `block` is the whole block, word for word.
|
|
94
|
+
*/
|
|
95
|
+
place(block) {
|
|
96
|
+
this.budget?.ask();
|
|
97
|
+
const hash = hashWords(block, this.words);
|
|
98
|
+
const bucket = hash & this.mask;
|
|
99
|
+
for (let slot = this.heads[bucket]; slot >= 0; slot = this.next[slot]) {
|
|
100
|
+
if (this.hashes[slot] === hash && this.holds(slot, block)) {
|
|
101
|
+
this.askedIn[slot] = this.frame;
|
|
102
|
+
return slot * this.slotSize;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const slot = this.displace();
|
|
106
|
+
if (slot < 0) {
|
|
107
|
+
this.budget?.drop();
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
if (this.held[slot] === 1)
|
|
111
|
+
this.unlink(slot);
|
|
112
|
+
this.ints.set(block, slot * this.stride);
|
|
113
|
+
this.hashes[slot] = hash;
|
|
114
|
+
this.next[slot] = this.heads[bucket];
|
|
115
|
+
this.heads[bucket] = slot;
|
|
116
|
+
this.held[slot] = 1;
|
|
117
|
+
this.askedIn[slot] = this.frame;
|
|
118
|
+
this.pending[slot] = 1;
|
|
119
|
+
if (slot < this.lowPending)
|
|
120
|
+
this.lowPending = slot;
|
|
121
|
+
if (slot > this.highPending)
|
|
122
|
+
this.highPending = slot;
|
|
123
|
+
return slot * this.slotSize;
|
|
124
|
+
}
|
|
125
|
+
/** Upload every slot written since the last flush, one write per run of neighbouring slots. */
|
|
126
|
+
flush() {
|
|
127
|
+
let slot = this.lowPending;
|
|
128
|
+
while (slot <= this.highPending) {
|
|
129
|
+
if (this.pending[slot] !== 1) {
|
|
130
|
+
slot += 1;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const from = slot;
|
|
134
|
+
while (slot <= this.highPending && this.pending[slot] === 1) {
|
|
135
|
+
this.pending[slot] = 0;
|
|
136
|
+
slot += 1;
|
|
137
|
+
}
|
|
138
|
+
const at = from * this.slotSize;
|
|
139
|
+
this.device.queue.writeBuffer(this.buffer, at, this.staging, at, (slot - from) * this.slotSize);
|
|
140
|
+
}
|
|
141
|
+
this.lowPending = this.capacity;
|
|
142
|
+
this.highPending = -1;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Make room for at least `slots`, forgetting every block held, and say whether the buffer was
|
|
146
|
+
* replaced. Called where `UniformRing.growTo` is, at a frame's start, for the reasons it gives,
|
|
147
|
+
* and refused past the same ceiling.
|
|
148
|
+
*/
|
|
149
|
+
growTo(slots) {
|
|
150
|
+
if (slots <= this.capacity)
|
|
151
|
+
return false;
|
|
152
|
+
if (this.slotSize * slots > MAX_RING_BYTES)
|
|
153
|
+
return false;
|
|
154
|
+
this.buffer.destroy();
|
|
155
|
+
this.capacity = slots;
|
|
156
|
+
this.staging = new ArrayBuffer(this.slotSize * slots);
|
|
157
|
+
this.ints = new Int32Array(this.staging);
|
|
158
|
+
this.hashes = new Int32Array(slots);
|
|
159
|
+
this.next = new Int32Array(slots);
|
|
160
|
+
this.held = new Uint8Array(slots);
|
|
161
|
+
this.askedIn = new Int32Array(slots);
|
|
162
|
+
this.pending = new Uint8Array(slots);
|
|
163
|
+
this.pins = new Int32Array(slots);
|
|
164
|
+
this.heads = new Int32Array(bucketsFor(slots)).fill(-1);
|
|
165
|
+
this.mask = this.heads.length - 1;
|
|
166
|
+
this.lowPending = slots;
|
|
167
|
+
this.epoch += 1;
|
|
168
|
+
this.highPending = -1;
|
|
169
|
+
this.hand = 0;
|
|
170
|
+
this.buffer = this.device.createBuffer({
|
|
171
|
+
label: this.label,
|
|
172
|
+
size: this.staging.byteLength,
|
|
173
|
+
usage: this.usage,
|
|
174
|
+
});
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Keep the block at `offset` where it is until `unpin`: a holder binding it by offset frame after
|
|
179
|
+
* frame — a list recorded once — whether or not anything asks for it. Counted, so two holders of
|
|
180
|
+
* one block each let go of their own pin.
|
|
181
|
+
*/
|
|
182
|
+
pin(offset) {
|
|
183
|
+
const slot = offset / this.slotSize;
|
|
184
|
+
this.pins[slot] = this.pins[slot] + 1;
|
|
185
|
+
}
|
|
186
|
+
unpin(offset) {
|
|
187
|
+
const slot = offset / this.slotSize;
|
|
188
|
+
if (this.pins[slot] > 0)
|
|
189
|
+
this.pins[slot] = this.pins[slot] - 1;
|
|
190
|
+
}
|
|
191
|
+
dispose() {
|
|
192
|
+
this.buffer.destroy();
|
|
193
|
+
}
|
|
194
|
+
holds(slot, block) {
|
|
195
|
+
const base = slot * this.stride;
|
|
196
|
+
for (let word = 0; word < this.words; word++) {
|
|
197
|
+
if (this.ints[base + word] !== block[word])
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* The slot a new block goes in: the first from the hand nobody asked for this frame or the last,
|
|
204
|
+
* else the first this frame has not asked for, else none. One sweep at most.
|
|
205
|
+
*/
|
|
206
|
+
displace() {
|
|
207
|
+
let fallback = -1;
|
|
208
|
+
for (let step = 0; step < this.capacity; step++) {
|
|
209
|
+
const slot = this.hand;
|
|
210
|
+
this.hand = slot + 1 === this.capacity ? 0 : slot + 1;
|
|
211
|
+
if (this.pins[slot] > 0)
|
|
212
|
+
continue;
|
|
213
|
+
const asked = this.askedIn[slot];
|
|
214
|
+
if (asked < this.frame - 1)
|
|
215
|
+
return slot;
|
|
216
|
+
if (fallback < 0 && asked !== this.frame)
|
|
217
|
+
fallback = slot;
|
|
218
|
+
}
|
|
219
|
+
return fallback;
|
|
220
|
+
}
|
|
221
|
+
unlink(slot) {
|
|
222
|
+
const bucket = this.hashes[slot] & this.mask;
|
|
223
|
+
let at = this.heads[bucket];
|
|
224
|
+
if (at === slot) {
|
|
225
|
+
this.heads[bucket] = this.next[slot];
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
while (at >= 0) {
|
|
229
|
+
const after = this.next[at];
|
|
230
|
+
if (after === slot) {
|
|
231
|
+
this.next[at] = this.next[slot];
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
at = after;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function bucketsFor(slots) {
|
|
239
|
+
let buckets = 16;
|
|
240
|
+
while (buckets < slots * 2)
|
|
241
|
+
buckets *= 2;
|
|
242
|
+
return buckets;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* MurmurHash3's 32-bit mix over the block's words. Not FNV, whose multiply carries a difference only
|
|
246
|
+
* upward: the bucket is the hash's low bits, and a material's words are mostly floats, whose low
|
|
247
|
+
* mantissa bits are zero for every value a person types — 0.5, 1, 2 — so blocks differing only in
|
|
248
|
+
* those would all have shared one bucket. The compare that follows a match is what decides.
|
|
249
|
+
*/
|
|
250
|
+
export function hashWords(block, words) {
|
|
251
|
+
let hash = 0x9747b28c;
|
|
252
|
+
for (let word = 0; word < words; word++) {
|
|
253
|
+
let k = Math.imul(block[word], 0xcc9e2d51);
|
|
254
|
+
k = (k << 15) | (k >>> 17);
|
|
255
|
+
hash ^= Math.imul(k, 0x1b873593);
|
|
256
|
+
hash = (hash << 13) | (hash >>> 19);
|
|
257
|
+
hash = (Math.imul(hash, 5) + 0xe6546b64) | 0;
|
|
258
|
+
}
|
|
259
|
+
hash ^= words * 4;
|
|
260
|
+
hash ^= hash >>> 16;
|
|
261
|
+
hash = Math.imul(hash, 0x85ebca6b);
|
|
262
|
+
hash ^= hash >>> 13;
|
|
263
|
+
hash = Math.imul(hash, 0xc2b2ae35);
|
|
264
|
+
return hash ^ (hash >>> 16);
|
|
265
|
+
}
|
|
@@ -52,6 +52,12 @@ export declare class PipelineCache {
|
|
|
52
52
|
readonly glassShadows: boolean;
|
|
53
53
|
/** How to describe each lit pipeline again, so `enable` can rebuild every one. */
|
|
54
54
|
private readonly litDescribers;
|
|
55
|
+
/**
|
|
56
|
+
* Bumped when a switch's rebuilt set lands, which replaces pipelines already handed out: a holder
|
|
57
|
+
* of one — a recorded render bundle — compares this and records again rather than drawing on
|
|
58
|
+
* with the pipelines from before the switch.
|
|
59
|
+
*/
|
|
60
|
+
version: number;
|
|
55
61
|
/** Bumped by every switch, so a lit build started before one is not kept after it. */
|
|
56
62
|
private litGeneration;
|
|
57
63
|
/** The last rebuild, which the next one waits for so they land in the order they were asked. */
|
|
@@ -51,6 +51,12 @@ export class PipelineCache {
|
|
|
51
51
|
glassShadows;
|
|
52
52
|
/** How to describe each lit pipeline again, so `enable` can rebuild every one. */
|
|
53
53
|
litDescribers = new Map();
|
|
54
|
+
/**
|
|
55
|
+
* Bumped when a switch's rebuilt set lands, which replaces pipelines already handed out: a holder
|
|
56
|
+
* of one — a recorded render bundle — compares this and records again rather than drawing on
|
|
57
|
+
* with the pipelines from before the switch.
|
|
58
|
+
*/
|
|
59
|
+
version = 0;
|
|
54
60
|
/** Bumped by every switch, so a lit build started before one is not kept after it. */
|
|
55
61
|
litGeneration = 0;
|
|
56
62
|
/** The last rebuild, which the next one waits for so they land in the order they were asked. */
|
|
@@ -201,6 +207,7 @@ export class PipelineCache {
|
|
|
201
207
|
if (result.status === 'fulfilled')
|
|
202
208
|
this.pipelines.set(result.value[0], result.value[1]);
|
|
203
209
|
}
|
|
210
|
+
this.version += 1;
|
|
204
211
|
});
|
|
205
212
|
return this.litRebuild;
|
|
206
213
|
}
|
|
@@ -5,7 +5,7 @@ import { TEMPORAL_RESOLVE_FRAG_WGSL } from '../../shaders/generated/temporalReso
|
|
|
5
5
|
import { OIT_RESOLVE_FRAG_WGSL } from '../../shaders/generated/oitResolve.wgsl.ts';
|
|
6
6
|
import { DECAL_PROJECT_FRAG_WGSL } from '../../shaders/generated/decalProject.wgsl.ts';
|
|
7
7
|
import { SSR_TRACE_FRAG_WGSL } from '../../shaders/generated/ssrTrace.wgsl.ts';
|
|
8
|
-
import { SSR_RESOLVE_FRAG_WGSL } from '../../shaders/generated/ssrResolve.wgsl.ts';
|
|
8
|
+
import { SSR_MATERIAL_RESOLVE_FRAG_WGSL, SSR_RESOLVE_FRAG_WGSL } from '../../shaders/generated/ssrResolve.wgsl.ts';
|
|
9
9
|
import { MEDIUM_FRAG_WGSL, MEDIUM_UPSAMPLE_FRAG_WGSL } from '../../shaders/generated/globalMedium.wgsl.ts';
|
|
10
10
|
import type { UniformFields } from './scatterPass.ts';
|
|
11
11
|
import type { PipelineCache } from './pipelineCache.ts';
|
|
@@ -26,7 +26,7 @@ import type { PipelineCache } from './pipelineCache.ts';
|
|
|
26
26
|
* float target the generated shaders can sample as an ordinary texture.
|
|
27
27
|
*/
|
|
28
28
|
export declare const RUSH_FRAG_FIELDS: UniformFields;
|
|
29
|
-
export declare const RUSH_FRAG_SIZE:
|
|
29
|
+
export declare const RUSH_FRAG_SIZE: 272;
|
|
30
30
|
declare const RUSH_UNIFORMS: 1;
|
|
31
31
|
declare const RUSH_TEXTURES: {
|
|
32
32
|
readonly uScene: {
|
|
@@ -39,29 +39,34 @@ declare const RUSH_TEXTURES: {
|
|
|
39
39
|
readonly sampler: 35;
|
|
40
40
|
readonly type: "sampler2D";
|
|
41
41
|
};
|
|
42
|
-
readonly
|
|
42
|
+
readonly uMotion: {
|
|
43
43
|
readonly texture: 36;
|
|
44
44
|
readonly sampler: 37;
|
|
45
45
|
readonly type: "sampler2D";
|
|
46
46
|
};
|
|
47
|
-
readonly
|
|
47
|
+
readonly uAo: {
|
|
48
48
|
readonly texture: 38;
|
|
49
49
|
readonly sampler: 39;
|
|
50
50
|
readonly type: "sampler2D";
|
|
51
51
|
};
|
|
52
|
-
readonly
|
|
52
|
+
readonly uBloom: {
|
|
53
53
|
readonly texture: 40;
|
|
54
54
|
readonly sampler: 41;
|
|
55
55
|
readonly type: "sampler2D";
|
|
56
56
|
};
|
|
57
|
-
readonly
|
|
57
|
+
readonly uExposureHeld: {
|
|
58
58
|
readonly texture: 42;
|
|
59
59
|
readonly sampler: 43;
|
|
60
60
|
readonly type: "sampler2D";
|
|
61
61
|
};
|
|
62
|
-
readonly
|
|
62
|
+
readonly uExposureLocal: {
|
|
63
63
|
readonly texture: 44;
|
|
64
64
|
readonly sampler: 45;
|
|
65
|
+
readonly type: "sampler2D";
|
|
66
|
+
};
|
|
67
|
+
readonly uGradeLut: {
|
|
68
|
+
readonly texture: 46;
|
|
69
|
+
readonly sampler: 47;
|
|
65
70
|
readonly type: "sampler3D";
|
|
66
71
|
};
|
|
67
72
|
};
|
|
@@ -180,6 +185,12 @@ export declare const PREMULTIPLIED_OVER_BLEND: GPUBlendState;
|
|
|
180
185
|
* the reflection's own and its alpha is the coverage this resolve reads.
|
|
181
186
|
*/
|
|
182
187
|
export declare const REFLECTION_OVER_BLEND: GPUBlendState;
|
|
188
|
+
/**
|
|
189
|
+
* The frame's materials' reflection, added: the found colour times the tint, less the probe's share,
|
|
190
|
+
* which is negative where the probe was brighter than what replaced it. A half-float scene takes
|
|
191
|
+
* the negative addend as the subtraction it is. Its alpha kept.
|
|
192
|
+
*/
|
|
193
|
+
export declare const FRAME_REFLECTION_BLEND: GPUBlendState;
|
|
183
194
|
/**
|
|
184
195
|
* The bloom pyramid's way back up: an octave added onto a level that the blend multiplies by that
|
|
185
196
|
* level's tint first — the blend constant, which white makes `one, one` exactly. Into the pyramid's
|
|
@@ -276,7 +287,7 @@ export declare const DECAL_TEXTURES: {
|
|
|
276
287
|
* commands, so one block rewritten between two passes gives both passes the last write.
|
|
277
288
|
*/
|
|
278
289
|
export declare const SSR_FRAG_FIELDS: UniformFields;
|
|
279
|
-
export declare const SSR_FRAG_SIZE:
|
|
290
|
+
export declare const SSR_FRAG_SIZE: 288;
|
|
280
291
|
export declare const SSR_UNIFORMS: 1;
|
|
281
292
|
export declare const SSR_TEXTURES: {
|
|
282
293
|
readonly uSsrDepth: {
|
|
@@ -289,6 +300,16 @@ export declare const SSR_TEXTURES: {
|
|
|
289
300
|
readonly sampler: 35;
|
|
290
301
|
readonly type: "sampler2D";
|
|
291
302
|
};
|
|
303
|
+
readonly uSsrProbeMap: {
|
|
304
|
+
readonly texture: 36;
|
|
305
|
+
readonly sampler: 37;
|
|
306
|
+
readonly type: "sampler2D";
|
|
307
|
+
};
|
|
308
|
+
readonly uSsrTintMap: {
|
|
309
|
+
readonly texture: 38;
|
|
310
|
+
readonly sampler: 39;
|
|
311
|
+
readonly type: "sampler2D";
|
|
312
|
+
};
|
|
292
313
|
};
|
|
293
314
|
export declare const SSR_RESOLVE_TEXTURES: {
|
|
294
315
|
readonly uSsrReflection: {
|
|
@@ -297,6 +318,27 @@ export declare const SSR_RESOLVE_TEXTURES: {
|
|
|
297
318
|
readonly type: "sampler2D";
|
|
298
319
|
};
|
|
299
320
|
};
|
|
321
|
+
/** The material resolve's block — the blur — and its three inputs. See `frameReflections.ts`. */
|
|
322
|
+
export declare const SSR_MATERIAL_FIELDS: UniformFields;
|
|
323
|
+
export declare const SSR_MATERIAL_SIZE: 16;
|
|
324
|
+
export declare const SSR_MATERIAL_UNIFORMS: 1;
|
|
325
|
+
export declare const SSR_MATERIAL_TEXTURES: {
|
|
326
|
+
readonly uSsrReflection: {
|
|
327
|
+
readonly texture: 32;
|
|
328
|
+
readonly sampler: 33;
|
|
329
|
+
readonly type: "sampler2D";
|
|
330
|
+
};
|
|
331
|
+
readonly uSsrProbeMap: {
|
|
332
|
+
readonly texture: 34;
|
|
333
|
+
readonly sampler: 35;
|
|
334
|
+
readonly type: "sampler2D";
|
|
335
|
+
};
|
|
336
|
+
readonly uSsrTintMap: {
|
|
337
|
+
readonly texture: 36;
|
|
338
|
+
readonly sampler: 37;
|
|
339
|
+
readonly type: "sampler2D";
|
|
340
|
+
};
|
|
341
|
+
};
|
|
300
342
|
/**
|
|
301
343
|
* The resolve's layout: one texture and no uniform block.
|
|
302
344
|
*
|
|
@@ -341,7 +383,7 @@ export declare const MEDIUM_UPSAMPLE_TEXTURES: {
|
|
|
341
383
|
readonly type: "sampler2D";
|
|
342
384
|
};
|
|
343
385
|
};
|
|
344
|
-
export { RUSH_FRAG_WGSL, AO_FRAG_WGSL, AO_BLUR_FRAG_WGSL, TEMPORAL_RESOLVE_FRAG_WGSL, OIT_RESOLVE_FRAG_WGSL, DECAL_PROJECT_FRAG_WGSL, SSR_TRACE_FRAG_WGSL, SSR_RESOLVE_FRAG_WGSL, };
|
|
386
|
+
export { RUSH_FRAG_WGSL, AO_FRAG_WGSL, AO_BLUR_FRAG_WGSL, TEMPORAL_RESOLVE_FRAG_WGSL, OIT_RESOLVE_FRAG_WGSL, DECAL_PROJECT_FRAG_WGSL, SSR_TRACE_FRAG_WGSL, SSR_RESOLVE_FRAG_WGSL, SSR_MATERIAL_RESOLVE_FRAG_WGSL, };
|
|
345
387
|
export { BLOOM_PREFILTER_FRAG_WGSL, BLOOM_DOWNSAMPLE_FRAG_WGSL, BLOOM_UPSAMPLE_FRAG_WGSL };
|
|
346
388
|
export { RUSH_UNIFORMS, RUSH_TEXTURES };
|
|
347
389
|
export declare const AO_UNIFORMS: 1;
|
|
@@ -6,7 +6,7 @@ import { TEMPORALRESOLVE_BINDINGS as TAA_BINDINGS, TEMPORAL_RESOLVE_FRAG_WGSL, }
|
|
|
6
6
|
import { OITRESOLVE_BINDINGS as OIT_BINDINGS, OIT_RESOLVE_FRAG_WGSL, } from '../../shaders/generated/oitResolve.wgsl.js';
|
|
7
7
|
import { DECALPROJECT_BINDINGS as DECAL_BINDINGS, DECAL_PROJECT_FRAG_WGSL, } from '../../shaders/generated/decalProject.wgsl.js';
|
|
8
8
|
import { SSRTRACE_BINDINGS as SSR_BINDINGS, SSR_TRACE_FRAG_WGSL, } from '../../shaders/generated/ssrTrace.wgsl.js';
|
|
9
|
-
import { SSRRESOLVE_BINDINGS as SSR_RESOLVE_BINDINGS, SSR_RESOLVE_FRAG_WGSL, } from '../../shaders/generated/ssrResolve.wgsl.js';
|
|
9
|
+
import { SSRRESOLVE_BINDINGS as SSR_RESOLVE_BINDINGS, SSR_MATERIAL_RESOLVE_FRAG_WGSL, SSR_RESOLVE_FRAG_WGSL, } from '../../shaders/generated/ssrResolve.wgsl.js';
|
|
10
10
|
import { GLOBALMEDIUM_BINDINGS as MEDIUM_BINDINGS, MEDIUM_FRAG_WGSL, MEDIUM_UPSAMPLE_FRAG_WGSL, } from '../../shaders/generated/globalMedium.wgsl.js';
|
|
11
11
|
import { shaderModule } from './shaderModules.js';
|
|
12
12
|
import { SCENE_ALPHA_KEEPS, SCENE_ALPHA_TRANSMITS } from '../../sceneCoverage.js';
|
|
@@ -252,6 +252,15 @@ export const REFLECTION_OVER_BLEND = {
|
|
|
252
252
|
color: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
253
253
|
alpha: SCENE_ALPHA_KEEPS,
|
|
254
254
|
};
|
|
255
|
+
/**
|
|
256
|
+
* The frame's materials' reflection, added: the found colour times the tint, less the probe's share,
|
|
257
|
+
* which is negative where the probe was brighter than what replaced it. A half-float scene takes
|
|
258
|
+
* the negative addend as the subtraction it is. Its alpha kept.
|
|
259
|
+
*/
|
|
260
|
+
export const FRAME_REFLECTION_BLEND = {
|
|
261
|
+
color: { srcFactor: 'one', dstFactor: 'one', operation: 'add' },
|
|
262
|
+
alpha: SCENE_ALPHA_KEEPS,
|
|
263
|
+
};
|
|
255
264
|
/**
|
|
256
265
|
* The bloom pyramid's way back up: an octave added onto a level that the blend multiplies by that
|
|
257
266
|
* level's tint first — the blend constant, which white makes `one, one` exactly. Into the pyramid's
|
|
@@ -340,6 +349,11 @@ export const SSR_FRAG_SIZE = SSR_BINDINGS.SSR_TRACE_FRAG.uniformSize;
|
|
|
340
349
|
export const SSR_UNIFORMS = SSR_BINDINGS.SSR_TRACE_FRAG.uniforms;
|
|
341
350
|
export const SSR_TEXTURES = SSR_BINDINGS.SSR_TRACE_FRAG.textures;
|
|
342
351
|
export const SSR_RESOLVE_TEXTURES = SSR_RESOLVE_BINDINGS.SSR_RESOLVE_FRAG.textures;
|
|
352
|
+
/** The material resolve's block — the blur — and its three inputs. See `frameReflections.ts`. */
|
|
353
|
+
export const SSR_MATERIAL_FIELDS = SSR_RESOLVE_BINDINGS.SSR_MATERIAL_RESOLVE_FRAG.fields;
|
|
354
|
+
export const SSR_MATERIAL_SIZE = SSR_RESOLVE_BINDINGS.SSR_MATERIAL_RESOLVE_FRAG.uniformSize;
|
|
355
|
+
export const SSR_MATERIAL_UNIFORMS = SSR_RESOLVE_BINDINGS.SSR_MATERIAL_RESOLVE_FRAG.uniforms;
|
|
356
|
+
export const SSR_MATERIAL_TEXTURES = SSR_RESOLVE_BINDINGS.SSR_MATERIAL_RESOLVE_FRAG.textures;
|
|
343
357
|
/**
|
|
344
358
|
* The resolve's layout: one texture and no uniform block.
|
|
345
359
|
*
|
|
@@ -390,7 +404,7 @@ export const MEDIUM_UNIFORMS = MEDIUM_BINDINGS.MEDIUM_FRAG.uniforms;
|
|
|
390
404
|
export const MEDIUM_TEXTURES = MEDIUM_BINDINGS.MEDIUM_FRAG.textures;
|
|
391
405
|
export const MEDIUM_UPSAMPLE_UNIFORMS = MEDIUM_BINDINGS.MEDIUM_UPSAMPLE_FRAG.uniforms;
|
|
392
406
|
export const MEDIUM_UPSAMPLE_TEXTURES = MEDIUM_BINDINGS.MEDIUM_UPSAMPLE_FRAG.textures;
|
|
393
|
-
export { RUSH_FRAG_WGSL, AO_FRAG_WGSL, AO_BLUR_FRAG_WGSL, TEMPORAL_RESOLVE_FRAG_WGSL, OIT_RESOLVE_FRAG_WGSL, DECAL_PROJECT_FRAG_WGSL, SSR_TRACE_FRAG_WGSL, SSR_RESOLVE_FRAG_WGSL, };
|
|
407
|
+
export { RUSH_FRAG_WGSL, AO_FRAG_WGSL, AO_BLUR_FRAG_WGSL, TEMPORAL_RESOLVE_FRAG_WGSL, OIT_RESOLVE_FRAG_WGSL, DECAL_PROJECT_FRAG_WGSL, SSR_TRACE_FRAG_WGSL, SSR_RESOLVE_FRAG_WGSL, SSR_MATERIAL_RESOLVE_FRAG_WGSL, };
|
|
394
408
|
export { BLOOM_PREFILTER_FRAG_WGSL, BLOOM_DOWNSAMPLE_FRAG_WGSL, BLOOM_UPSAMPLE_FRAG_WGSL };
|
|
395
409
|
export { RUSH_UNIFORMS, RUSH_TEXTURES };
|
|
396
410
|
export const AO_UNIFORMS = AO_BINDINGS.AO_FRAG.uniforms;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DrawCommand } from './drawCommand.ts';
|
|
2
|
+
/** Both targets' format: linear light and a tint, which an eight-bit target would clip and band. */
|
|
3
|
+
export declare const REFLECTION_SURFACE_FORMAT: GPUTextureFormat;
|
|
4
|
+
export declare class ReflectionSurfacePass {
|
|
5
|
+
private readonly device;
|
|
6
|
+
private readonly commands;
|
|
7
|
+
private probe;
|
|
8
|
+
private tint;
|
|
9
|
+
/** The environment as the frame shows it, and the roughness in alpha. */
|
|
10
|
+
probeView: GPUTextureView | null;
|
|
11
|
+
/** What a found reflection is multiplied by. */
|
|
12
|
+
tintView: GPUTextureView | null;
|
|
13
|
+
constructor(device: GPUDevice);
|
|
14
|
+
/** A command for one opaque lit draw's surface half, filled by the caller. */
|
|
15
|
+
take(): DrawCommand;
|
|
16
|
+
/** How many draws the frame kept. */
|
|
17
|
+
get kept(): number;
|
|
18
|
+
/** A new frame keeps nothing yet. */
|
|
19
|
+
reset(): void;
|
|
20
|
+
/** The two targets at the frame's size, made again only when it changes. */
|
|
21
|
+
size(width: number, height: number): void;
|
|
22
|
+
/**
|
|
23
|
+
* Every kept draw into the two targets against the frame's depth, which it reads and does not
|
|
24
|
+
* write; both cleared first, so a pixel no lit surface reached reflects nothing. Called with no
|
|
25
|
+
* pass open on `encoder`, and drawn even with nothing kept, since the clear is what the trace
|
|
26
|
+
* reads there.
|
|
27
|
+
*/
|
|
28
|
+
draw(encoder: GPUCommandEncoder, depth: GPUTextureView, issue: (pass: GPURenderPassEncoder, command: DrawCommand) => void): void;
|
|
29
|
+
release(): void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The surface half of a reflection traced through the frame's materials, on this backend: the
|
|
3
|
+
* frame's opaque lit draws again, against the depth they wrote, into two half-float targets — the
|
|
4
|
+
* environment as the frame shows it with the surface's roughness, and what a reflection found in the
|
|
5
|
+
* frame is multiplied by to land in its place. `shaders/flat/reflectionSurface.ts` is what the two
|
|
6
|
+
* hold and why the swap is exact; this is where they are drawn.
|
|
7
|
+
*
|
|
8
|
+
* **Why a second pass and not a second output of the frame's.** Every pipeline drawn into the
|
|
9
|
+
* frame's pass would have to declare a target it never writes — the sky, water, particles, text and
|
|
10
|
+
* every pass a consumer registers — so the frame keeps its one attachment, and the lit stage's two
|
|
11
|
+
* extra outputs land nowhere there. Here they land: the same pipelines with `REFLECTION_SURFACE` on,
|
|
12
|
+
* which leaves before the lamps, the same bind groups and ring slots, tested `equal` against the
|
|
13
|
+
* frame's depth so only what the frame kept writes.
|
|
14
|
+
*
|
|
15
|
+
* **The draws are commands, kept the way the skin's halves are** (`skinScatterPass.ts`): the frame
|
|
16
|
+
* graph's pool is spent at every flush, and these are replayed after the flush that ends the frame's
|
|
17
|
+
* pass. Each holds the ring slots its frame draw used, which stay valid until the frame's last
|
|
18
|
+
* submit, after this has run.
|
|
19
|
+
*
|
|
20
|
+
* **What it costs**: every opaque lit draw twice, the second without its lamps; two half-float
|
|
21
|
+
* targets the size of the frame. Single-sampled only, as the trace that reads them is.
|
|
22
|
+
*/
|
|
23
|
+
import { createCommandPool, resetPool, takeCommand } from './drawCommand.js';
|
|
24
|
+
/** Both targets' format: linear light and a tint, which an eight-bit target would clip and band. */
|
|
25
|
+
export const REFLECTION_SURFACE_FORMAT = 'rgba16float';
|
|
26
|
+
const USAGE_TARGET = 0x10 | 0x4; // RENDER_ATTACHMENT | TEXTURE_BINDING
|
|
27
|
+
export class ReflectionSurfacePass {
|
|
28
|
+
device;
|
|
29
|
+
commands = createCommandPool(256);
|
|
30
|
+
probe = null;
|
|
31
|
+
tint = null;
|
|
32
|
+
/** The environment as the frame shows it, and the roughness in alpha. */
|
|
33
|
+
probeView = null;
|
|
34
|
+
/** What a found reflection is multiplied by. */
|
|
35
|
+
tintView = null;
|
|
36
|
+
constructor(device) {
|
|
37
|
+
this.device = device;
|
|
38
|
+
}
|
|
39
|
+
/** A command for one opaque lit draw's surface half, filled by the caller. */
|
|
40
|
+
take() {
|
|
41
|
+
return this.commands.commands[takeCommand(this.commands)];
|
|
42
|
+
}
|
|
43
|
+
/** How many draws the frame kept. */
|
|
44
|
+
get kept() {
|
|
45
|
+
return this.commands.taken;
|
|
46
|
+
}
|
|
47
|
+
/** A new frame keeps nothing yet. */
|
|
48
|
+
reset() {
|
|
49
|
+
resetPool(this.commands);
|
|
50
|
+
}
|
|
51
|
+
/** The two targets at the frame's size, made again only when it changes. */
|
|
52
|
+
size(width, height) {
|
|
53
|
+
if (this.probe !== null && this.probe.width === width && this.probe.height === height)
|
|
54
|
+
return;
|
|
55
|
+
this.release();
|
|
56
|
+
const make = (label) => this.device.createTexture({
|
|
57
|
+
label,
|
|
58
|
+
size: [width, height],
|
|
59
|
+
format: REFLECTION_SURFACE_FORMAT,
|
|
60
|
+
usage: USAGE_TARGET,
|
|
61
|
+
});
|
|
62
|
+
this.probe = make('reflection.probe');
|
|
63
|
+
this.tint = make('reflection.tint');
|
|
64
|
+
this.probeView = this.probe.createView();
|
|
65
|
+
this.tintView = this.tint.createView();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Every kept draw into the two targets against the frame's depth, which it reads and does not
|
|
69
|
+
* write; both cleared first, so a pixel no lit surface reached reflects nothing. Called with no
|
|
70
|
+
* pass open on `encoder`, and drawn even with nothing kept, since the clear is what the trace
|
|
71
|
+
* reads there.
|
|
72
|
+
*/
|
|
73
|
+
draw(encoder, depth, issue) {
|
|
74
|
+
const probe = this.probeView;
|
|
75
|
+
const tint = this.tintView;
|
|
76
|
+
if (probe === null || tint === null)
|
|
77
|
+
return;
|
|
78
|
+
const pass = encoder.beginRenderPass({
|
|
79
|
+
label: 'reflection.surface',
|
|
80
|
+
colorAttachments: [
|
|
81
|
+
null,
|
|
82
|
+
{ view: probe, clearValue: [0, 0, 0, 1], loadOp: 'clear', storeOp: 'store' },
|
|
83
|
+
{ view: tint, clearValue: [0, 0, 0, 0], loadOp: 'clear', storeOp: 'store' },
|
|
84
|
+
],
|
|
85
|
+
depthStencilAttachment: { view: depth, depthReadOnly: true },
|
|
86
|
+
});
|
|
87
|
+
for (let i = 0; i < this.commands.taken; i += 1) {
|
|
88
|
+
issue(pass, this.commands.commands[i]);
|
|
89
|
+
}
|
|
90
|
+
pass.end();
|
|
91
|
+
}
|
|
92
|
+
release() {
|
|
93
|
+
this.probe?.destroy();
|
|
94
|
+
this.tint?.destroy();
|
|
95
|
+
this.probe = null;
|
|
96
|
+
this.tint = null;
|
|
97
|
+
this.probeView = null;
|
|
98
|
+
this.tintView = null;
|
|
99
|
+
}
|
|
100
|
+
}
|