@driftengine/core 4.4.1 → 4.4.2
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 +26 -0
- package/README.md +1 -1
- package/dist/render/backend/webgl2/renderer.d.ts +3 -0
- package/dist/render/backend/webgl2/renderer.js +13 -0
- package/dist/render/backend/webgpu/postPass.d.ts +19 -3
- package/dist/render/backend/webgpu/postPass.js +17 -4
- package/dist/render/backend/webgpu/renderer.d.ts +10 -0
- package/dist/render/backend/webgpu/renderer.js +67 -4
- package/dist/render/flameLight.js +15 -2
- package/dist/render/pointShadowBudget.js +51 -41
- package/dist/render/recon/disocclusion.d.ts +36 -3
- package/dist/render/recon/disocclusion.js +56 -4
- package/dist/render/recon/resolve.js +95 -12
- package/dist/render/sceneTarget.d.ts +2 -0
- package/dist/render/sceneTarget.js +1 -1
- package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +31 -6
- package/dist/render/shaders/generated/temporalResolve.wgsl.js +31 -6
- package/dist/render/shaders/recon/resolve.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/resolve.wgsl.js +112 -8
- package/dist/render/shaders/temporalResolve.js +133 -5
- package/dist/render/temporalAa.d.ts +145 -0
- package/dist/render/temporalAa.js +190 -0
- package/dist/render/temporalPass.d.ts +16 -14
- package/dist/render/temporalPass.js +59 -14
- package/package.json +6 -6
- package/src/render/backend/webgl2/renderer.ts +21 -1
- package/src/render/backend/webgpu/postPass.ts +34 -4
- package/src/render/backend/webgpu/renderer.ts +70 -4
- package/src/render/flameLight.ts +15 -2
- package/src/render/pointShadowBudget.ts +49 -39
- package/src/render/recon/disocclusion.ts +54 -3
- package/src/render/recon/resolve.ts +137 -10
- package/src/render/sceneTarget.ts +8 -1
- package/src/render/shaders/generated/temporalResolve.wgsl.ts +31 -6
- package/src/render/shaders/recon/resolve.wgsl.ts +112 -8
- package/src/render/shaders/temporalResolve.ts +141 -5
- package/src/render/temporalAa.ts +227 -0
- package/src/render/temporalPass.ts +88 -12
package/src/render/flameLight.ts
CHANGED
|
@@ -82,6 +82,7 @@ export function flameFrequencyHz(diameterM: number): number {
|
|
|
82
82
|
export function createFlame(options: FlameOptions): Flame {
|
|
83
83
|
const height = HEIGHT_PER_DIAMETER * options.diameterM;
|
|
84
84
|
const centre: Vec3 = [options.x, options.y + height / 3, options.z];
|
|
85
|
+
const swayM = (options.sway ?? SWAY_PER_HEIGHT) * height;
|
|
85
86
|
/* A seed spread over the whole turn, so seeds 1 and 2 are not neighbours in phase. */
|
|
86
87
|
const phase = ((options.seed ?? 0) * 2.399963) % (Math.PI * 2);
|
|
87
88
|
const light: PointLightSource = {
|
|
@@ -94,7 +95,19 @@ export function createFlame(options: FlameOptions): Flame {
|
|
|
94
95
|
radius: options.radius,
|
|
95
96
|
/* Off, because this helper is the flicker; the selection's own would apply a second one. */
|
|
96
97
|
flicker: 0,
|
|
97
|
-
|
|
98
|
+
/*
|
|
99
|
+
* **Clear of what the fire burns from wherever the light has wandered**, which is the sway added
|
|
100
|
+
* to the near plane a still flame would want. The shadow map is baked from where the light
|
|
101
|
+
* stood, so the cut moves with it, and each axis moves by at most `swayM`: a near plane of D
|
|
102
|
+
* alone left a brazier's bowl 7 mm inside it at the top of the sway and 13 cm outside at the
|
|
103
|
+
* bottom, and the bowl's shadow on the floor under the brazier came and went with every
|
|
104
|
+
* re-bake — a dark disc on some, none on others.
|
|
105
|
+
*
|
|
106
|
+
* What it gives up is `swayM` of shadow nearest the light, which is inside the fixture. What
|
|
107
|
+
* would make it wrong is a fixture reaching further below the flame than D / 6: this clears
|
|
108
|
+
* that far and no further, so a deep bowl sets its own `shadowNear` from its own depth.
|
|
109
|
+
*/
|
|
110
|
+
shadowNear: Math.max(0.05, options.diameterM) + swayM,
|
|
98
111
|
sourceRadius: options.diameterM / 2,
|
|
99
112
|
...(options.castsShadow === false ? { castsShadow: false } : {}),
|
|
100
113
|
};
|
|
@@ -112,7 +125,7 @@ export function createFlame(options: FlameOptions): Flame {
|
|
|
112
125
|
color: [options.color[0], options.color[1], options.color[2]],
|
|
113
126
|
flicker: options.flicker ?? 0.18,
|
|
114
127
|
phase,
|
|
115
|
-
swayM
|
|
128
|
+
swayM,
|
|
116
129
|
};
|
|
117
130
|
}
|
|
118
131
|
|
|
@@ -256,15 +256,15 @@ export function runPointShadowBakes<M extends StaleCheck, L extends BakeableLigh
|
|
|
256
256
|
* **The run decays rather than resetting, and it climbs past the threshold before it stops.**
|
|
257
257
|
*
|
|
258
258
|
* A light that wanders on a curve is not stale on *every* frame — near the turning points of
|
|
259
|
-
* its travel it moves less in a frame than the rebake tolerance
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
259
|
+
* its travel it moves less in a frame than the rebake tolerance. When the run decided whether a
|
|
260
|
+
* wanderer got its whole cube, a run that reset to zero dropped it back to two faces a frame
|
|
261
|
+
* there, and the shadow stepped through the slow part of the wander: reported as a vibration
|
|
262
|
+
* against a brazier. Every image-holding map is re-baked whole now, so the run only orders the
|
|
263
|
+
* queue, and the hysteresis keeps a wanderer behind the lights that settle instead of letting
|
|
264
|
+
* it jump ahead at every turning point.
|
|
264
265
|
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
* so a light that genuinely settles stops re-baking rather than holding a budget for ever.
|
|
266
|
+
* It climbs to twice the threshold, which keeps a light chronic for three quiet frames, and
|
|
267
|
+
* decays one frame at a time so a light that genuinely settles rejoins the ordinary order.
|
|
268
268
|
*/
|
|
269
269
|
const previous = scratch.staleRun[slot] ?? 0;
|
|
270
270
|
const run = stale
|
|
@@ -285,37 +285,40 @@ export function runPointShadowBakes<M extends StaleCheck, L extends BakeableLigh
|
|
|
285
285
|
let faces = facesPerFrame;
|
|
286
286
|
let urgentSpent = false;
|
|
287
287
|
/*
|
|
288
|
-
* **
|
|
289
|
-
*
|
|
290
|
-
* dribbled out at two faces a frame is a map nobody can sample correctly until it lands.
|
|
288
|
+
* **A map that holds an image is re-baked whole or not at all**, and one being shaded may take a
|
|
289
|
+
* whole cube a frame outside the budget to make that possible.
|
|
291
290
|
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
* wanders about once a second.
|
|
291
|
+
* Faces land in the layer the shader samples as they are drawn, and `planBake` publishes the
|
|
292
|
+
* origin they were drawn from only with the last one. So a re-bake spread over frames is a cube
|
|
293
|
+
* the shader reads from the old origin with part of it drawn from the new one — and a face is a
|
|
294
|
+
* 90 degree frustum, so the part drawn from somewhere else is a straight-edged quadrilateral of
|
|
295
|
+
* wrong shadow on the ground under the lamp. With the budget spent elsewhere it could hold for a
|
|
296
|
+
* second and more. Reported under a brazier as a dark shape that came and went.
|
|
299
297
|
*
|
|
300
|
-
*
|
|
298
|
+
* A map with no image yet is not sampled until its sixth face lands (see
|
|
299
|
+
* `PointShadowSystem.bind`), so it still fills a few faces a frame, and a cold one being shaded
|
|
300
|
+
* still jumps the queue with all six.
|
|
301
301
|
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
* cost the frame.
|
|
302
|
+
* The allowance used to be for a *chronically* stale light only — a wandering flame — whose
|
|
303
|
+
* dribbled cube published a new origin once every third frame, so its shadow stepped at 20 Hz
|
|
304
|
+
* where the flame wanders about once a second: reported as motion that was "really fast, not
|
|
305
|
+
* smooth, snappy, and unrealistic". Any shaded light is owed the same now, because a cube read
|
|
306
|
+
* part-way is wrong in the same place for the same reason whether or not it will be stale again.
|
|
308
307
|
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
308
|
+
* **Bounded to one light, and it has to be.** Eight braziers each taking six passes is the 48
|
|
309
|
+
* passes and 89 ms `pointShadowFacesPerFrame` exists to prevent. The first in the plan's order
|
|
310
|
+
* takes it, and `planPointShadowBakes` puts the lights that settled ahead of the ones that never
|
|
311
|
+
* do, so a flame refining its image cannot hold a correction hostage. The rest keep sampling a
|
|
312
|
+
* complete image from a few centimetres away until their turn, which is the trade
|
|
313
|
+
* `pointShadowRebakeDistance` already makes. A warm map, held but not shaded, is re-baked when a
|
|
314
|
+
* whole cube fits the budget or once it is shaded, and not before.
|
|
312
315
|
*
|
|
313
|
-
* **What would make it wrong** is a caster set heavy enough that six passes over it does not
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
+
* **What would make it wrong** is a caster set heavy enough that six passes over it does not fit
|
|
317
|
+
* the frame. Measured against a game whose whole static world is about 8,500 triangles in a
|
|
318
|
+
* handful of draws; a world an order of magnitude heavier wants `pointShadowFacesPerFrame`
|
|
316
319
|
* raised or this given up, and `gpuTiming` is how to tell which.
|
|
317
320
|
*/
|
|
318
|
-
let
|
|
321
|
+
let refreshSpent = false;
|
|
319
322
|
for (let i = 0; i < planned && faces > 0; i++) {
|
|
320
323
|
const slot = scratch.order[i] ?? -1;
|
|
321
324
|
/*
|
|
@@ -328,13 +331,20 @@ export function runPointShadowBakes<M extends StaleCheck, L extends BakeableLigh
|
|
|
328
331
|
if (light === undefined || map === undefined) continue;
|
|
329
332
|
|
|
330
333
|
const sampled = slot < pool.sampledCount;
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
334
|
+
if (scratch.ready[slot] !== 1) {
|
|
335
|
+
/* No image to spoil: a few faces a frame, or all six at once for one being shaded. */
|
|
336
|
+
const urgent = sampled && !urgentSpent;
|
|
337
|
+
if (urgent) urgentSpent = true;
|
|
338
|
+
faces -= bake(map, light, staticCasters, urgent ? faceCount : faces);
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
if (faces >= faceCount) {
|
|
342
|
+
faces -= bake(map, light, staticCasters, faceCount);
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
if (!sampled || refreshSpent) continue;
|
|
346
|
+
refreshSpent = true;
|
|
347
|
+
faces -= bake(map, light, staticCasters, faceCount);
|
|
338
348
|
}
|
|
339
349
|
|
|
340
350
|
/*
|
|
@@ -12,10 +12,15 @@
|
|
|
12
12
|
* a different part of a texel than the one it stands for, which at a grazing angle is a different
|
|
13
13
|
* depth; the tolerance grows with the motion's length.
|
|
14
14
|
*
|
|
15
|
+
* **And in proportion to the surface's own slope.** A new jitter samples a surface somewhere else, so
|
|
16
|
+
* on one turned from the eye two frames' samples of it differ by up to a texel's worth of its depth
|
|
17
|
+
* with nothing moved. `surfaceSlope` measures that step on the surface's own side of any silhouette.
|
|
18
|
+
*
|
|
15
19
|
* **Normals, for the case depth cannot see.** A leaf's two sides are at one depth, and the history of
|
|
16
20
|
* the front is not the back. The forward frame has no normal buffer, so both normals come from their
|
|
17
21
|
* frame's depth — `worldPositionFromDepth` and `normalFromPositions` — in world space, where the two
|
|
18
|
-
* frames agree.
|
|
22
|
+
* frames agree. **A normal differenced across an edge is not a normal**, so the caller weighs each by
|
|
23
|
+
* `planarity`: at an edge, a sliver, or anything finer than a texel the depth test decides alone.
|
|
19
24
|
*
|
|
20
25
|
* **Continuous in every input**, because a step is a line on screen along which the history is kept on
|
|
21
26
|
* one frame and dropped on the next: every threshold is a smoothstep, never a comparison.
|
|
@@ -51,12 +56,57 @@ function smoothstep(edge0: number, edge1: number, x: number): number {
|
|
|
51
56
|
return t * t * (3 - 2 * t);
|
|
52
57
|
}
|
|
53
58
|
|
|
59
|
+
/**
|
|
60
|
+
* The band over which three texels stop being one plane: how far their two steps in inverse depth
|
|
61
|
+
* fail to cancel, as a share of the two together. None of it is a plane at any angle; all of it is an
|
|
62
|
+
* edge — one side steps, the other does not — or a sliver, both stepping the same way.
|
|
63
|
+
*
|
|
64
|
+
* **A share and not a size**, which is the lesson of the rods in `resolve.test.ts`: a part a
|
|
65
|
+
* hundredth of the depth in front of a wall passes the depth test, and a normal differenced across it
|
|
66
|
+
* still leans by its height over a texel's width — nearly edge-on where texels are small. What would
|
|
67
|
+
* make this wrong is a curved surface judged at its apex, where both steps lean one way and the
|
|
68
|
+
* normal is sound; there it only gives the normals less say, which the depth test does not need.
|
|
69
|
+
*/
|
|
70
|
+
export const PLANAR_FROM = 0.25;
|
|
71
|
+
export const PLANAR_TO = 0.5;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* How sure it is that `centre` and its neighbours either side along one axis lie on one plane, one to
|
|
75
|
+
* zero. Inverse depth is affine across a plane on screen, so a plane's two steps cancel whatever its
|
|
76
|
+
* angle. One where a neighbour is missing — zero, off the picture or undrawn — or where there is no
|
|
77
|
+
* step to compare: nothing to judge by, so a normal keeps the say it always had.
|
|
78
|
+
*/
|
|
79
|
+
export function planarity(before: number, centre: number, after: number): number {
|
|
80
|
+
if (!(before > 0) || !(centre > 0) || !(after > 0)) return 1;
|
|
81
|
+
const a = 1 / after - 1 / centre;
|
|
82
|
+
const b = 1 / before - 1 / centre;
|
|
83
|
+
const spread = Math.abs(a) + Math.abs(b);
|
|
84
|
+
if (!(spread > 0)) return 1;
|
|
85
|
+
return 1 - smoothstep(PLANAR_FROM, PLANAR_TO, Math.abs(a + b) / spread);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* How far a surface's depth moves across one texel along an axis, relative to the depth: the smaller
|
|
90
|
+
* of the steps to its two neighbours, because beside a silhouette one of them is the surface behind.
|
|
91
|
+
* Zero at a sliver — nearer or farther than both, so each step is to another surface — and one
|
|
92
|
+
* neighbour's step where only one is there.
|
|
93
|
+
*/
|
|
94
|
+
export function surfaceSlope(before: number, centre: number, after: number): number {
|
|
95
|
+
const a = after > 0 ? after - centre : Number.NaN;
|
|
96
|
+
const b = before > 0 ? before - centre : Number.NaN;
|
|
97
|
+
if (Number.isNaN(a)) return Number.isNaN(b) ? 0 : Math.abs(b) / centre;
|
|
98
|
+
if (Number.isNaN(b)) return Math.abs(a) / centre;
|
|
99
|
+
if (a * b > 0) return 0;
|
|
100
|
+
return Math.min(Math.abs(a), Math.abs(b)) / centre;
|
|
101
|
+
}
|
|
102
|
+
|
|
54
103
|
/**
|
|
55
104
|
* One where the history is trustworthy, zero where it is not, and continuous between.
|
|
56
105
|
*
|
|
57
106
|
* `currDepth` is the view depth this surface should have had last frame; `histDepth` the view depth
|
|
58
107
|
* last frame held where it lands, or zero where it landed off the screen; `motionLength` the motion's
|
|
59
|
-
* length in uv; `normalDot` the cosine between the two frames' world normals there
|
|
108
|
+
* length in uv; `normalDot` the cosine between the two frames' world normals there; `slope` the
|
|
109
|
+
* surface's `surfaceSlope`, which widens the tolerance one for one.
|
|
60
110
|
*/
|
|
61
111
|
export function disocclusionWeight(
|
|
62
112
|
currDepth: number,
|
|
@@ -64,12 +114,13 @@ export function disocclusionWeight(
|
|
|
64
114
|
motionLength: number,
|
|
65
115
|
normalDot: number,
|
|
66
116
|
params: DisocclusionParams,
|
|
117
|
+
slope = 0,
|
|
67
118
|
): number {
|
|
68
119
|
if (!(currDepth > 0) || !(histDepth > 0) || !(motionLength >= 0) || Number.isNaN(normalDot)) {
|
|
69
120
|
return 0;
|
|
70
121
|
}
|
|
71
122
|
const disagreement = Math.abs(currDepth - histDepth) / currDepth;
|
|
72
|
-
const tolerance = params.depthTolerance + params.motionScale * motionLength;
|
|
123
|
+
const tolerance = params.depthTolerance + params.motionScale * motionLength + slope;
|
|
73
124
|
const depth = 1 - smoothstep(tolerance, 2 * tolerance, disagreement);
|
|
74
125
|
const normal = smoothstep(params.normalFloor, params.normalCeiling, normalDot);
|
|
75
126
|
return depth * normal;
|
|
@@ -21,8 +21,10 @@
|
|
|
21
21
|
* previous view depth in its third channel; otherwise it is the camera's, through the surface's
|
|
22
22
|
* world position.
|
|
23
23
|
* 4. Where the surface was is read from the history — its colour and the weight it had gathered — and
|
|
24
|
-
* last frame's depth
|
|
25
|
-
*
|
|
24
|
+
* last frame's depth says whether it is the same surface: the nearest of the nine texels around
|
|
25
|
+
* where the dilated texel was, forgiven its own slope across a texel. The two frames' normals, from
|
|
26
|
+
* their depths, catch thin geometry, each with the say its planarity gives it. The disocclusion
|
|
27
|
+
* scales the history's weight.
|
|
26
28
|
* 5. The history is clipped to the box, its weight capped so a tenth of each frame is always new, and
|
|
27
29
|
* the two are mixed by their weights. Where the pixel has gathered less than one sample's worth,
|
|
28
30
|
* the render read bicubically fills the gap. The history keeps colour and weight; the picture shown
|
|
@@ -33,7 +35,13 @@
|
|
|
33
35
|
* buffer before a sample reaches this arithmetic, as the temporal resolve already does.
|
|
34
36
|
*/
|
|
35
37
|
import { clipToBox, rgbToYCoCg, varianceBox, yCoCgToRgb } from './clamp.ts';
|
|
36
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
disocclusionWeight,
|
|
40
|
+
normalFromPositions,
|
|
41
|
+
planarity,
|
|
42
|
+
surfaceSlope,
|
|
43
|
+
worldPositionFromDepth,
|
|
44
|
+
} from './disocclusion.ts';
|
|
37
45
|
import type { DisocclusionParams } from './disocclusion.ts';
|
|
38
46
|
import { sampleBilinear, sampleHistoryBicubic5 } from './reproject.ts';
|
|
39
47
|
|
|
@@ -209,6 +217,59 @@ function worldAt(
|
|
|
209
217
|
return 1 / w;
|
|
210
218
|
}
|
|
211
219
|
|
|
220
|
+
/**
|
|
221
|
+
* A texel's view depth at its unjittered uv, or 0 — `worldAt` without the position, which is all a
|
|
222
|
+
* search over depths needs: one row of the inverse rather than four. Zero off the picture, where
|
|
223
|
+
* `worldAt` would clamp, because a neighbour that is not there is not a step.
|
|
224
|
+
*/
|
|
225
|
+
function viewDepthAt(
|
|
226
|
+
depths: ArrayLike<number>,
|
|
227
|
+
inverse: ArrayLike<number>,
|
|
228
|
+
jitter: ArrayLike<number>,
|
|
229
|
+
width: number,
|
|
230
|
+
height: number,
|
|
231
|
+
x: number,
|
|
232
|
+
y: number,
|
|
233
|
+
): number {
|
|
234
|
+
if (x < 0 || y < 0 || x >= width || y >= height) return 0;
|
|
235
|
+
const u = (x + 0.5 - (jitter[0] as number)) / width;
|
|
236
|
+
const v = (y + 0.5 - (jitter[1] as number)) / height;
|
|
237
|
+
const m = inverse;
|
|
238
|
+
const w =
|
|
239
|
+
(m[3] as number) * (u * 2 - 1) +
|
|
240
|
+
(m[7] as number) * (v * 2 - 1) +
|
|
241
|
+
(m[11] as number) * (depths[y * width + x] as number) +
|
|
242
|
+
(m[15] as number);
|
|
243
|
+
return Math.abs(w) > 1e-12 ? 1 / w : 0;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** What a texel's four neighbours say about its surface: see `planarity` and `surfaceSlope`. */
|
|
247
|
+
const SURFACE = { planar: 1, slope: 0 };
|
|
248
|
+
|
|
249
|
+
function surfaceAt(
|
|
250
|
+
depths: ArrayLike<number>,
|
|
251
|
+
inverse: ArrayLike<number>,
|
|
252
|
+
jitter: ArrayLike<number>,
|
|
253
|
+
width: number,
|
|
254
|
+
height: number,
|
|
255
|
+
x: number,
|
|
256
|
+
y: number,
|
|
257
|
+
centre: number,
|
|
258
|
+
): void {
|
|
259
|
+
let planar = 1;
|
|
260
|
+
let slope = 0;
|
|
261
|
+
for (let axis = 0; axis < 2; axis += 1) {
|
|
262
|
+
const ax = 1 - axis;
|
|
263
|
+
const ay = axis;
|
|
264
|
+
const after = viewDepthAt(depths, inverse, jitter, width, height, x + ax, y + ay);
|
|
265
|
+
const before = viewDepthAt(depths, inverse, jitter, width, height, x - ax, y - ay);
|
|
266
|
+
planar *= planarity(before, centre, after);
|
|
267
|
+
slope = Math.max(slope, surfaceSlope(before, centre, after));
|
|
268
|
+
}
|
|
269
|
+
SURFACE.planar = planar;
|
|
270
|
+
SURFACE.slope = slope;
|
|
271
|
+
}
|
|
272
|
+
|
|
212
273
|
/** The world normal at a texel, from its depth and its right and upper neighbours'. */
|
|
213
274
|
function normalAt(
|
|
214
275
|
depths: ArrayLike<number>,
|
|
@@ -282,20 +343,84 @@ function historyWeight(frame: ResolveFrame, u: number, v: number, dx: number, dy
|
|
|
282
343
|
4,
|
|
283
344
|
HISTORY,
|
|
284
345
|
);
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
346
|
+
/*
|
|
347
|
+
* **Last frame's depth is searched for this surface, around where the dilated texel was.** The
|
|
348
|
+
* surface being judged is the dilated texel's, which beside an edge is a neighbour's, so judging
|
|
349
|
+
* it by the texel under the pixel compares two surfaces: the side of every silhouette away from the
|
|
350
|
+
* eye dropped its history on every frame of a still picture. And a new jitter samples a surface
|
|
351
|
+
* somewhere else, so the nearest of last frame's nine is taken rather than the one the rounding
|
|
352
|
+
* picks. What it gives up is a disocclusion narrower than a texel, which keeps a history that the
|
|
353
|
+
* neighbourhood clip then bounds.
|
|
354
|
+
*/
|
|
355
|
+
const su = (dx + 0.5 - (frame.jitter[0] as number)) / rw + mu;
|
|
356
|
+
const sv = (dy + 0.5 - (frame.jitter[1] as number)) / rh + mv;
|
|
357
|
+
const cx = clampTexel(Math.round(su * rw + (frame.previousJitter[0] as number) - 0.5), rw);
|
|
358
|
+
const cy = clampTexel(Math.round(sv * rh + (frame.previousJitter[1] as number) - 0.5), rh);
|
|
359
|
+
/*
|
|
360
|
+
* The first texel looked at answers alone when it agrees within the tolerance, which it does
|
|
361
|
+
* everywhere but at an edge: the depth test trusts it fully whichever texel would have won, so
|
|
362
|
+
* only an edge pays for the other eight.
|
|
363
|
+
*/
|
|
364
|
+
let held = viewDepthAt(
|
|
288
365
|
frame.previousDepth,
|
|
289
366
|
frame.previousInverseViewProj,
|
|
290
367
|
frame.previousJitter,
|
|
291
368
|
rw,
|
|
292
369
|
rh,
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
RIGHT,
|
|
370
|
+
cx,
|
|
371
|
+
cy,
|
|
296
372
|
);
|
|
373
|
+
let px = cx;
|
|
374
|
+
let py = cy;
|
|
375
|
+
if (!(held > 0 && Math.abs(held - expected) <= frame.disocclusion.depthTolerance * expected)) {
|
|
376
|
+
held = 0;
|
|
377
|
+
let nearest = Number.POSITIVE_INFINITY;
|
|
378
|
+
for (let j = -1; j <= 1; j += 1) {
|
|
379
|
+
for (let i = -1; i <= 1; i += 1) {
|
|
380
|
+
const tx = clampTexel(cx + i, rw);
|
|
381
|
+
const ty = clampTexel(cy + j, rh);
|
|
382
|
+
const depth = viewDepthAt(
|
|
383
|
+
frame.previousDepth,
|
|
384
|
+
frame.previousInverseViewProj,
|
|
385
|
+
frame.previousJitter,
|
|
386
|
+
rw,
|
|
387
|
+
rh,
|
|
388
|
+
tx,
|
|
389
|
+
ty,
|
|
390
|
+
);
|
|
391
|
+
if (!(depth > 0)) continue;
|
|
392
|
+
const off = Math.abs(depth - expected);
|
|
393
|
+
if (off < nearest) {
|
|
394
|
+
nearest = off;
|
|
395
|
+
held = depth;
|
|
396
|
+
px = tx;
|
|
397
|
+
py = ty;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const here = viewDepthAt(frame.depth, frame.inverseViewProj, frame.jitter, rw, rh, dx, dy);
|
|
404
|
+
surfaceAt(frame.depth, frame.inverseViewProj, frame.jitter, rw, rh, dx, dy, here);
|
|
405
|
+
const slope = SURFACE.slope;
|
|
406
|
+
let planar = SURFACE.planar;
|
|
407
|
+
if (planar > 0) {
|
|
408
|
+
surfaceAt(
|
|
409
|
+
frame.previousDepth,
|
|
410
|
+
frame.previousInverseViewProj,
|
|
411
|
+
frame.previousJitter,
|
|
412
|
+
rw,
|
|
413
|
+
rh,
|
|
414
|
+
px,
|
|
415
|
+
py,
|
|
416
|
+
held,
|
|
417
|
+
);
|
|
418
|
+
planar *= SURFACE.planar;
|
|
419
|
+
}
|
|
420
|
+
/* A normal has the say its planarity gives it; at an edge or a sliver, none, and none is computed. */
|
|
297
421
|
let normalDot = 1;
|
|
298
422
|
if (
|
|
423
|
+
planar > 0 &&
|
|
299
424
|
normalAt(frame.depth, frame.inverseViewProj, frame.jitter, frame.eye, rw, rh, dx, dy, NORMAL) &&
|
|
300
425
|
normalAt(
|
|
301
426
|
frame.previousDepth,
|
|
@@ -309,10 +434,11 @@ function historyWeight(frame: ResolveFrame, u: number, v: number, dx: number, dy
|
|
|
309
434
|
PREVIOUS_NORMAL,
|
|
310
435
|
)
|
|
311
436
|
) {
|
|
312
|
-
|
|
437
|
+
const cosine =
|
|
313
438
|
(NORMAL[0] as number) * (PREVIOUS_NORMAL[0] as number) +
|
|
314
439
|
(NORMAL[1] as number) * (PREVIOUS_NORMAL[1] as number) +
|
|
315
440
|
(NORMAL[2] as number) * (PREVIOUS_NORMAL[2] as number);
|
|
441
|
+
normalDot = 1 - planar * (1 - cosine);
|
|
316
442
|
}
|
|
317
443
|
const trust = disocclusionWeight(
|
|
318
444
|
expected,
|
|
@@ -320,6 +446,7 @@ function historyWeight(frame: ResolveFrame, u: number, v: number, dx: number, dy
|
|
|
320
446
|
Math.hypot(mu, mv),
|
|
321
447
|
normalDot,
|
|
322
448
|
frame.disocclusion,
|
|
449
|
+
slope,
|
|
323
450
|
);
|
|
324
451
|
return (HISTORY[3] as number) * trust;
|
|
325
452
|
}
|
|
@@ -743,7 +743,12 @@ export class SceneTarget {
|
|
|
743
743
|
* `veilColor` and `veilAlpha` are positional defaults and every existing caller passes them
|
|
744
744
|
* by position.
|
|
745
745
|
*/
|
|
746
|
-
temporal?: {
|
|
746
|
+
temporal?: {
|
|
747
|
+
readonly reprojection: Float32Array;
|
|
748
|
+
readonly blend: number;
|
|
749
|
+
readonly periodStart: boolean;
|
|
750
|
+
readonly depthToViewZ: Float32Array;
|
|
751
|
+
},
|
|
747
752
|
): void {
|
|
748
753
|
const { gl } = this;
|
|
749
754
|
this.depthWanted =
|
|
@@ -883,6 +888,8 @@ export class SceneTarget {
|
|
|
883
888
|
this.width,
|
|
884
889
|
this.height,
|
|
885
890
|
temporal.blend,
|
|
891
|
+
temporal.periodStart,
|
|
892
|
+
temporal.depthToViewZ,
|
|
886
893
|
);
|
|
887
894
|
}
|
|
888
895
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* the next generation, and `npm run wgsl:check` fails the build when this is stale.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
export const TEMPORAL_RESOLVE_FRAG_WGSL = "struct Uniforms {\n uReprojection: mat4x4<f32>,\n uTexel: vec2<f32>,\n uHistoryBlend: f32,\n}\n\n@group(0) @binding(32) \nvar uScene_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uScene_s: sampler;\nvar<private> vUv_1: vec2<f32>;\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(34) \nvar uHistory_t: texture_2d<f32>;\n@group(0) @binding(35) \nvar uHistory_s: sampler;\nvar<private> fragColor: vec4<f32>;\n@group(0) @binding(36) \nvar uDepth_t: texture_2d<f32>;\n@group(0) @binding(37) \nvar uDepth_s: sampler;\n\nfn clipToNeighbourhood_u0028_vf3_u003b_vf3_u003b_vf3_u003b(history: ptr<function, vec3<f32>>, lo: ptr<function, vec3<f32>>, hi: ptr<function, vec3<f32>>) -> vec3<f32> {\n var centre: vec3<f32>;\n var extent: vec3<f32>;\n var offset: vec3<f32>;\n var ratios: vec3<f32>;\n var ratio: f32;\n\n let _e39 = (*lo);\n let _e40 = (*hi);\n centre = ((_e39 + _e40) * 0.5f);\n let _e43 = (*hi);\n let _e44 = (*lo);\n extent = ((_e43 - _e44) * 0.5f);\n let _e47 = (*history);\n let _e48 = centre;\n offset = (_e47 - _e48);\n let _e50 = offset;\n let _e52 = extent;\n ratios = (abs(_e50) / max(_e52, vec3<f32>(0.0000001f, 0.0000001f, 0.0000001f)));\n let _e56 = ratios[0u];\n let _e58 = ratios[1u];\n let _e60 = ratios[2u];\n ratio = max(_e56, max(_e58, _e60));\n let _e63 = ratio;\n if (_e63 <= 1f) {\n let _e65 = (*history);\n return _e65;\n }\n let _e66 = centre;\n let _e67 = offset;\n let _e68 = ratio;\n return (_e66 + (_e67 / vec3(_e68)));\n}\n\nfn historyCatmullRom_u0028_vf2_u003b(uv: ptr<function, vec2<f32>>) -> vec3<f32> {\n var size: vec2<f32>;\n var at: vec2<f32>;\n var base: vec2<f32>;\n var f: vec2<f32>;\n var w0_: vec2<f32>;\n var w1_: vec2<f32>;\n var w2_: vec2<f32>;\n var w3_: vec2<f32>;\n var w12_: vec2<f32>;\n var at0_: vec2<f32>;\n var at3_: vec2<f32>;\n var at12_: vec2<f32>;\n var sum: vec3<f32>;\n var weight: f32;\n\n let _e47 = unnamed.uTexel;\n size = (vec2(1f) / _e47);\n let _e50 = (*uv);\n let _e51 = size;\n at = (_e50 * _e51);\n let _e53 = at;\n base = (floor((_e53 - vec2(0.5f))) + vec2(0.5f));\n let _e59 = at;\n let _e60 = base;\n f = (_e59 - _e60);\n let _e62 = f;\n let _e63 = f;\n let _e64 = f;\n w0_ = (_e62 * (vec2(-0.5f) + (_e63 * (vec2(1f) - (_e64 * 0.5f)))));\n let _e72 = f;\n let _e73 = f;\n let _e75 = f;\n w1_ = (vec2(1f) + ((_e72 * _e73) * (vec2(-2.5f) + (_e75 * 1.5f))));\n let _e82 = f;\n let _e83 = f;\n let _e84 = f;\n w2_ = (_e82 * (vec2(0.5f) + (_e83 * (vec2(2f) - (_e84 * 1.5f)))));\n let _e92 = f;\n let _e93 = f;\n let _e95 = f;\n w3_ = ((_e92 * _e93) * (vec2(-0.5f) + (_e95 * 0.5f)));\n let _e100 = w1_;\n let _e101 = w2_;\n w12_ = (_e100 + _e101);\n let _e103 = base;\n let _e107 = unnamed.uTexel;\n at0_ = ((_e103 - vec2(1f)) * _e107);\n let _e109 = base;\n let _e113 = unnamed.uTexel;\n at3_ = ((_e109 + vec2(2f)) * _e113);\n let _e115 = base;\n let _e116 = w2_;\n let _e117 = w12_;\n let _e121 = unnamed.uTexel;\n at12_ = ((_e115 + (_e116 / _e117)) * _e121);\n let _e124 = at12_[0u];\n let _e126 = at0_[1u];\n let _e128 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e124, _e126), 0f);\n let _e131 = w12_[0u];\n let _e133 = w0_[1u];\n let _e137 = at0_[0u];\n let _e139 = at12_[1u];\n let _e141 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e137, _e139), 0f);\n let _e144 = w0_[0u];\n let _e146 = w12_[1u];\n let _e150 = at12_;\n let _e151 = textureSampleLevel(uHistory_t, uHistory_s, _e150, 0f);\n let _e154 = w12_[0u];\n let _e156 = w12_[1u];\n let _e161 = at3_[0u];\n let _e163 = at12_[1u];\n let _e165 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e161, _e163), 0f);\n let _e168 = w3_[0u];\n let _e170 = w12_[1u];\n let _e175 = at12_[0u];\n let _e177 = at3_[1u];\n let _e179 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e175, _e177), 0f);\n let _e182 = w12_[0u];\n let _e184 = w3_[1u];\n sum = (((((_e128.xyz * (_e131 * _e133)) + (_e141.xyz * (_e144 * _e146))) + (_e151.xyz * (_e154 * _e156))) + (_e165.xyz * (_e168 * _e170))) + (_e179.xyz * (_e182 * _e184)));\n let _e189 = w12_[0u];\n let _e191 = w0_[1u];\n let _e194 = w0_[0u];\n let _e196 = w12_[1u];\n let _e200 = w12_[0u];\n let _e202 = w12_[1u];\n let _e206 = w3_[0u];\n let _e208 = w12_[1u];\n let _e212 = w12_[0u];\n let _e214 = w3_[1u];\n weight = (((((_e189 * _e191) + (_e194 * _e196)) + (_e200 * _e202)) + (_e206 * _e208)) + (_e212 * _e214));\n let _e217 = sum;\n let _e218 = weight;\n return max((_e217 / vec3(_e218)), vec3<f32>(0f, 0f, 0f));\n}\n\nfn neighbourhood_u0028_vf3_u003b_vf3_u003b(lo_1: ptr<function, vec3<f32>>, hi_1: ptr<function, vec3<f32>>) {\n var y: i32;\n var x: i32;\n var c: vec3<f32>;\n\n (*lo_1) = vec3<f32>(1000000000f, 1000000000f, 1000000000f);\n (*hi_1) = vec3<f32>(-1000000000f, -1000000000f, -1000000000f);\n y = -1i;\n loop {\n let _e36 = y;\n if (_e36 <= 1i) {\n x = -1i;\n loop {\n let _e38 = x;\n if (_e38 <= 1i) {\n let _e40 = vUv_1;\n let _e41 = x;\n let _e43 = y;\n let _e47 = unnamed.uTexel;\n let _e50 = textureSampleLevel(uScene_t, uScene_s, (_e40 + (vec2<f32>(f32(_e41), f32(_e43)) * _e47)), 0f);\n c = _e50.xyz;\n let _e52 = (*lo_1);\n let _e53 = c;\n (*lo_1) = min(_e52, _e53);\n let _e55 = (*hi_1);\n let _e56 = c;\n (*hi_1) = max(_e55, _e56);\n continue;\n } else {\n break;\n }\n continuing {\n let _e58 = x;\n x = (_e58 + 1i);\n }\n }\n continue;\n } else {\n break;\n }\n continuing {\n let _e60 = y;\n y = (_e60 + 1i);\n }\n }\n return;\n}\n\nfn main_1() {\n var current: vec3<f32>;\n var depth: f32;\n var clip: vec4<f32>;\n var previous: vec4<f32>;\n var wasUv: vec2<f32>;\n var lo_2: vec3<f32>;\n var hi_2: vec3<f32>;\n var param: vec3<f32>;\n var param_1: vec3<f32>;\n var history_1: vec3<f32>;\n var param_2: vec2<f32>;\n var bounded: vec3<f32>;\n var param_3: vec3<f32>;\n var param_4: vec3<f32>;\n var param_5: vec3<f32>;\n var phi_440_: bool;\n var phi_447_: bool;\n var phi_454_: bool;\n\n let _e46 = vUv_1;\n let _e47 = textureSampleLevel(uScene_t, uScene_s, _e46, 0f);\n current = _e47.xyz;\n let _e50 = unnamed.uHistoryBlend;\n if (_e50 <= 0f) {\n let _e52 = current;\n fragColor = vec4<f32>(_e52.x, _e52.y, _e52.z, 1f);\n return;\n }\n let _e57 = vUv_1;\n let _e58 = textureSampleLevel(uDepth_t, uDepth_s, _e57, 0f);\n depth = _e58.x;\n let _e60 = vUv_1;\n let _e63 = ((_e60 * 2f) - vec2(1f));\n let _e64 = depth;\n clip = vec4<f32>(_e63.x, _e63.y, (1f - (_e64 * 2f)), 1f);\n let _e71 = unnamed.uReprojection;\n let _e72 = clip;\n previous = (_e71 * _e72);\n let _e75 = previous[3u];\n if (_e75 <= 0f) {\n let _e77 = current;\n fragColor = vec4<f32>(_e77.x, _e77.y, _e77.z, 1f);\n return;\n }\n let _e82 = previous;\n let _e85 = previous[3u];\n wasUv = (((_e82.xy / vec2(_e85)) * 0.5f) + vec2(0.5f));\n let _e92 = wasUv[0u];\n let _e93 = (_e92 < 0f);\n phi_440_ = _e93;\n if !(_e93) {\n let _e96 = wasUv[0u];\n phi_440_ = (_e96 > 1f);\n }\n let _e99 = phi_440_;\n phi_447_ = _e99;\n if !(_e99) {\n let _e102 = wasUv[1u];\n phi_447_ = (_e102 < 0f);\n }\n let _e105 = phi_447_;\n phi_454_ = _e105;\n if !(_e105) {\n let _e108 = wasUv[1u];\n phi_454_ = (_e108 > 1f);\n }\n let _e111 = phi_454_;\n if _e111 {\n let _e112 = current;\n fragColor = vec4<f32>(_e112.x, _e112.y, _e112.z, 1f);\n return;\n }\n neighbourhood_u0028_vf3_u003b_vf3_u003b((¶m), (¶m_1));\n let _e117 = param;\n lo_2 = _e117;\n let _e118 = param_1;\n hi_2 = _e118;\n let _e119 = wasUv;\n param_2 = _e119;\n let _e120 = historyCatmullRom_u0028_vf2_u003b((¶m_2));\n history_1 = _e120;\n let _e121 = history_1;\n param_3 = _e121;\n let _e122 = lo_2;\n param_4 = _e122;\n let _e123 = hi_2;\n param_5 = _e123;\n let _e124 = clipToNeighbourhood_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_3), (¶m_4), (¶m_5));\n bounded = _e124;\n let _e125 = current;\n let _e126 = bounded;\n let _e128 = unnamed.uHistoryBlend;\n let _e130 = mix(_e125, _e126, vec3(_e128));\n fragColor = vec4<f32>(_e130.x, _e130.y, _e130.z, 1f);\n return;\n}\n\n@fragment \nfn main(@location(0) vUv: vec2<f32>) -> @location(0) vec4<f32> {\n vUv_1 = vUv;\n main_1();\n let _e3 = fragColor;\n return _e3;\n}\n";
|
|
8
|
+
export const TEMPORAL_RESOLVE_FRAG_WGSL = "struct Uniforms {\n uDepthToViewZ: vec4<f32>,\n uAntiFlicker: f32,\n uReprojection: mat4x4<f32>,\n uTexel: vec2<f32>,\n uPeriodStart: f32,\n uHistoryBlend: f32,\n}\n\nstruct FragmentOutput {\n @location(0) member: vec4<f32>,\n @location(1) member_1: vec4<f32>,\n @location(2) member_2: vec4<f32>,\n}\n\n@group(0) @binding(1) \nvar<uniform> unnamed: Uniforms;\n@group(0) @binding(32) \nvar uScene_t: texture_2d<f32>;\n@group(0) @binding(33) \nvar uScene_s: sampler;\nvar<private> vUv_1: vec2<f32>;\n@group(0) @binding(34) \nvar uHistory_t: texture_2d<f32>;\n@group(0) @binding(35) \nvar uHistory_s: sampler;\nvar<private> fragColor: vec4<f32>;\nvar<private> flickerOut: vec4<f32>;\nvar<private> flickerMotionOut: vec4<f32>;\n@group(0) @binding(40) \nvar uDepth_t: texture_2d<f32>;\n@group(0) @binding(41) \nvar uDepth_s: sampler;\n@group(0) @binding(36) \nvar uFlicker_t: texture_2d<f32>;\n@group(0) @binding(38) \nvar uFlickerMotion_t: texture_2d<f32>;\n@group(0) @binding(37) \nvar uFlicker_s: sampler;\n@group(0) @binding(39) \nvar uFlickerMotion_s: sampler;\n\nfn repeats_u0028_f1_u003b_f1_u003b(mean: ptr<function, f32>, previous: ptr<function, f32>) -> f32 {\n var apart: f32;\n\n let _e63 = (*mean);\n let _e64 = (*previous);\n let _e67 = (*mean);\n let _e68 = (*previous);\n apart = (abs((_e63 - _e64)) / max(max(_e67, _e68), 0.003921569f));\n let _e72 = apart;\n return (1f - smoothstep(0.05f, 0.1f, _e72));\n}\n\nfn clipToNeighbourhood_u0028_vf3_u003b_vf3_u003b_vf3_u003b(history: ptr<function, vec3<f32>>, lo: ptr<function, vec3<f32>>, hi: ptr<function, vec3<f32>>) -> vec3<f32> {\n var centre: vec3<f32>;\n var extent: vec3<f32>;\n var offset: vec3<f32>;\n var ratios: vec3<f32>;\n var ratio: f32;\n\n let _e68 = (*lo);\n let _e69 = (*hi);\n centre = ((_e68 + _e69) * 0.5f);\n let _e72 = (*hi);\n let _e73 = (*lo);\n extent = ((_e72 - _e73) * 0.5f);\n let _e76 = (*history);\n let _e77 = centre;\n offset = (_e76 - _e77);\n let _e79 = offset;\n let _e81 = extent;\n ratios = (abs(_e79) / max(_e81, vec3<f32>(0.0000001f, 0.0000001f, 0.0000001f)));\n let _e85 = ratios[0u];\n let _e87 = ratios[1u];\n let _e89 = ratios[2u];\n ratio = max(_e85, max(_e87, _e89));\n let _e92 = ratio;\n if (_e92 <= 1f) {\n let _e94 = (*history);\n return _e94;\n }\n let _e95 = centre;\n let _e96 = offset;\n let _e97 = ratio;\n return (_e95 + (_e96 / vec3(_e97)));\n}\n\nfn luma_u0028_vf3_u003b(c: ptr<function, vec3<f32>>) -> f32 {\n let _e61 = (*c);\n return dot(_e61, vec3<f32>(0.2126f, 0.7152f, 0.0722f));\n}\n\nfn historyCatmullRom_u0028_vf2_u003b(uv: ptr<function, vec2<f32>>) -> vec3<f32> {\n var size: vec2<f32>;\n var at: vec2<f32>;\n var base: vec2<f32>;\n var f: vec2<f32>;\n var w0_: vec2<f32>;\n var w1_: vec2<f32>;\n var w2_: vec2<f32>;\n var w3_: vec2<f32>;\n var w12_: vec2<f32>;\n var at0_: vec2<f32>;\n var at3_: vec2<f32>;\n var at12_: vec2<f32>;\n var sum: vec3<f32>;\n var weight: f32;\n\n let _e76 = unnamed.uTexel;\n size = (vec2(1f) / _e76);\n let _e79 = (*uv);\n let _e80 = size;\n at = (_e79 * _e80);\n let _e82 = at;\n base = (floor((_e82 - vec2(0.5f))) + vec2(0.5f));\n let _e88 = at;\n let _e89 = base;\n f = (_e88 - _e89);\n let _e91 = f;\n let _e92 = f;\n let _e93 = f;\n w0_ = (_e91 * (vec2(-0.5f) + (_e92 * (vec2(1f) - (_e93 * 0.5f)))));\n let _e101 = f;\n let _e102 = f;\n let _e104 = f;\n w1_ = (vec2(1f) + ((_e101 * _e102) * (vec2(-2.5f) + (_e104 * 1.5f))));\n let _e111 = f;\n let _e112 = f;\n let _e113 = f;\n w2_ = (_e111 * (vec2(0.5f) + (_e112 * (vec2(2f) - (_e113 * 1.5f)))));\n let _e121 = f;\n let _e122 = f;\n let _e124 = f;\n w3_ = ((_e121 * _e122) * (vec2(-0.5f) + (_e124 * 0.5f)));\n let _e129 = w1_;\n let _e130 = w2_;\n w12_ = (_e129 + _e130);\n let _e132 = base;\n let _e136 = unnamed.uTexel;\n at0_ = ((_e132 - vec2(1f)) * _e136);\n let _e138 = base;\n let _e142 = unnamed.uTexel;\n at3_ = ((_e138 + vec2(2f)) * _e142);\n let _e144 = base;\n let _e145 = w2_;\n let _e146 = w12_;\n let _e150 = unnamed.uTexel;\n at12_ = ((_e144 + (_e145 / _e146)) * _e150);\n let _e153 = at12_[0u];\n let _e155 = at0_[1u];\n let _e157 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e153, _e155), 0f);\n let _e160 = w12_[0u];\n let _e162 = w0_[1u];\n let _e166 = at0_[0u];\n let _e168 = at12_[1u];\n let _e170 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e166, _e168), 0f);\n let _e173 = w0_[0u];\n let _e175 = w12_[1u];\n let _e179 = at12_;\n let _e180 = textureSampleLevel(uHistory_t, uHistory_s, _e179, 0f);\n let _e183 = w12_[0u];\n let _e185 = w12_[1u];\n let _e190 = at3_[0u];\n let _e192 = at12_[1u];\n let _e194 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e190, _e192), 0f);\n let _e197 = w3_[0u];\n let _e199 = w12_[1u];\n let _e204 = at12_[0u];\n let _e206 = at3_[1u];\n let _e208 = textureSampleLevel(uHistory_t, uHistory_s, vec2<f32>(_e204, _e206), 0f);\n let _e211 = w12_[0u];\n let _e213 = w3_[1u];\n sum = (((((_e157.xyz * (_e160 * _e162)) + (_e170.xyz * (_e173 * _e175))) + (_e180.xyz * (_e183 * _e185))) + (_e194.xyz * (_e197 * _e199))) + (_e208.xyz * (_e211 * _e213)));\n let _e218 = w12_[0u];\n let _e220 = w0_[1u];\n let _e223 = w0_[0u];\n let _e225 = w12_[1u];\n let _e229 = w12_[0u];\n let _e231 = w12_[1u];\n let _e235 = w3_[0u];\n let _e237 = w12_[1u];\n let _e241 = w12_[0u];\n let _e243 = w3_[1u];\n weight = (((((_e218 * _e220) + (_e223 * _e225)) + (_e229 * _e231)) + (_e235 * _e237)) + (_e241 * _e243));\n let _e246 = sum;\n let _e247 = weight;\n return max((_e246 / vec3(_e247)), vec3<f32>(0f, 0f, 0f));\n}\n\nfn neighbourhood_u0028_vf3_u003b_vf3_u003b(lo_1: ptr<function, vec3<f32>>, hi_1: ptr<function, vec3<f32>>) {\n var y: i32;\n var x: i32;\n var c_1: vec3<f32>;\n\n (*lo_1) = vec3<f32>(1000000000f, 1000000000f, 1000000000f);\n (*hi_1) = vec3<f32>(-1000000000f, -1000000000f, -1000000000f);\n y = -1i;\n loop {\n let _e65 = y;\n if (_e65 <= 1i) {\n x = -1i;\n loop {\n let _e67 = x;\n if (_e67 <= 1i) {\n let _e69 = vUv_1;\n let _e70 = x;\n let _e72 = y;\n let _e76 = unnamed.uTexel;\n let _e79 = textureSampleLevel(uScene_t, uScene_s, (_e69 + (vec2<f32>(f32(_e70), f32(_e72)) * _e76)), 0f);\n c_1 = _e79.xyz;\n let _e81 = (*lo_1);\n let _e82 = c_1;\n (*lo_1) = min(_e81, _e82);\n let _e84 = (*hi_1);\n let _e85 = c_1;\n (*hi_1) = max(_e84, _e85);\n continue;\n } else {\n break;\n }\n continuing {\n let _e87 = x;\n x = (_e87 + 1i);\n }\n }\n continue;\n } else {\n break;\n }\n continuing {\n let _e89 = y;\n y = (_e89 + 1i);\n }\n }\n return;\n}\n\nfn viewDepthOf_u0028_f1_u003b(depth: ptr<function, f32>) -> f32 {\n var z: f32;\n\n let _e62 = (*depth);\n z = (1f - (_e62 * 2f));\n let _e67 = unnamed.uDepthToViewZ[0u];\n let _e68 = z;\n let _e72 = unnamed.uDepthToViewZ[1u];\n let _e77 = unnamed.uDepthToViewZ[2u];\n let _e78 = z;\n let _e82 = unnamed.uDepthToViewZ[3u];\n return (-(((_e67 * _e68) + _e72)) / ((_e77 * _e78) + _e82));\n}\n\nfn freshRecord_u0028_vf3_u003b(current: ptr<function, vec3<f32>>) -> vec4<f32> {\n var seen: f32;\n var param: vec3<f32>;\n\n let _e63 = (*current);\n param = _e63;\n let _e64 = luma_u0028_vf3_u003b((¶m));\n seen = _e64;\n let _e65 = seen;\n let _e67 = seen;\n return vec4<f32>(0f, (_e65 * 0.125f), _e67, 0f);\n}\n\nfn main_1() {\n var current_1: vec3<f32>;\n var param_1: vec3<f32>;\n var nearestAt: vec2<f32>;\n var depth_1: f32;\n var metres: f32;\n var param_2: f32;\n var y_1: i32;\n var x_1: i32;\n var at_1: vec2<f32>;\n var tap: f32;\n var tapMetres: f32;\n var param_3: f32;\n var clip: vec4<f32>;\n var previous_1: vec4<f32>;\n var param_4: vec3<f32>;\n var wasUv: vec2<f32>;\n var param_5: vec3<f32>;\n var lo_2: vec3<f32>;\n var hi_2: vec3<f32>;\n var param_6: vec3<f32>;\n var param_7: vec3<f32>;\n var history_1: vec3<f32>;\n var param_8: vec2<f32>;\n var size_1: vec2<i32>;\n var was: vec2<i32>;\n var nearest: f32;\n var n: i32;\n var at_2: vec2<i32>;\n var local: vec2<i32>;\n var local_1: vec2<i32>;\n var local_2: vec2<i32>;\n var stood: f32;\n var motionThere: vec4<f32>;\n var missedAll: bool;\n var same: bool;\n var swingOut: f32;\n var local_3: f32;\n var seen_1: f32;\n var param_9: vec3<f32>;\n var held: vec4<f32>;\n var local_4: vec4<f32>;\n var param_10: vec3<f32>;\n var still: f32;\n var apart_1: f32;\n var reach: f32;\n var within: bool;\n var proven: bool;\n var widen: f32;\n var local_5: f32;\n var blend: f32;\n var local_6: f32;\n var bounded: vec3<f32>;\n var param_11: vec3<f32>;\n var param_12: vec3<f32>;\n var param_13: vec3<f32>;\n var sum_1: f32;\n var mean_1: f32;\n var repeated: f32;\n var local_7: f32;\n var param_14: f32;\n var param_15: f32;\n var local_8: f32;\n var phi_589_: bool;\n var phi_596_: bool;\n var phi_603_: bool;\n var phi_740_: bool;\n\n let _e122 = vUv_1;\n let _e123 = textureSampleLevel(uScene_t, uScene_s, _e122, 0f);\n current_1 = _e123.xyz;\n let _e126 = unnamed.uHistoryBlend;\n if (_e126 <= 0f) {\n let _e128 = current_1;\n fragColor = vec4<f32>(_e128.x, _e128.y, _e128.z, 1f);\n let _e133 = current_1;\n param_1 = _e133;\n let _e134 = freshRecord_u0028_vf3_u003b((¶m_1));\n flickerOut = _e134;\n flickerMotionOut = vec4<f32>(0f, 0f, 0f, 0f);\n return;\n }\n let _e135 = vUv_1;\n nearestAt = _e135;\n let _e136 = vUv_1;\n let _e137 = textureSampleLevel(uDepth_t, uDepth_s, _e136, 0f);\n depth_1 = _e137.x;\n let _e139 = depth_1;\n param_2 = _e139;\n let _e140 = viewDepthOf_u0028_f1_u003b((¶m_2));\n metres = _e140;\n y_1 = -1i;\n loop {\n let _e141 = y_1;\n if (_e141 <= 1i) {\n x_1 = -1i;\n loop {\n let _e143 = x_1;\n if (_e143 <= 1i) {\n let _e145 = vUv_1;\n let _e146 = x_1;\n let _e148 = y_1;\n let _e152 = unnamed.uTexel;\n at_1 = (_e145 + (vec2<f32>(f32(_e146), f32(_e148)) * _e152));\n let _e155 = at_1;\n let _e156 = textureSampleLevel(uDepth_t, uDepth_s, _e155, 0f);\n tap = _e156.x;\n let _e158 = tap;\n param_3 = _e158;\n let _e159 = viewDepthOf_u0028_f1_u003b((¶m_3));\n tapMetres = _e159;\n let _e160 = tapMetres;\n let _e161 = metres;\n if (_e160 < _e161) {\n let _e163 = tapMetres;\n metres = _e163;\n let _e164 = tap;\n depth_1 = _e164;\n let _e165 = at_1;\n nearestAt = _e165;\n }\n continue;\n } else {\n break;\n }\n continuing {\n let _e166 = x_1;\n x_1 = (_e166 + 1i);\n }\n }\n continue;\n } else {\n break;\n }\n continuing {\n let _e168 = y_1;\n y_1 = (_e168 + 1i);\n }\n }\n let _e170 = nearestAt;\n let _e173 = ((_e170 * 2f) - vec2(1f));\n let _e174 = depth_1;\n clip = vec4<f32>(_e173.x, _e173.y, (1f - (_e174 * 2f)), 1f);\n let _e181 = unnamed.uReprojection;\n let _e182 = clip;\n previous_1 = (_e181 * _e182);\n let _e185 = previous_1[3u];\n if (_e185 <= 0f) {\n let _e187 = current_1;\n fragColor = vec4<f32>(_e187.x, _e187.y, _e187.z, 1f);\n let _e192 = current_1;\n param_4 = _e192;\n let _e193 = freshRecord_u0028_vf3_u003b((¶m_4));\n flickerOut = _e193;\n let _e194 = metres;\n flickerMotionOut = vec4<f32>(_e194, 0f, 0f, 0f);\n return;\n }\n let _e196 = vUv_1;\n let _e197 = previous_1;\n let _e200 = previous_1[3u];\n let _e206 = nearestAt;\n wasUv = (_e196 + ((((_e197.xy / vec2(_e200)) * 0.5f) + vec2(0.5f)) - _e206));\n let _e210 = wasUv[0u];\n let _e211 = (_e210 < 0f);\n phi_589_ = _e211;\n if !(_e211) {\n let _e214 = wasUv[0u];\n phi_589_ = (_e214 > 1f);\n }\n let _e217 = phi_589_;\n phi_596_ = _e217;\n if !(_e217) {\n let _e220 = wasUv[1u];\n phi_596_ = (_e220 < 0f);\n }\n let _e223 = phi_596_;\n phi_603_ = _e223;\n if !(_e223) {\n let _e226 = wasUv[1u];\n phi_603_ = (_e226 > 1f);\n }\n let _e229 = phi_603_;\n if _e229 {\n let _e230 = current_1;\n fragColor = vec4<f32>(_e230.x, _e230.y, _e230.z, 1f);\n let _e235 = current_1;\n param_5 = _e235;\n let _e236 = freshRecord_u0028_vf3_u003b((¶m_5));\n flickerOut = _e236;\n let _e237 = metres;\n flickerMotionOut = vec4<f32>(_e237, 0f, 0f, 0f);\n return;\n }\n neighbourhood_u0028_vf3_u003b_vf3_u003b((¶m_6), (¶m_7));\n let _e239 = param_6;\n lo_2 = _e239;\n let _e240 = param_7;\n hi_2 = _e240;\n let _e241 = wasUv;\n param_8 = _e241;\n let _e242 = historyCatmullRom_u0028_vf2_u003b((¶m_8));\n history_1 = _e242;\n let _e243 = textureDimensions(uFlicker_t, 0i);\n size_1 = vec2<i32>(_e243);\n let _e245 = wasUv;\n let _e246 = size_1;\n let _e250 = size_1;\n was = clamp(vec2<i32>((_e245 * vec2<f32>(_e246))), vec2<i32>(0i, 0i), (_e250 - vec2(1i)));\n nearest = 1000000000f;\n n = 0i;\n loop {\n let _e254 = n;\n if (_e254 < 5i) {\n let _e256 = was;\n let _e257 = n;\n if (_e257 == 1i) {\n local = vec2<i32>(1i, 0i);\n } else {\n let _e259 = n;\n if (_e259 == 2i) {\n local_1 = vec2<i32>(-1i, 0i);\n } else {\n let _e261 = n;\n if (_e261 == 3i) {\n local_2 = vec2<i32>(0i, 1i);\n } else {\n let _e263 = n;\n local_2 = select(vec2<i32>(0i, 0i), vec2<i32>(0i, -1i), vec2((_e263 == 4i)));\n }\n let _e267 = local_2;\n local_1 = _e267;\n }\n let _e268 = local_1;\n local = _e268;\n }\n let _e269 = local;\n at_2 = (_e256 + _e269);\n let _e271 = at_2;\n let _e272 = size_1;\n let _e276 = textureLoad(uFlickerMotion_t, clamp(_e271, vec2<i32>(0i, 0i), (_e272 - vec2(1i))), 0i);\n stood = _e276.x;\n let _e278 = stood;\n if (_e278 > 0f) {\n let _e280 = nearest;\n let _e281 = stood;\n let _e283 = previous_1[3u];\n nearest = min(_e280, abs((_e281 - _e283)));\n }\n continue;\n } else {\n break;\n }\n continuing {\n let _e287 = n;\n n = (_e287 + 1i);\n }\n }\n let _e289 = was;\n let _e290 = textureLoad(uFlickerMotion_t, _e289, 0i);\n motionThere = _e290;\n let _e291 = nearest;\n missedAll = (_e291 > 100000000f);\n let _e294 = unnamed.uAntiFlicker;\n let _e296 = missedAll;\n let _e298 = ((_e294 > 0.5f) && !(_e296));\n phi_740_ = _e298;\n if _e298 {\n let _e299 = nearest;\n let _e301 = motionThere[1u];\n let _e304 = previous_1[3u];\n phi_740_ = (_e299 <= ((6f * _e301) + (0.02f * _e304)));\n }\n let _e309 = phi_740_;\n same = _e309;\n let _e310 = missedAll;\n if _e310 {\n local_3 = 0f;\n } else {\n let _e312 = motionThere[1u];\n let _e313 = nearest;\n let _e315 = motionThere[1u];\n local_3 = (_e312 + ((_e313 - _e315) * 0.125f));\n }\n let _e319 = local_3;\n swingOut = _e319;\n let _e320 = current_1;\n param_9 = _e320;\n let _e321 = luma_u0028_vf3_u003b((¶m_9));\n seen_1 = _e321;\n let _e322 = same;\n if _e322 {\n let _e323 = was;\n let _e324 = textureLoad(uFlicker_t, _e323, 0i);\n local_4 = _e324;\n } else {\n let _e325 = current_1;\n param_10 = _e325;\n let _e326 = freshRecord_u0028_vf3_u003b((¶m_10));\n local_4 = _e326;\n }\n let _e327 = local_4;\n held = _e327;\n let _e328 = wasUv;\n let _e329 = vUv_1;\n let _e332 = unnamed.uTexel;\n still = (1f - smoothstep(0.01f, 0.05f, length(((_e328 - _e329) / _e332))));\n let _e337 = seen_1;\n let _e339 = held[2u];\n apart_1 = abs((_e337 - _e339));\n let _e343 = held[0u];\n reach = ((6f * _e343) + 0.003921569f);\n let _e346 = apart_1;\n let _e347 = reach;\n within = (_e346 <= _e347);\n let _e350 = held[3u];\n let _e352 = within;\n proven = ((_e350 > 0.75f) && _e352);\n let _e354 = proven;\n if _e354 {\n let _e356 = held[0u];\n let _e358 = still;\n local_5 = ((6f * _e356) * _e358);\n } else {\n local_5 = 0f;\n }\n let _e360 = local_5;\n widen = _e360;\n let _e361 = proven;\n if _e361 {\n let _e363 = unnamed.uHistoryBlend;\n let _e364 = still;\n local_6 = mix(_e363, 0.97f, _e364);\n } else {\n let _e367 = unnamed.uHistoryBlend;\n local_6 = _e367;\n }\n let _e368 = local_6;\n blend = _e368;\n let _e369 = lo_2;\n let _e370 = widen;\n let _e373 = hi_2;\n let _e374 = widen;\n let _e377 = history_1;\n param_11 = _e377;\n param_12 = (_e369 - vec3(_e370));\n param_13 = (_e373 + vec3(_e374));\n let _e378 = clipToNeighbourhood_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_11), (¶m_12), (¶m_13));\n bounded = _e378;\n let _e380 = held[1u];\n sum_1 = _e380;\n let _e382 = held[2u];\n mean_1 = _e382;\n let _e383 = within;\n if _e383 {\n let _e385 = held[3u];\n local_7 = _e385;\n } else {\n local_7 = 0f;\n }\n let _e386 = local_7;\n repeated = _e386;\n let _e388 = unnamed.uPeriodStart;\n if (_e388 > 0.5f) {\n let _e390 = sum_1;\n param_14 = _e390;\n let _e391 = mean_1;\n param_15 = _e391;\n let _e392 = repeats_u0028_f1_u003b_f1_u003b((¶m_14), (¶m_15));\n if (_e392 > 0.5f) {\n let _e394 = repeated;\n local_8 = min(1f, (_e394 + 0.5f));\n } else {\n local_8 = 0f;\n }\n let _e397 = local_8;\n repeated = _e397;\n let _e398 = sum_1;\n mean_1 = _e398;\n sum_1 = 0f;\n }\n let _e400 = held[0u];\n let _e401 = apart_1;\n let _e403 = held[0u];\n let _e407 = sum_1;\n let _e408 = seen_1;\n let _e411 = mean_1;\n let _e412 = repeated;\n let _e413 = still;\n flickerOut = vec4<f32>((_e400 + ((_e401 - _e403) * 0.125f)), (_e407 + (_e408 * 0.125f)), _e411, (_e412 * _e413));\n let _e416 = metres;\n let _e417 = swingOut;\n flickerMotionOut = vec4<f32>(_e416, _e417, 0f, 0f);\n let _e419 = current_1;\n let _e420 = bounded;\n let _e421 = blend;\n let _e423 = mix(_e419, _e420, vec3(_e421));\n fragColor = vec4<f32>(_e423.x, _e423.y, _e423.z, 1f);\n return;\n}\n\n@fragment \nfn main(@location(0) vUv: vec2<f32>) -> FragmentOutput {\n vUv_1 = vUv;\n main_1();\n let _e5 = fragColor;\n let _e6 = flickerOut;\n let _e7 = flickerMotionOut;\n return FragmentOutput(_e5, _e6, _e7);\n}\n";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* What the transform assigned, so the renderer binds the same numbers.
|
|
@@ -15,20 +15,35 @@ export const TEMPORAL_RESOLVE_FRAG_WGSL = "struct Uniforms {\n uReprojection:
|
|
|
15
15
|
export const TEMPORALRESOLVE_BINDINGS = {
|
|
16
16
|
"TEMPORAL_RESOLVE_FRAG": {
|
|
17
17
|
"uniforms": 1,
|
|
18
|
-
"uniformSize":
|
|
18
|
+
"uniformSize": 112,
|
|
19
19
|
"fields": {
|
|
20
|
-
"
|
|
20
|
+
"uDepthToViewZ": {
|
|
21
21
|
"offset": 0,
|
|
22
|
+
"size": 16,
|
|
23
|
+
"type": "vec4"
|
|
24
|
+
},
|
|
25
|
+
"uAntiFlicker": {
|
|
26
|
+
"offset": 16,
|
|
27
|
+
"size": 4,
|
|
28
|
+
"type": "float"
|
|
29
|
+
},
|
|
30
|
+
"uReprojection": {
|
|
31
|
+
"offset": 32,
|
|
22
32
|
"size": 64,
|
|
23
33
|
"type": "mat4"
|
|
24
34
|
},
|
|
25
35
|
"uTexel": {
|
|
26
|
-
"offset":
|
|
36
|
+
"offset": 96,
|
|
27
37
|
"size": 8,
|
|
28
38
|
"type": "vec2"
|
|
29
39
|
},
|
|
40
|
+
"uPeriodStart": {
|
|
41
|
+
"offset": 104,
|
|
42
|
+
"size": 4,
|
|
43
|
+
"type": "float"
|
|
44
|
+
},
|
|
30
45
|
"uHistoryBlend": {
|
|
31
|
-
"offset":
|
|
46
|
+
"offset": 108,
|
|
32
47
|
"size": 4,
|
|
33
48
|
"type": "float"
|
|
34
49
|
}
|
|
@@ -44,10 +59,20 @@ export const TEMPORALRESOLVE_BINDINGS = {
|
|
|
44
59
|
"sampler": 35,
|
|
45
60
|
"type": "sampler2D"
|
|
46
61
|
},
|
|
47
|
-
"
|
|
62
|
+
"uFlicker": {
|
|
48
63
|
"texture": 36,
|
|
49
64
|
"sampler": 37,
|
|
50
65
|
"type": "sampler2D"
|
|
66
|
+
},
|
|
67
|
+
"uFlickerMotion": {
|
|
68
|
+
"texture": 38,
|
|
69
|
+
"sampler": 39,
|
|
70
|
+
"type": "sampler2D"
|
|
71
|
+
},
|
|
72
|
+
"uDepth": {
|
|
73
|
+
"texture": 40,
|
|
74
|
+
"sampler": 41,
|
|
75
|
+
"type": "sampler2D"
|
|
51
76
|
}
|
|
52
77
|
}
|
|
53
78
|
}
|