@vitreajs/vitrea 0.14.0 → 0.16.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/dist/{chunk-WM2DV3ZD.js → chunk-IOTISK2R.js} +2 -2
- package/dist/{chunk-WM2DV3ZD.js.map → chunk-IOTISK2R.js.map} +1 -1
- package/dist/{dist-PT4PUS4K.js → dist-C43H3RKY.js} +395 -78
- package/dist/dist-C43H3RKY.js.map +1 -0
- package/dist/index.d.ts +90 -18
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/dist-PT4PUS4K.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_GROUP_UNION, LowPassHysteresisDriver, WGSL_RSUPN, WGSL_RSUP, resolveFromChannels, resolveConcentric, governorFieldParams, fieldParams, DEFAULT_MOTION_PROFILE } from './chunk-
|
|
1
|
+
import { DEFAULT_GROUP_UNION, LowPassHysteresisDriver, WGSL_RSUPN, WGSL_RSUP, resolveFromChannels, resolveConcentric, governorFieldParams, fieldParams, DEFAULT_MOTION_PROFILE } from './chunk-IOTISK2R.js';
|
|
2
2
|
|
|
3
3
|
// ../renderer-webgpu/dist/wgsl/analysis.js
|
|
4
4
|
var ANALYSIS_WORKGROUP = 64;
|
|
@@ -1212,6 +1212,12 @@ function withMaterialOverrides(base, patch) {
|
|
|
1212
1212
|
tintShadeDark: patch.tintShadeDark ?? base.tintShadeDark,
|
|
1213
1213
|
tintShadeLight: patch.tintShadeLight ?? base.tintShadeLight,
|
|
1214
1214
|
tintShadeStrength: patch.tintShadeStrength ?? base.tintShadeStrength,
|
|
1215
|
+
...(patch.tintChromaScale ?? base.tintChromaScale ?? 1) === 1 ? {} : {
|
|
1216
|
+
tintChromaScale: patch.tintChromaScale ?? base.tintChromaScale
|
|
1217
|
+
},
|
|
1218
|
+
...(patch.tintShadeCollapseRetention ?? base.tintShadeCollapseRetention ?? 0) === 0 ? {} : {
|
|
1219
|
+
tintShadeCollapseRetention: patch.tintShadeCollapseRetention ?? base.tintShadeCollapseRetention
|
|
1220
|
+
},
|
|
1215
1221
|
backdropToneMax: patch.backdropToneMax ?? base.backdropToneMax,
|
|
1216
1222
|
backdropToneLow: patch.backdropToneLow ?? base.backdropToneLow,
|
|
1217
1223
|
backdropToneHigh: patch.backdropToneHigh ?? base.backdropToneHigh,
|
|
@@ -1300,7 +1306,15 @@ function tintShade(materialLuminance, grip, profile = DEFAULT_MATERIAL_PROFILE)
|
|
|
1300
1306
|
}
|
|
1301
1307
|
function tintShadeLayer(seed, materialLuminance, grip, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
1302
1308
|
const shade = tintShade(materialLuminance, grip, profile);
|
|
1303
|
-
|
|
1309
|
+
const chroma = Math.min(1, Math.max(0, profile.tintChromaScale ?? 1));
|
|
1310
|
+
if (chroma === 1)
|
|
1311
|
+
return [seed[0] * shade, seed[1] * shade, seed[2] * shade];
|
|
1312
|
+
const neutral = Math.max(...seed);
|
|
1313
|
+
return [
|
|
1314
|
+
(neutral + (seed[0] - neutral) * chroma) * shade,
|
|
1315
|
+
(neutral + (seed[1] - neutral) * chroma) * shade,
|
|
1316
|
+
(neutral + (seed[2] - neutral) * chroma) * shade
|
|
1317
|
+
];
|
|
1304
1318
|
}
|
|
1305
1319
|
function tintedMaterialColour(material, tint, grip, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
1306
1320
|
if (tint === void 0 || tint.strength <= 0)
|
|
@@ -2498,9 +2512,17 @@ var poolKey = {
|
|
|
2498
2512
|
backdropHeavy: (sourceId) => `backdrop:${sourceId}:heavy`,
|
|
2499
2513
|
backdropHeavyScratch: (sourceId) => `backdrop:${sourceId}:heavy-scratch`,
|
|
2500
2514
|
backdropUpload: (sourceId) => `backdrop:${sourceId}:upload`,
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2515
|
+
/*
|
|
2516
|
+
* The four field targets. Their key is a group's RESOURCE identity — the id
|
|
2517
|
+
* qualified by the plane it draws on (`groupResourceId`) — and not the group
|
|
2518
|
+
* id, because one group can draw on two planes in one frame and each plane's
|
|
2519
|
+
* field is its own size.
|
|
2520
|
+
*/
|
|
2521
|
+
groupField: (resourceId) => `group:${resourceId}:field`,
|
|
2522
|
+
groupAux: (resourceId) => `group:${resourceId}:aux`,
|
|
2523
|
+
groupAux2: (resourceId) => `group:${resourceId}:aux2`,
|
|
2524
|
+
/** The surface's presence per pixel (W27d) — the field pass's fourth target. */
|
|
2525
|
+
groupPresence: (resourceId) => `group:${resourceId}:presence`
|
|
2504
2526
|
};
|
|
2505
2527
|
|
|
2506
2528
|
// ../renderer-webgpu/dist/gpu-context.js
|
|
@@ -2589,12 +2611,32 @@ var IDLE_CHANNELS = {
|
|
|
2589
2611
|
glow: 0,
|
|
2590
2612
|
sweep: 0,
|
|
2591
2613
|
shimmer: 0,
|
|
2592
|
-
lensStrength: 1
|
|
2614
|
+
lensStrength: 1,
|
|
2615
|
+
// 1 rather than 0, for `lensStrength`'s reason: a surface nobody is driving is
|
|
2616
|
+
// a surface that is fully there, and 0 is a distinct claim a driver can make.
|
|
2617
|
+
materialization: 1
|
|
2593
2618
|
};
|
|
2594
2619
|
|
|
2595
2620
|
// ../renderer-webgpu/dist/instances.js
|
|
2596
2621
|
var INSTANCE_FLOATS = 18;
|
|
2597
2622
|
var INSTANCE_BYTES = INSTANCE_FLOATS * 4;
|
|
2623
|
+
var LENS_STRENGTH_MAX = 4;
|
|
2624
|
+
function boundedLensStrength(strength) {
|
|
2625
|
+
if (Number.isNaN(strength))
|
|
2626
|
+
return IDLE_CHANNELS.lensStrength;
|
|
2627
|
+
return Math.min(LENS_STRENGTH_MAX, Math.max(0, strength));
|
|
2628
|
+
}
|
|
2629
|
+
function boundedMaterialization(value) {
|
|
2630
|
+
if (Number.isNaN(value))
|
|
2631
|
+
return IDLE_CHANNELS.materialization;
|
|
2632
|
+
return Math.min(1, Math.max(0, value));
|
|
2633
|
+
}
|
|
2634
|
+
function drawsMaterial(surface) {
|
|
2635
|
+
if (surface.fieldReferenceOnly === true)
|
|
2636
|
+
return false;
|
|
2637
|
+
const presence = surface.channels?.materialization ?? IDLE_CHANNELS.materialization;
|
|
2638
|
+
return boundedMaterialization(presence) > 0;
|
|
2639
|
+
}
|
|
2598
2640
|
var channelsOf = (input) => ({
|
|
2599
2641
|
...IDLE_CHANNELS,
|
|
2600
2642
|
...input.channels
|
|
@@ -2643,7 +2685,7 @@ function resolveSurfaces(group, family, profile = DEFAULT_MATERIAL_PROFILE, poli
|
|
|
2643
2685
|
return shape;
|
|
2644
2686
|
};
|
|
2645
2687
|
const paramsFor = (shape) => family === "rsup" ? governorFieldParams(shape) : fieldParams(shape);
|
|
2646
|
-
return group.surfaces.filter(
|
|
2688
|
+
return group.surfaces.filter(drawsMaterial).map((surface) => {
|
|
2647
2689
|
const channels = channelsOf(surface);
|
|
2648
2690
|
const shape = resolveShapeOf(surface);
|
|
2649
2691
|
const fieldSource = surface.concentricOf === void 0 ? shape : resolveShapeOf(byId.get(surface.concentricOf.nodeId));
|
|
@@ -2660,6 +2702,7 @@ function resolveSurfaces(group, family, profile = DEFAULT_MATERIAL_PROFILE, poli
|
|
|
2660
2702
|
spanPx,
|
|
2661
2703
|
lensDepthPx: lensDepthPx(shape.channels.thickness, spanPx, profile, profile.refractionScale[accessibilityRefractionCap(policy)]),
|
|
2662
2704
|
sizeThickness: thickness,
|
|
2705
|
+
materialization: boundedMaterialization(channels.materialization),
|
|
2663
2706
|
tintStrength: Math.min(1, Math.max(0, surface.tint?.strength ?? 0))
|
|
2664
2707
|
};
|
|
2665
2708
|
});
|
|
@@ -2723,10 +2766,10 @@ function packInstances(surfaces, origin, into) {
|
|
|
2723
2766
|
data[o + 11] = s.shape.channels.thickness;
|
|
2724
2767
|
data[o + 12] = s.channels.press;
|
|
2725
2768
|
data[o + 13] = s.channels.glow;
|
|
2726
|
-
data[o + 14] = Math.max(s.shape.channels.thickness, 0) *
|
|
2769
|
+
data[o + 14] = Math.max(s.shape.channels.thickness, 0) * boundedLensStrength(s.channels.lensStrength);
|
|
2727
2770
|
data[o + 15] = s.tintStrength;
|
|
2728
2771
|
data[o + 16] = s.spanPx;
|
|
2729
|
-
data[o + 17] =
|
|
2772
|
+
data[o + 17] = s.materialization;
|
|
2730
2773
|
}
|
|
2731
2774
|
return { data, count: surfaces.length };
|
|
2732
2775
|
}
|
|
@@ -3004,7 +3047,7 @@ var WGSL_INSTANCE_STRUCT = `struct Instance {
|
|
|
3004
3047
|
lensThick : f32, // 56 authored thickness in CSS px times the lensStrength channel (W12 G2): both depths are evaluated from it per pixel
|
|
3005
3048
|
tintK : f32, // 60 author tint strength, 0..1 \u2014 the seed itself is a group uniform
|
|
3006
3049
|
span : f32, // 64 the surface's shorter extent, CSS px \u2014 the size law's input, both curves (W11c)
|
|
3007
|
-
|
|
3050
|
+
mat : f32, // 68 presence, 0..1 (W27d): the slot the 8-byte alignment already required
|
|
3008
3051
|
};`;
|
|
3009
3052
|
var WGSL_FIELD_SAMPLE = `struct FieldSample {
|
|
3010
3053
|
d : f32,
|
|
@@ -3214,6 +3257,17 @@ var WGSL_FIELD_PASS = `struct FieldUniforms {
|
|
|
3214
3257
|
// two merged members share one oval there \u2014 a value nothing measured either.
|
|
3215
3258
|
// For a concentric child the box is the parent's (the child is the parent's
|
|
3216
3259
|
// level set), which is the same centre and a slightly larger oval.
|
|
3260
|
+
//
|
|
3261
|
+
// 'presence' (W27d) is the fourth target and carries one number: the surface's
|
|
3262
|
+
// materialization, blended through the union on the same weight as everything
|
|
3263
|
+
// else. It is a target of its own rather than a component of one of the three
|
|
3264
|
+
// above because all three are full \u2014 the field carries the distance, the normal
|
|
3265
|
+
// and the coverage, 'aux' the four optical scalars, 'aux2' the surface's own box
|
|
3266
|
+
// \u2014 and repurposing a component would mean re-deriving a value the fragment
|
|
3267
|
+
// stages read, which is how a golden moves for a reason nobody named. It is
|
|
3268
|
+
// r16float rather than the working rgba16float for the same honesty: one scalar
|
|
3269
|
+
// costs one channel, and a wave that needs a second widens the format in the one
|
|
3270
|
+
// place it is declared ('passes.ts').
|
|
3217
3271
|
|
|
3218
3272
|
@group(0) @binding(0) var<uniform> fu : FieldUniforms;
|
|
3219
3273
|
@group(0) @binding(1) var<storage, read> instances : array<Instance>;
|
|
@@ -3223,6 +3277,7 @@ struct Member {
|
|
|
3223
3277
|
g : vec2f,
|
|
3224
3278
|
aux : vec4f,
|
|
3225
3279
|
aux2 : vec4f,
|
|
3280
|
+
mat : f32,
|
|
3226
3281
|
};
|
|
3227
3282
|
|
|
3228
3283
|
fn eval_instance(i : u32, p : vec2f) -> Member {
|
|
@@ -3239,6 +3294,7 @@ fn eval_instance(i : u32, p : vec2f) -> Member {
|
|
|
3239
3294
|
// The pixel relative to the surface's centre, and the half-extents: what the
|
|
3240
3295
|
// oval's gradient needs, written here where the group-local position is exact.
|
|
3241
3296
|
m.aux2 = vec4f(p - s.centre, s.half);
|
|
3297
|
+
m.mat = s.mat;
|
|
3242
3298
|
return m;
|
|
3243
3299
|
}
|
|
3244
3300
|
|
|
@@ -3246,6 +3302,7 @@ struct FieldOut {
|
|
|
3246
3302
|
@location(0) field : vec4f,
|
|
3247
3303
|
@location(1) aux : vec4f,
|
|
3248
3304
|
@location(2) aux2 : vec4f,
|
|
3305
|
+
@location(3) presence : vec4f,
|
|
3249
3306
|
};
|
|
3250
3307
|
|
|
3251
3308
|
@fragment
|
|
@@ -3264,6 +3321,10 @@ fn fs_field(in : FullscreenOut) -> FieldOut {
|
|
|
3264
3321
|
out.field = vec4f(65000.0, 0.0, -1.0, 0.0);
|
|
3265
3322
|
out.aux = vec4f(0.0);
|
|
3266
3323
|
out.aux2 = vec4f(0.0);
|
|
3324
|
+
// The idle, not zero: no surface here means nothing to be absent, and a
|
|
3325
|
+
// reader that walks off the instances (the outer shadow's offset read) must
|
|
3326
|
+
// not find a material it has to fade.
|
|
3327
|
+
out.presence = vec4f(1.0, 0.0, 0.0, 0.0);
|
|
3267
3328
|
return out;
|
|
3268
3329
|
}
|
|
3269
3330
|
|
|
@@ -3277,6 +3338,7 @@ fn fs_field(in : FullscreenOut) -> FieldOut {
|
|
|
3277
3338
|
acc.g = mix(s.g, acc.g, h);
|
|
3278
3339
|
acc.aux = mix(s.aux, acc.aux, h);
|
|
3279
3340
|
acc.aux2 = mix(s.aux2, acc.aux2, h);
|
|
3341
|
+
acc.mat = mix(s.mat, acc.mat, h);
|
|
3280
3342
|
nearest = min(nearest, s.d);
|
|
3281
3343
|
}
|
|
3282
3344
|
// One clamp at the end of the fold, so |union - min| <= maxBulge holds for any
|
|
@@ -3290,6 +3352,7 @@ fn fs_field(in : FullscreenOut) -> FieldOut {
|
|
|
3290
3352
|
out.field = vec4f(acc.d, normal.x, normal.y, coverage);
|
|
3291
3353
|
out.aux = acc.aux;
|
|
3292
3354
|
out.aux2 = acc.aux2;
|
|
3355
|
+
out.presence = vec4f(acc.mat, 0.0, 0.0, 0.0);
|
|
3293
3356
|
return out;
|
|
3294
3357
|
}`;
|
|
3295
3358
|
function fieldPassSource(family) {
|
|
@@ -3349,6 +3412,10 @@ var WGSL_HIGHLIGHT_PASS = `struct HighlightUniforms {
|
|
|
3349
3412
|
@group(0) @binding(1) var fieldTexture : texture_2d<f32>;
|
|
3350
3413
|
@group(0) @binding(2) var auxTexture : texture_2d<f32>;
|
|
3351
3414
|
@group(0) @binding(3) var fieldSampler : sampler;
|
|
3415
|
+
/// The surface's presence per pixel (W27d) \u2014 the field pass's fourth target,
|
|
3416
|
+
/// bound here for the same reason the optics pass binds it: a highlight is the
|
|
3417
|
+
/// material catching light, and a material that is not there catches none.
|
|
3418
|
+
@group(0) @binding(4) var presenceTexture : texture_2d<f32>;
|
|
3352
3419
|
|
|
3353
3420
|
const TAU = 6.283185307179586;
|
|
3354
3421
|
|
|
@@ -3367,14 +3434,18 @@ fn fs_highlight(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
3367
3434
|
let fieldUv = in.uv * hu.fieldFit.xy + hu.fieldFit.zw;
|
|
3368
3435
|
var field : vec4f;
|
|
3369
3436
|
var aux : vec4f;
|
|
3437
|
+
var presence : vec4f;
|
|
3370
3438
|
if (hu.flags.z > 0.5) {
|
|
3371
3439
|
field = textureSampleLevel(fieldTexture, fieldSampler, fieldUv, 0.0);
|
|
3372
3440
|
aux = textureSampleLevel(auxTexture, fieldSampler, fieldUv, 0.0);
|
|
3441
|
+
presence = textureSampleLevel(presenceTexture, fieldSampler, fieldUv, 0.0);
|
|
3373
3442
|
} else {
|
|
3374
3443
|
let texel = vec2i(fieldUv * hu.flags.xy);
|
|
3375
3444
|
field = textureLoad(fieldTexture, texel, 0);
|
|
3376
3445
|
aux = textureLoad(auxTexture, texel, 0);
|
|
3446
|
+
presence = textureLoad(presenceTexture, texel, 0);
|
|
3377
3447
|
}
|
|
3448
|
+
let mat = clamp(presence.x, 0.0, 1.0);
|
|
3378
3449
|
let d = field.x;
|
|
3379
3450
|
let normal = field.yz;
|
|
3380
3451
|
let coverage = field.w;
|
|
@@ -3432,7 +3503,15 @@ fn fs_highlight(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
3432
3503
|
toneAdapt = clamp(hu.toneAdapt.w, 0.0, 1.0) * (1.0 - toneT * toneT * (3.0 - 2.0 * toneT));
|
|
3433
3504
|
}
|
|
3434
3505
|
|
|
3435
|
-
|
|
3506
|
+
/*
|
|
3507
|
+
* The presence (W27d) fades both lights on one factor, exactly as the collapse
|
|
3508
|
+
* above fades them: the sweep is the material's own rim catching a travelling
|
|
3509
|
+
* light and the glow is the material lit from a press, so neither survives a
|
|
3510
|
+
* surface that is not there. It is applied to the composed intensity rather
|
|
3511
|
+
* than to each term, because a highlight that fades on two statements of one
|
|
3512
|
+
* rule is a highlight that will one day fade on one of them.
|
|
3513
|
+
*/
|
|
3514
|
+
let intensity = clamp(sweep + press, 0.0, 1.0) * coverage * (1.0 - toneAdapt) * mat;
|
|
3436
3515
|
if (intensity <= 0.0) {
|
|
3437
3516
|
return vec4f(0.0);
|
|
3438
3517
|
}
|
|
@@ -3460,9 +3539,8 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
|
|
|
3460
3539
|
/// accessibility fold \u2014 the refraction ladder read at the preference's cap,
|
|
3461
3540
|
/// which every facet's span-dependent rise is multiplied by (W11c)
|
|
3462
3541
|
tone : vec4f,
|
|
3463
|
-
/// rimWidthPx, rimAlpha;
|
|
3464
|
-
///
|
|
3465
|
-
/// section 1) and are written but unread
|
|
3542
|
+
/// rimWidthPx, rimAlpha; the slots retired by W24 now carry W27c's
|
|
3543
|
+
/// tintChromaScale (z) and tintShadeCollapseRetention (w).
|
|
3466
3544
|
rim : vec4f,
|
|
3467
3545
|
/// light direction, unit (xy), shadowDepth (z), shadowAlpha (w)
|
|
3468
3546
|
light : vec4f,
|
|
@@ -3578,7 +3656,9 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
|
|
|
3578
3656
|
/// carries a heavy texture, 0 where it does not. The WIDTH is not here: the
|
|
3579
3657
|
/// pyramid blurred it into 'backdropHeavy' before any group was drawn, so all
|
|
3580
3658
|
/// this pass decides is which of two textures the deep sample comes from.
|
|
3581
|
-
/// (y) (
|
|
3659
|
+
/// (y) is the DOM material mode (0 off, 1 unknown tone, 2 measured tone);
|
|
3660
|
+
/// (z) and (w) carry its reference level and minimum tint contrast.
|
|
3661
|
+
/// Texture draws keep those lanes zero, so their input bytes do not move.
|
|
3582
3662
|
heavyTap : vec4f,
|
|
3583
3663
|
};
|
|
3584
3664
|
|
|
@@ -3598,6 +3678,11 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
|
|
|
3598
3678
|
/// from. Bound at every draw; read only where 'heavyTap.x' says there is one.
|
|
3599
3679
|
@group(0) @binding(8) var backdropHeavy : texture_2d<f32>;
|
|
3600
3680
|
|
|
3681
|
+
/// The surface's PRESENCE per pixel (W27d; contract X6): the 'materialization'
|
|
3682
|
+
/// channel, unioned in the field pass like every other per-surface scalar. One
|
|
3683
|
+
/// channel, in the field pass's fourth target \u2014 see 'wgsl/field.ts'.
|
|
3684
|
+
@group(0) @binding(9) var presenceTexture : texture_2d<f32>;
|
|
3685
|
+
|
|
3601
3686
|
/// One encoded sRGB channel from a linear one \u2014 the space the backdrop tone
|
|
3602
3687
|
/// response's anchors live in (W9). Mirrors material.ts's 'linearToSrgbChannel'.
|
|
3603
3688
|
fn srgb_encode(c : f32) -> f32 {
|
|
@@ -3672,6 +3757,12 @@ struct ShadowSample {
|
|
|
3672
3757
|
alpha : f32,
|
|
3673
3758
|
falloff : f32,
|
|
3674
3759
|
castSpanCss : f32,
|
|
3760
|
+
/// The presence of the surface that CAST the shadow (W27d), read at the offset
|
|
3761
|
+
/// position beside its span. A shadow belongs to the surface above it, so it
|
|
3762
|
+
/// fades with that surface's materialization and not with the one under this
|
|
3763
|
+
/// pixel \u2014 which is a real difference wherever a dissolving surface's shadow
|
|
3764
|
+
/// falls across a present one.
|
|
3765
|
+
castMat : f32,
|
|
3675
3766
|
};
|
|
3676
3767
|
|
|
3677
3768
|
/// The composite's peak linear occlusion above the knee, at a casting span \u2014
|
|
@@ -3702,6 +3793,7 @@ fn outer_shadow(uv : vec2f, upsampled : f32, fieldSize : vec2f) -> ShadowSample
|
|
|
3702
3793
|
out.alpha = 0.0;
|
|
3703
3794
|
out.falloff = 0.0;
|
|
3704
3795
|
out.castSpanCss = 0.0;
|
|
3796
|
+
out.castMat = 1.0;
|
|
3705
3797
|
if (ou.shadow.x <= 0.0 && ou.shadowThick.x <= 0.0) {
|
|
3706
3798
|
return out;
|
|
3707
3799
|
}
|
|
@@ -3729,14 +3821,18 @@ fn outer_shadow(uv : vec2f, upsampled : f32, fieldSize : vec2f) -> ShadowSample
|
|
|
3729
3821
|
let shadowUv = clamp(vec2f(uv.x, shiftedY), vec2f(0.0), vec2f(1.0));
|
|
3730
3822
|
var shadowField : vec4f;
|
|
3731
3823
|
var shadowAux : vec4f;
|
|
3824
|
+
var shadowPresence : vec4f;
|
|
3732
3825
|
if (upsampled > 0.5) {
|
|
3733
3826
|
shadowField = textureSampleLevel(fieldTexture, fieldSampler, shadowUv, 0.0);
|
|
3734
3827
|
shadowAux = textureSampleLevel(auxTexture, fieldSampler, shadowUv, 0.0);
|
|
3828
|
+
shadowPresence = textureSampleLevel(presenceTexture, fieldSampler, shadowUv, 0.0);
|
|
3735
3829
|
} else {
|
|
3736
3830
|
let texel = clamp(vec2i(shadowUv * fieldSize), vec2i(0), vec2i(fieldSize) - vec2i(1));
|
|
3737
3831
|
shadowField = textureLoad(fieldTexture, texel, 0);
|
|
3738
3832
|
shadowAux = textureLoad(auxTexture, texel, 0);
|
|
3833
|
+
shadowPresence = textureLoad(presenceTexture, texel, 0);
|
|
3739
3834
|
}
|
|
3835
|
+
let castMat = clamp(shadowPresence.x, 0.0, 1.0);
|
|
3740
3836
|
|
|
3741
3837
|
// The size law reaches the amplitude and nothing else \u2014 the reference's three
|
|
3742
3838
|
// lengths are span-invariant across 32\u2026160 px. Every span-keyed quantity here
|
|
@@ -3766,9 +3862,12 @@ fn outer_shadow(uv : vec2f, upsampled : f32, fieldSize : vec2f) -> ShadowSample
|
|
|
3766
3862
|
// LINEAR light; then the one conversion to the canvas's compositing space,
|
|
3767
3863
|
// which is where the black term is actually composited.
|
|
3768
3864
|
let occ = clamp(regime + ou.shadowSize.x * sizeK * (1.0 - regime), 0.0, 1.0);
|
|
3769
|
-
|
|
3865
|
+
// Times the casting surface's presence (W27d): a material that is not there
|
|
3866
|
+
// occludes nothing. At presence 1 this is the alpha the bed measures.
|
|
3867
|
+
out.alpha = (1.0 - pow(1.0 - occ, 1.0 / 2.4)) * castMat;
|
|
3770
3868
|
out.falloff = outer_shadow_falloff(shadowField.x + clampedOffCss - ou.shadow.z, ou.shadow.y);
|
|
3771
3869
|
out.castSpanCss = shadowAux.z;
|
|
3870
|
+
out.castMat = castMat;
|
|
3772
3871
|
return out;
|
|
3773
3872
|
}
|
|
3774
3873
|
|
|
@@ -3788,7 +3887,8 @@ fn outer_shadow(uv : vec2f, upsampled : f32, fieldSize : vec2f) -> ShadowSample
|
|
|
3788
3887
|
/// zero where the group has no backdrop to copy \u2014 so 'dark-solid', 'impulse',
|
|
3789
3888
|
/// every thin cell and every unsampled group stay byte-for-byte what they were.
|
|
3790
3889
|
fn outer_shadow_lift(viewport01 : vec2f, shadow : ShadowSample) -> vec3f {
|
|
3791
|
-
if (ou.flags.x <= 0.5
|
|
3890
|
+
if ((ou.flags.x <= 0.5 && ou.heavyTap.y < 1.5) ||
|
|
3891
|
+
ou.shadowLift.x <= 0.0 || shadow.falloff <= 0.0) {
|
|
3792
3892
|
return vec3f(0.0);
|
|
3793
3893
|
}
|
|
3794
3894
|
// Written out rather than through WGSL's 'smoothstep', which is undefined
|
|
@@ -3804,13 +3904,53 @@ fn outer_shadow_lift(viewport01 : vec2f, shadow : ShadowSample) -> vec3f {
|
|
|
3804
3904
|
if (rise <= 0.0) {
|
|
3805
3905
|
return vec3f(0.0);
|
|
3806
3906
|
}
|
|
3907
|
+
if (ou.flags.x <= 0.5) {
|
|
3908
|
+
// A DOM page has no exterior texture: this is the law at the stated tone,
|
|
3909
|
+
// not a claim to reproduce the colour or structure beyond the silhouette.
|
|
3910
|
+
return ou.toneColour.rgb * (ou.shadowLift.x * rise * shadow.falloff);
|
|
3911
|
+
}
|
|
3807
3912
|
let uv = clamp(viewport01 * ou.fit.xy + ou.fit.zw, vec2f(0.0), vec2f(1.0));
|
|
3808
3913
|
let chainSample = textureSampleLevel(backdropChain, backdropSampler, uv, ou.shadowLift.w);
|
|
3809
3914
|
// Premultiplied linear in, straight colour out \u2014 the same unpremultiply the
|
|
3810
3915
|
// body's own samples take, for the same reason: a partially transparent
|
|
3811
3916
|
// backdrop must not darken what the material adds back.
|
|
3812
3917
|
let v = chainSample.rgb / max(chainSample.a, 1e-6);
|
|
3813
|
-
|
|
3918
|
+
// The black term's presence, on the shadow's second term: the two are one
|
|
3919
|
+
// shadow with one falloff (W14 G0), so one channel fades both.
|
|
3920
|
+
return v * (ou.shadowLift.x * rise * shadow.falloff * shadow.castMat);
|
|
3921
|
+
}
|
|
3922
|
+
|
|
3923
|
+
/// The DOM branch is the per-pixel mirror of platform-web's materialAtBackdrop.
|
|
3924
|
+
/// It evaluates the linear response, collapse, paint and rim at the stated tone,
|
|
3925
|
+
/// then solves the encoded layer the browser composites. A union's span stays
|
|
3926
|
+
/// per pixel, and the conversion reference never enables an unknown tone.
|
|
3927
|
+
fn dom_material_backdrop() -> vec3f {
|
|
3928
|
+
if (ou.heavyTap.y > 1.5) { return ou.toneColour.rgb; }
|
|
3929
|
+
return vec3f(ou.heavyTap.z);
|
|
3930
|
+
}
|
|
3931
|
+
|
|
3932
|
+
/// The cssTintAlpha secant, at the actual tone rather than before the response.
|
|
3933
|
+
fn dom_material_alpha(composite : vec3f, backdrop : vec3f, alpha : f32) -> f32 {
|
|
3934
|
+
if (alpha <= 1e-6) { return 0.0; }
|
|
3935
|
+
let weights = vec3f(0.2126, 0.7152, 0.0722);
|
|
3936
|
+
let neutral = max((composite - backdrop * (1.0 - alpha)) / alpha, vec3f(0.0));
|
|
3937
|
+
let b = srgb_encode(dot(backdrop, weights));
|
|
3938
|
+
let span = srgb_encode(dot(neutral, weights)) - b;
|
|
3939
|
+
if (abs(span) < ou.heavyTap.w) { return alpha; }
|
|
3940
|
+
return clamp((srgb_encode(dot(composite, weights)) - b) / span, 0.0, 1.0);
|
|
3941
|
+
}
|
|
3942
|
+
|
|
3943
|
+
/// The final encoded solve, including paint and contour light. The least opacity
|
|
3944
|
+
/// needed to keep every channel in gamut is an algebraic constraint, not a fit.
|
|
3945
|
+
/// At the reference B this returns E(C) exactly after browser source-over; away
|
|
3946
|
+
/// from B the scalar layer cannot reproduce the sampled path's local structure.
|
|
3947
|
+
fn dom_material_output(encodedComposite : vec3f, encodedBackdrop : vec3f, alpha : f32) -> vec4f {
|
|
3948
|
+
let c = clamp(encodedComposite, vec3f(0.0), vec3f(1.0));
|
|
3949
|
+
let b = clamp(encodedBackdrop, vec3f(0.0), vec3f(1.0));
|
|
3950
|
+
let need = select((b - c) / max(b, vec3f(1e-6)),
|
|
3951
|
+
(c - b) / max(vec3f(1.0) - b, vec3f(1e-6)), c >= b);
|
|
3952
|
+
let a = clamp(max(alpha, max(need.x, max(need.y, need.z))), 0.0, 1.0);
|
|
3953
|
+
return vec4f(clamp(c - b * (1.0 - a), vec3f(0.0), vec3f(a)), a);
|
|
3814
3954
|
}
|
|
3815
3955
|
|
|
3816
3956
|
@fragment
|
|
@@ -3823,20 +3963,48 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
3823
3963
|
var field : vec4f;
|
|
3824
3964
|
var aux : vec4f;
|
|
3825
3965
|
var aux2 : vec4f;
|
|
3966
|
+
var presence : vec4f;
|
|
3826
3967
|
if (ou.flags.w > 0.5) {
|
|
3827
3968
|
field = textureSampleLevel(fieldTexture, fieldSampler, in.uv, 0.0);
|
|
3828
3969
|
aux = textureSampleLevel(auxTexture, fieldSampler, in.uv, 0.0);
|
|
3829
3970
|
aux2 = textureSampleLevel(aux2Texture, fieldSampler, in.uv, 0.0);
|
|
3971
|
+
presence = textureSampleLevel(presenceTexture, fieldSampler, in.uv, 0.0);
|
|
3830
3972
|
} else {
|
|
3831
3973
|
let texel = vec2i(in.uv * ou.flags.yz);
|
|
3832
3974
|
field = textureLoad(fieldTexture, texel, 0);
|
|
3833
3975
|
aux = textureLoad(auxTexture, texel, 0);
|
|
3834
3976
|
aux2 = textureLoad(aux2Texture, texel, 0);
|
|
3977
|
+
presence = textureLoad(presenceTexture, texel, 0);
|
|
3835
3978
|
}
|
|
3836
3979
|
|
|
3837
3980
|
let d = field.x;
|
|
3838
3981
|
let normal = field.yz;
|
|
3839
3982
|
let coverage = field.w;
|
|
3983
|
+
/*
|
|
3984
|
+
* The surface's PRESENCE at this pixel (W27d; contract X6) \u2014 the
|
|
3985
|
+
* 'materialization' channel, 1 on a surface nobody is driving.
|
|
3986
|
+
*
|
|
3987
|
+
* It multiplies every term the material ADDS to what is behind it: the lens's
|
|
3988
|
+
* depth and magnitude, the body's mix away from the unblurred backdrop, the
|
|
3989
|
+
* material's own alpha, the author tint's coverage, the inner shadow, the rim,
|
|
3990
|
+
* the outer shadow and the highlight pass's light. It does NOT multiply the
|
|
3991
|
+
* coverage: a presence spent there would be a crossfade of the whole composite,
|
|
3992
|
+
* which is the alpha Apple's rule rules out ("prefer setting the effect
|
|
3993
|
+
* property over the alpha") and which the runtime cannot afford either \u2014 the
|
|
3994
|
+
* host that wrote it would form a Backdrop Root and lose the group's sampling.
|
|
3995
|
+
*
|
|
3996
|
+
* Not to be confused with 'present' below, which is what survives the backdrop
|
|
3997
|
+
* COLLAPSE. The two multiply many of the same terms and mean different things:
|
|
3998
|
+
* one is the author's presence, the other is the material having taken its
|
|
3999
|
+
* backdrop's tone. Both are one multiplication by one on the resting bed.
|
|
4000
|
+
*
|
|
4001
|
+
* The channel is strictly ABOVE zero here. Exactly 0 is 'Glass.identity' and is
|
|
4002
|
+
* resolved on the CPU by dropping the member before this pass ever runs
|
|
4003
|
+
* ('instances.ts'), so a surface that is not there has no silhouette to draw a
|
|
4004
|
+
* faded material into and no shape to union with its neighbours. What this
|
|
4005
|
+
* shader owns is the continuum between the endpoints.
|
|
4006
|
+
*/
|
|
4007
|
+
let mat = clamp(presence.x, 0.0, 1.0);
|
|
3840
4008
|
|
|
3841
4009
|
/*
|
|
3842
4010
|
* The outer shadow (W8) sits UNDER the material, so it is resolved before the
|
|
@@ -3892,7 +4060,13 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
3892
4060
|
// Per-pixel, unioned through the field pass. See the module note. 'aux.x' is
|
|
3893
4061
|
// the authored thickness times the lensStrength channel (W12 G2); the lens's
|
|
3894
4062
|
// depth and the inner shadow's are both evaluated from it and the span below.
|
|
3895
|
-
|
|
4063
|
+
//
|
|
4064
|
+
// Times the presence (W27d), because this is the one number Apple's own
|
|
4065
|
+
// description of materializing names \u2014 "by gradually modulating the light
|
|
4066
|
+
// bending and lensing" \u2014 and both depths are functions of it, so the lens
|
|
4067
|
+
// shallows and weakens together and the inner shadow's depth follows the same
|
|
4068
|
+
// channel rather than a second statement of it.
|
|
4069
|
+
let lensThick = max(aux.x, 0.0) * mat;
|
|
3896
4070
|
// The thickness curve off the span of whichever surface owns this pixel
|
|
3897
4071
|
// (W11c). 'sizeK' is the thickness factor, 0..1: zero on anything at or below
|
|
3898
4072
|
// the profile's 'sizeSpanMin', saturated at 'sizeSpanMax', folded under the
|
|
@@ -4070,6 +4244,8 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4070
4244
|
let scatterLod = clamp(ou.size.w + log2(max(gainEff, 1e-4)), 0.0, ou.lens.w);
|
|
4071
4245
|
|
|
4072
4246
|
var backdrop = vec3f(0.0);
|
|
4247
|
+
let domMaterial = ou.heavyTap.y > 0.5;
|
|
4248
|
+
if (domMaterial) { backdrop = dom_material_backdrop(); }
|
|
4073
4249
|
if (ou.flags.x > 0.5) {
|
|
4074
4250
|
// Both components at the refracted position (W11c G2): the band and the
|
|
4075
4251
|
// interior are one body, and the displacement alone is the lens.
|
|
@@ -4105,6 +4281,26 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4105
4281
|
// the glass.
|
|
4106
4282
|
let scatterColour = scatterSample.rgb / max(scatterSample.a, 1e-6);
|
|
4107
4283
|
backdrop = mix(bodySample.rgb / max(bodySample.a, 1e-6), scatterColour, kScatter);
|
|
4284
|
+
/*
|
|
4285
|
+
* The body's own half of the presence (W27d): a material at half presence
|
|
4286
|
+
* shows half the BLUR, not half the surface. What a surface at presence 0
|
|
4287
|
+
* stands over is the page as it is, so the two components' composite lerps
|
|
4288
|
+
* back to the unblurred backdrop \u2014 the chain's own level 0, which is the
|
|
4289
|
+
* texture before any of the pyramid's widths were applied.
|
|
4290
|
+
*
|
|
4291
|
+
* Read at 'refractedUv' rather than at this pixel's own position: the lens is
|
|
4292
|
+
* scaled by the same channel, so the sample walks back to the pixel as the
|
|
4293
|
+
* presence falls and arrives exactly there at 0. One uv, one read, and no
|
|
4294
|
+
* discontinuity between the two ends.
|
|
4295
|
+
*
|
|
4296
|
+
* The branch is what keeps the resting material byte-identical \u2014 at presence
|
|
4297
|
+
* 1 the extra tap is not taken at all \u2014 and it is also what keeps a present
|
|
4298
|
+
* surface from paying for a channel it is not using.
|
|
4299
|
+
*/
|
|
4300
|
+
if (mat < 1.0) {
|
|
4301
|
+
let sharpSample = textureSampleLevel(backdropChain, backdropSampler, refractedUv, 0.0);
|
|
4302
|
+
backdrop = mix(sharpSample.rgb / max(sharpSample.a, 1e-6), backdrop, mat);
|
|
4303
|
+
}
|
|
4108
4304
|
}
|
|
4109
4305
|
|
|
4110
4306
|
// Adaptive tint. 'adapt.w' is the strength the accessibility policy and the
|
|
@@ -4255,7 +4451,7 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4255
4451
|
* There the CSS tier's own 'backdrop-filter' is what carries the transmission.
|
|
4256
4452
|
*/
|
|
4257
4453
|
var toneTarget = ou.toneColour.rgb;
|
|
4258
|
-
if (ou.flags.x > 0.5) {
|
|
4454
|
+
if (ou.flags.x > 0.5 || domMaterial) {
|
|
4259
4455
|
toneTarget = mix(toneTarget, backdrop, clamp(ou.toneRowThick.w, 0.0, 1.0));
|
|
4260
4456
|
}
|
|
4261
4457
|
|
|
@@ -4273,7 +4469,15 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4273
4469
|
// opaque" is a statement about how much material there is), and the backdrop
|
|
4274
4470
|
// adaptation moved it above. The author's colour never touches it \u2014 but not
|
|
4275
4471
|
// for the reason the composition contract first gave (claims \xA75.36).
|
|
4276
|
-
|
|
4472
|
+
/*
|
|
4473
|
+
* The material's alpha, times the presence (W27d) \u2014 and applied HERE rather
|
|
4474
|
+
* than to 'adaptedAlpha' above, which is load-bearing: that alpha is the
|
|
4475
|
+
* divisor the collapse's own composite is un-premultiplied by, so scaling it
|
|
4476
|
+
* there would move the adapted COLOUR as well as the amount of it. Presence is
|
|
4477
|
+
* how much of the material is there, not what the material is.
|
|
4478
|
+
*/
|
|
4479
|
+
let presentAlpha = adaptedAlpha * mat;
|
|
4480
|
+
var colour = mix(backdrop, adapted, presentAlpha);
|
|
4277
4481
|
/*
|
|
4278
4482
|
* How much of this pixel the SURFACE owns, as the canvas will composite it.
|
|
4279
4483
|
*
|
|
@@ -4295,10 +4499,41 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4295
4499
|
* in encoded sRGB, so the alpha is the CSS tier's, not the linear profile's.
|
|
4296
4500
|
*/
|
|
4297
4501
|
var bodyAlpha = 1.0;
|
|
4298
|
-
|
|
4502
|
+
var domAlpha = 1.0;
|
|
4503
|
+
if (domMaterial) {
|
|
4504
|
+
// The collapse transmits k*c of the DOM proxy as well. Solve the secant
|
|
4505
|
+
// after the linear material, never feed its encoded alpha back into R.
|
|
4506
|
+
/*
|
|
4507
|
+
* Times the presence (W27d), on the same factor 'presentAlpha' carries into
|
|
4508
|
+
* 'colour' just above \u2014 this branch's body is a SOLVED layer rather than a
|
|
4509
|
+
* composite, so the secant's own input is where the channel reaches it.
|
|
4510
|
+
*
|
|
4511
|
+
* It has to be here rather than on the result. The secant divides the
|
|
4512
|
+
* composite by this alpha to recover the material's own neutral, so scaling
|
|
4513
|
+
* both together leaves that neutral (and the span it spans) at exactly what
|
|
4514
|
+
* presence 1 solves, and only the returned coverage travels. Left unscaled,
|
|
4515
|
+
* the neutral would walk toward the backdrop as the surface thins, the span
|
|
4516
|
+
* would fall under 'heavyTap.w', and the guard would hand back the FULL
|
|
4517
|
+
* alpha \u2014 a flat tone painted over a page the surface has left.
|
|
4518
|
+
*
|
|
4519
|
+
* At presence 1 the factor is exactly 1.0 and the expression is bit-identical
|
|
4520
|
+
* to the resting one; at 0 the secant's own '<= 1e-6' guard returns 0.
|
|
4521
|
+
*/
|
|
4522
|
+
let transmission = toneAdapt * clamp(ou.toneRowThick.w, 0.0, 1.0);
|
|
4523
|
+
domAlpha = dom_material_alpha(colour, backdrop,
|
|
4524
|
+
clamp(adaptedAlpha - transmission, 0.0, 1.0) * mat);
|
|
4525
|
+
} else if (ou.flags.x <= 0.5) {
|
|
4299
4526
|
colour = adapted;
|
|
4300
|
-
bodyAlpha =
|
|
4527
|
+
bodyAlpha = presentAlpha;
|
|
4301
4528
|
}
|
|
4529
|
+
/*
|
|
4530
|
+
* One gap this tier cannot close from here, named rather than left to be
|
|
4531
|
+
* discovered (W27d): on an unsampled group the blurred backdrop is a DOM proxy
|
|
4532
|
+
* beneath this canvas, so the body's mix toward the unblurred backdrop above
|
|
4533
|
+
* has no texture to mix with. A layer that fades to alpha 0 there reveals the
|
|
4534
|
+
* PROXY's blur rather than the page \u2014 presence takes the tint, the rim and the
|
|
4535
|
+
* shadows out, and the blur is the host's to fade with it.
|
|
4536
|
+
*/
|
|
4302
4537
|
|
|
4303
4538
|
// The author tint (W10). 'aux.w' is the per-pixel strength, unioned in the
|
|
4304
4539
|
// field pass, so a toolbar can carry one tinted control among plain ones; the
|
|
@@ -4360,16 +4595,40 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4360
4595
|
* reach painted pixels only (W23 S10).
|
|
4361
4596
|
*/
|
|
4362
4597
|
var rimTintColour = vec3f(1.0);
|
|
4363
|
-
|
|
4598
|
+
/*
|
|
4599
|
+
* The author tint's coverage at this pixel, times the presence (W27d). The
|
|
4600
|
+
* paint is part of the material and not a thing painted onto the page, so a
|
|
4601
|
+
* dissolving surface takes its colour with it \u2014 at presence 0 the pixel is the
|
|
4602
|
+
* backdrop and not a flat orange over it. At presence 1 this is
|
|
4603
|
+
* 'clamp(aux.w, 0, 1)' exactly, which is what the tint's own law was fitted on.
|
|
4604
|
+
*/
|
|
4605
|
+
let tintK = clamp(aux.w, 0.0, 1.0) * mat;
|
|
4606
|
+
if (tintK > 0.0) {
|
|
4364
4607
|
// The untinted material's luminance at this pixel. Over a backdrop that is
|
|
4365
4608
|
// the composite; as a layer it is the layer over the tone the host measured
|
|
4366
4609
|
// for the group \u2014 zero where nothing was measured, the same reference-level
|
|
4367
4610
|
// convention the CSS tier's 'materialLuminance' takes (within its 0.02).
|
|
4368
4611
|
let u = bodyAlpha * dot(colour, vec3f(0.2126, 0.7152, 0.0722)) + (1.0 - bodyAlpha) * ou.toneColour.w;
|
|
4369
|
-
let grip = clamp(ou.seed.w, 0.0, 1.0) * clamp(ou.tone.z, 0.0, 1.0) *
|
|
4612
|
+
let grip = clamp(ou.seed.w, 0.0, 1.0) * clamp(ou.tone.z, 0.0, 1.0) *
|
|
4613
|
+
(1.0 - toneAdapt * (1.0 - clamp(ou.rim.w, 0.0, 1.0)));
|
|
4370
4614
|
let shade = mix(1.0, clamp(mix(ou.tone.x, ou.tone.y, clamp(u, 0.0, 1.0)), 0.0, 1.0), grip);
|
|
4371
|
-
|
|
4372
|
-
|
|
4615
|
+
// The identity branch preserves the active seed's arithmetic bit for bit.
|
|
4616
|
+
var seed = ou.seed.rgb;
|
|
4617
|
+
if (ou.rim.z < 1.0) {
|
|
4618
|
+
let neutral = max(seed.r, max(seed.g, seed.b));
|
|
4619
|
+
seed = mix(vec3f(neutral), seed, clamp(ou.rim.z, 0.0, 1.0));
|
|
4620
|
+
}
|
|
4621
|
+
let layer = seed * shade;
|
|
4622
|
+
/*
|
|
4623
|
+
* The recede's chroma collapse (W27c) shapes WHAT the paint is; presence
|
|
4624
|
+
* (W27d) is how much of it is there. They compose on this one strength and
|
|
4625
|
+
* each reaches it once: the collapse through 'seed', the presence through
|
|
4626
|
+
* 'tintK'. 's' is the coverage every consumer below reads \u2014 the rim's tint
|
|
4627
|
+
* mix, the encoded fold, and the DOM branch's own alpha \u2014 so folding the
|
|
4628
|
+
* presence in here is what keeps it from being applied twice downstream.
|
|
4629
|
+
*/
|
|
4630
|
+
let s = tintK;
|
|
4631
|
+
if (domMaterial) { domAlpha = 1.0 - (1.0 - s) * (1.0 - domAlpha); }
|
|
4373
4632
|
let layerLuma = max(dot(layer, vec3f(0.2126, 0.7152, 0.0722)), 0.05);
|
|
4374
4633
|
rimTintColour = mix(vec3f(1.0), layer / layerLuma, clamp(ou.rimLaw.w, 0.0, 1.0) * s);
|
|
4375
4634
|
let encodedMaterial = linear_to_srgb(clamp(colour, vec3f(0.0), vec3f(1.0)));
|
|
@@ -4412,7 +4671,11 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4412
4671
|
// A multiplicative occlusion of the whole composite. As a layer that is the
|
|
4413
4672
|
// colour scaled and the alpha raised \u2014 (k\xB7a\xB7c, 1 \u2212 k\xB7(1 \u2212 a)) composites to
|
|
4414
4673
|
// k times what (a\xB7c, a) would \u2014 and at bodyAlpha 1 it is the plain product.
|
|
4415
|
-
|
|
4674
|
+
// Times the presence (W27d) on the AMPLITUDE, beside the depth the same channel
|
|
4675
|
+
// already shallowed through 'lensThick': the occlusion is the material's own,
|
|
4676
|
+
// and a material that is half there occludes half as much of what is behind it.
|
|
4677
|
+
let shadowKeep = 1.0 - shadowProfile * shadowDepth * ou.light.w * present * mat;
|
|
4678
|
+
if (domMaterial) { domAlpha = 1.0 - shadowKeep * (1.0 - domAlpha); }
|
|
4416
4679
|
let shadowedAlpha = 1.0 - shadowKeep * (1.0 - bodyAlpha);
|
|
4417
4680
|
colour = colour * (shadowKeep * bodyAlpha / max(shadowedAlpha, 1e-6));
|
|
4418
4681
|
bodyAlpha = shadowedAlpha;
|
|
@@ -4464,7 +4727,7 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4464
4727
|
let rimLuma = materialAlpha * dot(materialColour, vec3f(0.2126, 0.7152, 0.0722))
|
|
4465
4728
|
+ (1.0 - materialAlpha) * ou.toneColour.w;
|
|
4466
4729
|
let rimAmplitude = ou.rim.y + ou.rimLaw.x * rimLuma;
|
|
4467
|
-
let rimCollapsed = mix(ou.rimLaw.y, ou.rimLaw.z,
|
|
4730
|
+
let rimCollapsed = mix(ou.rimLaw.y, ou.rimLaw.z, tintK);
|
|
4468
4731
|
/*
|
|
4469
4732
|
* The lit edge (W24; claims \xA75.107) \u2014 the directional factor the whole rim is
|
|
4470
4733
|
* multiplied by, symmetric about 'rimLit.xy'.
|
|
@@ -4524,10 +4787,15 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4524
4787
|
*/
|
|
4525
4788
|
let alongSide = clamp((rel.x / halfExt.x) * (rel.y / halfExt.y), -1.0, 1.0);
|
|
4526
4789
|
let alongFactor = max(1.0 + ou.rimLit.w * sizeThick * alongSide, 0.0);
|
|
4527
|
-
|
|
4790
|
+
// The whole rim \u2014 both the appearance's own and the one the collapse keeps \u2014
|
|
4791
|
+
// times the presence (W27d). The rim is the mark that says a surface is HERE,
|
|
4792
|
+
// which is the first thing a surface that is not there stops saying; the same
|
|
4793
|
+
// argument the collapse's 'present' makes, from the author's side.
|
|
4794
|
+
let rim = rw * lit * alongFactor * (rimAmplitude * present + rimCollapsed * toneAdapt) * mat;
|
|
4528
4795
|
let rimLight = rim * rimTintColour;
|
|
4529
|
-
if (ou.flags.x > 0.5) {
|
|
4796
|
+
if (ou.flags.x > 0.5 || domMaterial) {
|
|
4530
4797
|
colour = colour + rimLight;
|
|
4798
|
+
if (domMaterial) { domAlpha = clamp(domAlpha + rim, 0.0, 1.0); }
|
|
4531
4799
|
} else {
|
|
4532
4800
|
// Added light has no premultiplied form of its own \u2014 a canvas colour may
|
|
4533
4801
|
// not exceed its alpha \u2014 so the layer carries the light in its opacity:
|
|
@@ -4555,6 +4823,17 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4555
4823
|
// translucent surface shows the page through it, not its own shadow. (With
|
|
4556
4824
|
// an opaque body the two are the same quantity, which is how the shadow was
|
|
4557
4825
|
// first written and why the difference only surfaced with the layer form.)
|
|
4826
|
+
if (domMaterial) {
|
|
4827
|
+
// Coverage precedes the gamut solve. The sampled rim may exceed white
|
|
4828
|
+
// before antialiasing; clipping it first would dim the half-covered edge.
|
|
4829
|
+
// Include the exterior shadow in the same target so its light and opacity
|
|
4830
|
+
// remain one valid premultiplied layer at that edge too.
|
|
4831
|
+
let b = linear_to_srgb(backdrop);
|
|
4832
|
+
let compositeEncoded = linear_to_srgb(max(colour, vec3f(0.0))) * coverage
|
|
4833
|
+
+ (b * (1.0 - shadowAlpha) + liftEncoded) * (1.0 - coverage);
|
|
4834
|
+
let alpha = domAlpha * coverage + shadowAlpha * (1.0 - coverage);
|
|
4835
|
+
return dom_material_output(compositeEncoded, b, alpha);
|
|
4836
|
+
}
|
|
4558
4837
|
let body = encode_output(max(colour, vec3f(0.0)), coverage * bodyAlpha);
|
|
4559
4838
|
return vec4f(
|
|
4560
4839
|
body.rgb + liftEncoded * (1.0 - coverage),
|
|
@@ -4647,10 +4926,12 @@ function allShaderSource() {
|
|
|
4647
4926
|
|
|
4648
4927
|
// ../renderer-webgpu/dist/passes.js
|
|
4649
4928
|
var fieldUsage = () => GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING;
|
|
4929
|
+
var PRESENCE_TEXTURE_FORMAT = "r16float";
|
|
4650
4930
|
var PREMULTIPLIED_OVER = {
|
|
4651
4931
|
color: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" },
|
|
4652
4932
|
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" }
|
|
4653
4933
|
};
|
|
4934
|
+
var groupResourceId = (plane, groupId) => plane === "" ? groupId : `${plane}/${groupId}`;
|
|
4654
4935
|
function createPassRunner(context) {
|
|
4655
4936
|
const { device, pool, cache } = context;
|
|
4656
4937
|
const uniforms = /* @__PURE__ */ new Map();
|
|
@@ -4690,7 +4971,8 @@ function createPassRunner(context) {
|
|
|
4690
4971
|
targets: [
|
|
4691
4972
|
{ format: WORKING_TEXTURE_FORMAT },
|
|
4692
4973
|
{ format: WORKING_TEXTURE_FORMAT },
|
|
4693
|
-
{ format: WORKING_TEXTURE_FORMAT }
|
|
4974
|
+
{ format: WORKING_TEXTURE_FORMAT },
|
|
4975
|
+
{ format: PRESENCE_TEXTURE_FORMAT }
|
|
4694
4976
|
]
|
|
4695
4977
|
},
|
|
4696
4978
|
primitive: { topology: "triangle-list" }
|
|
@@ -4741,28 +5023,35 @@ function createPassRunner(context) {
|
|
|
4741
5023
|
const rectHeight = Math.max(1, Math.round(args.rectDevice.height));
|
|
4742
5024
|
const width = Math.max(1, Math.round(args.rectDevice.width * args.renderScale));
|
|
4743
5025
|
const height = Math.max(1, Math.round(args.rectDevice.height * args.renderScale));
|
|
4744
|
-
const field = pool.acquire(poolKey.groupField(args.
|
|
5026
|
+
const field = pool.acquire(poolKey.groupField(args.resourceId), {
|
|
4745
5027
|
width,
|
|
4746
5028
|
height,
|
|
4747
5029
|
format: WORKING_TEXTURE_FORMAT,
|
|
4748
5030
|
usage: fieldUsage(),
|
|
4749
|
-
label: `vitrea:group:${args.
|
|
5031
|
+
label: `vitrea:group:${args.resourceId}:field`
|
|
4750
5032
|
});
|
|
4751
|
-
const aux = pool.acquire(poolKey.groupAux(args.
|
|
5033
|
+
const aux = pool.acquire(poolKey.groupAux(args.resourceId), {
|
|
4752
5034
|
width,
|
|
4753
5035
|
height,
|
|
4754
5036
|
format: WORKING_TEXTURE_FORMAT,
|
|
4755
5037
|
usage: fieldUsage(),
|
|
4756
|
-
label: `vitrea:group:${args.
|
|
5038
|
+
label: `vitrea:group:${args.resourceId}:aux`
|
|
4757
5039
|
});
|
|
4758
|
-
const aux2 = pool.acquire(poolKey.groupAux2(args.
|
|
5040
|
+
const aux2 = pool.acquire(poolKey.groupAux2(args.resourceId), {
|
|
4759
5041
|
width,
|
|
4760
5042
|
height,
|
|
4761
5043
|
format: WORKING_TEXTURE_FORMAT,
|
|
4762
5044
|
usage: fieldUsage(),
|
|
4763
|
-
label: `vitrea:group:${args.
|
|
5045
|
+
label: `vitrea:group:${args.resourceId}:aux2`
|
|
5046
|
+
});
|
|
5047
|
+
const presence = pool.acquire(poolKey.groupPresence(args.resourceId), {
|
|
5048
|
+
width,
|
|
5049
|
+
height,
|
|
5050
|
+
format: PRESENCE_TEXTURE_FORMAT,
|
|
5051
|
+
usage: fieldUsage(),
|
|
5052
|
+
label: `vitrea:group:${args.resourceId}:presence`
|
|
4764
5053
|
});
|
|
4765
|
-
const slot = uniformSlot(`field:${args.
|
|
5054
|
+
const slot = uniformSlot(`field:${args.resourceId}`, 12);
|
|
4766
5055
|
slot.data[0] = rectWidth;
|
|
4767
5056
|
slot.data[1] = rectHeight;
|
|
4768
5057
|
slot.data[2] = args.cssPerDevice;
|
|
@@ -4776,12 +5065,12 @@ function createPassRunner(context) {
|
|
|
4776
5065
|
slot.data[11] = 0;
|
|
4777
5066
|
new Uint32Array(slot.data.buffer, slot.data.byteOffset + 32, 1)[0] = args.instanceCount;
|
|
4778
5067
|
slot.write();
|
|
4779
|
-
const instances = storageSlot(args.
|
|
5068
|
+
const instances = storageSlot(args.resourceId);
|
|
4780
5069
|
instances.ensure(Math.max(args.instanceCount, 1) * INSTANCE_BYTES);
|
|
4781
5070
|
instances.write(args.instances, Math.max(args.instanceCount, 1) * (INSTANCE_BYTES / 4));
|
|
4782
5071
|
const pipeline = fieldPipeline(args.family);
|
|
4783
5072
|
const pass = encoder.beginRenderPass({
|
|
4784
|
-
label: `vitrea:pass:field:${args.
|
|
5073
|
+
label: `vitrea:pass:field:${args.resourceId}`,
|
|
4785
5074
|
...timed(PASS_LABEL.field),
|
|
4786
5075
|
colorAttachments: [
|
|
4787
5076
|
{
|
|
@@ -4801,6 +5090,15 @@ function createPassRunner(context) {
|
|
|
4801
5090
|
loadOp: "clear",
|
|
4802
5091
|
storeOp: "store",
|
|
4803
5092
|
clearValue: { r: 0, g: 0, b: 0, a: 0 }
|
|
5093
|
+
},
|
|
5094
|
+
{
|
|
5095
|
+
view: presence.createView(),
|
|
5096
|
+
loadOp: "clear",
|
|
5097
|
+
// Cleared to the IDLE presence rather than to zero: a texel the
|
|
5098
|
+
// fullscreen triangle never wrote must not read as a material that
|
|
5099
|
+
// has been asked to disappear.
|
|
5100
|
+
storeOp: "store",
|
|
5101
|
+
clearValue: { r: 1, g: 0, b: 0, a: 0 }
|
|
4804
5102
|
}
|
|
4805
5103
|
]
|
|
4806
5104
|
});
|
|
@@ -4818,13 +5116,14 @@ function createPassRunner(context) {
|
|
|
4818
5116
|
field,
|
|
4819
5117
|
aux,
|
|
4820
5118
|
aux2,
|
|
5119
|
+
presence,
|
|
4821
5120
|
width,
|
|
4822
5121
|
height,
|
|
4823
5122
|
upsampled: width !== rectWidth || height !== rectHeight
|
|
4824
5123
|
};
|
|
4825
5124
|
},
|
|
4826
5125
|
opticsPass(encoder, args) {
|
|
4827
|
-
const slot = uniformSlot(`optics:${args.
|
|
5126
|
+
const slot = uniformSlot(`optics:${args.resourceId}`, 112);
|
|
4828
5127
|
const d = slot.data;
|
|
4829
5128
|
d[0] = args.viewportDevice[0];
|
|
4830
5129
|
d[1] = args.viewportDevice[1];
|
|
@@ -4856,8 +5155,8 @@ function createPassRunner(context) {
|
|
|
4856
5155
|
d[27] = args.sizeFold;
|
|
4857
5156
|
d[28] = args.rimWidth;
|
|
4858
5157
|
d[29] = args.rimAlpha;
|
|
4859
|
-
d[30] = args.
|
|
4860
|
-
d[31] = args.
|
|
5158
|
+
d[30] = args.tintChromaScale ?? 1;
|
|
5159
|
+
d[31] = args.tintShadeCollapseRetention ?? 0;
|
|
4861
5160
|
d[32] = args.lightDirection[0];
|
|
4862
5161
|
d[33] = args.lightDirection[1];
|
|
4863
5162
|
d[34] = args.shadowDepth;
|
|
@@ -4935,16 +5234,16 @@ function createPassRunner(context) {
|
|
|
4935
5234
|
d[106] = 0;
|
|
4936
5235
|
d[107] = 0;
|
|
4937
5236
|
d[108] = args.heavyTapEnabled ? 1 : 0;
|
|
4938
|
-
d[109] = 0;
|
|
4939
|
-
d[110] = 0;
|
|
4940
|
-
d[111] = 0;
|
|
5237
|
+
d[109] = args.domMaterial?.mode ?? 0;
|
|
5238
|
+
d[110] = args.domMaterial?.referenceBackdropLuminance ?? 0;
|
|
5239
|
+
d[111] = args.domMaterial?.minimumTintContrast ?? 0;
|
|
4941
5240
|
slot.write();
|
|
4942
5241
|
const chain = args.backdrop?.chain ?? placeholderView;
|
|
4943
5242
|
const body = args.backdrop?.body ?? placeholderView;
|
|
4944
5243
|
const heavy = args.backdrop?.heavy ?? placeholderView;
|
|
4945
5244
|
const pipeline = opticsPipeline(args.targetFormat);
|
|
4946
5245
|
const pass = encoder.beginRenderPass({
|
|
4947
|
-
label: `vitrea:pass:optics:${args.
|
|
5246
|
+
label: `vitrea:pass:optics:${args.resourceId}`,
|
|
4948
5247
|
...timed(PASS_LABEL.optics),
|
|
4949
5248
|
colorAttachments: [{ view: args.target, loadOp: "load", storeOp: "store" }]
|
|
4950
5249
|
});
|
|
@@ -4963,14 +5262,15 @@ function createPassRunner(context) {
|
|
|
4963
5262
|
// read at all when the governor shrank them below the group's rect.
|
|
4964
5263
|
{ binding: 6, resource: context.flatSampler },
|
|
4965
5264
|
{ binding: 7, resource: args.fields.aux2.createView() },
|
|
4966
|
-
{ binding: 8, resource: heavy }
|
|
5265
|
+
{ binding: 8, resource: heavy },
|
|
5266
|
+
{ binding: 9, resource: args.fields.presence.createView() }
|
|
4967
5267
|
]
|
|
4968
5268
|
}));
|
|
4969
5269
|
pass.draw(3);
|
|
4970
5270
|
pass.end();
|
|
4971
5271
|
},
|
|
4972
5272
|
highlightPass(encoder, args) {
|
|
4973
|
-
const slot = uniformSlot(`highlight:${args.
|
|
5273
|
+
const slot = uniformSlot(`highlight:${args.resourceId}`, 32);
|
|
4974
5274
|
const d = slot.data;
|
|
4975
5275
|
d[0] = args.viewportDevice[0];
|
|
4976
5276
|
d[1] = args.viewportDevice[1];
|
|
@@ -5008,7 +5308,7 @@ function createPassRunner(context) {
|
|
|
5008
5308
|
slot.write();
|
|
5009
5309
|
const pipeline = highlightPipeline(args.targetFormat);
|
|
5010
5310
|
const pass = encoder.beginRenderPass({
|
|
5011
|
-
label: `vitrea:pass:highlight:${args.
|
|
5311
|
+
label: `vitrea:pass:highlight:${args.resourceId}`,
|
|
5012
5312
|
...timed(PASS_LABEL.highlight),
|
|
5013
5313
|
colorAttachments: [{ view: args.target, loadOp: "load", storeOp: "store" }]
|
|
5014
5314
|
});
|
|
@@ -5020,7 +5320,8 @@ function createPassRunner(context) {
|
|
|
5020
5320
|
{ binding: 0, resource: { buffer: slot.buffer } },
|
|
5021
5321
|
{ binding: 1, resource: args.fields.field.createView() },
|
|
5022
5322
|
{ binding: 2, resource: args.fields.aux.createView() },
|
|
5023
|
-
{ binding: 3, resource: context.flatSampler }
|
|
5323
|
+
{ binding: 3, resource: context.flatSampler },
|
|
5324
|
+
{ binding: 4, resource: args.fields.presence.createView() }
|
|
5024
5325
|
]
|
|
5025
5326
|
}));
|
|
5026
5327
|
pass.draw(3);
|
|
@@ -5043,13 +5344,15 @@ function createPassRunner(context) {
|
|
|
5043
5344
|
setTimeline(next) {
|
|
5044
5345
|
timeline = next;
|
|
5045
5346
|
},
|
|
5046
|
-
forget(
|
|
5047
|
-
pool.release(poolKey.groupField(
|
|
5048
|
-
pool.release(poolKey.groupAux(
|
|
5049
|
-
pool.release(poolKey.groupAux2(
|
|
5050
|
-
|
|
5051
|
-
storages.
|
|
5052
|
-
|
|
5347
|
+
forget(resourceId) {
|
|
5348
|
+
pool.release(poolKey.groupField(resourceId));
|
|
5349
|
+
pool.release(poolKey.groupAux(resourceId));
|
|
5350
|
+
pool.release(poolKey.groupAux2(resourceId));
|
|
5351
|
+
pool.release(poolKey.groupPresence(resourceId));
|
|
5352
|
+
storages.get(resourceId)?.destroy();
|
|
5353
|
+
storages.delete(resourceId);
|
|
5354
|
+
for (const pass of ["field", "optics", "highlight"]) {
|
|
5355
|
+
const key = `${pass}:${resourceId}`;
|
|
5053
5356
|
uniforms.get(key)?.buffer.destroy();
|
|
5054
5357
|
uniforms.delete(key);
|
|
5055
5358
|
}
|
|
@@ -5710,6 +6013,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
5710
6013
|
let generations = 0;
|
|
5711
6014
|
let lastFrameTimeMs;
|
|
5712
6015
|
let targets;
|
|
6016
|
+
const planesDrawn = /* @__PURE__ */ new Set();
|
|
5713
6017
|
let pendingEncoder;
|
|
5714
6018
|
let pendingRebuilds = 0;
|
|
5715
6019
|
let pendingUnbuilt = [];
|
|
@@ -5831,7 +6135,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
5831
6135
|
return 0;
|
|
5832
6136
|
return heavyTapSigmaAtScale(material, viewport.devicePixelRatio) / Math.max(viewport.devicePixelRatio, 1e-3);
|
|
5833
6137
|
};
|
|
5834
|
-
const groupTintSeed = (input) => input.surfaces.find((surface) => surface
|
|
6138
|
+
const groupTintSeed = (input) => input.surfaces.find((surface) => drawsMaterial(surface) && (surface.tint?.strength ?? 0) > 0)?.tint?.color;
|
|
5835
6139
|
const stateOf = (input, resolution) => {
|
|
5836
6140
|
const resolved = resolution?.groups.find((group) => group.groupId === input.groupId);
|
|
5837
6141
|
if (resolved === void 0) {
|
|
@@ -5933,10 +6237,15 @@ function createWebGPURenderer(options = {}) {
|
|
|
5933
6237
|
];
|
|
5934
6238
|
const skipped = [];
|
|
5935
6239
|
let drawn = 0;
|
|
6240
|
+
planesDrawn.add(active.plane);
|
|
6241
|
+
const resourceOf = (groupId) => groupResourceId(active.plane, groupId);
|
|
6242
|
+
const releaseIdle = (groupId) => passes.forget(resourceOf(groupId));
|
|
5936
6243
|
for (const entry of groups.values()) {
|
|
5937
6244
|
const input = entry.input;
|
|
5938
|
-
if (input.surfaces.length === 0)
|
|
6245
|
+
if (input.surfaces.length === 0) {
|
|
6246
|
+
releaseIdle(input.groupId);
|
|
5939
6247
|
continue;
|
|
6248
|
+
}
|
|
5940
6249
|
const policy = resolution?.accessibility.material ?? accessibility;
|
|
5941
6250
|
let surfaces;
|
|
5942
6251
|
try {
|
|
@@ -5946,6 +6255,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
5946
6255
|
groupId: input.groupId,
|
|
5947
6256
|
reason: error instanceof Error ? error.message : String(error)
|
|
5948
6257
|
});
|
|
6258
|
+
releaseIdle(input.groupId);
|
|
5949
6259
|
continue;
|
|
5950
6260
|
}
|
|
5951
6261
|
const union = unionOf(input);
|
|
@@ -5958,15 +6268,17 @@ function createWebGPURenderer(options = {}) {
|
|
|
5958
6268
|
const shadowReachPx = outerShadowReachPx(shadow, reachOcclusion);
|
|
5959
6269
|
const snapped = snapRectToDevicePixels(groupFieldRect(surfaces, union, void 0, shadowReachPx), dpr);
|
|
5960
6270
|
const rectDevice = clipFieldRectToCanvas(snapped, dpr, viewportDevice);
|
|
5961
|
-
if (rectDevice === void 0)
|
|
6271
|
+
if (rectDevice === void 0) {
|
|
6272
|
+
releaseIdle(input.groupId);
|
|
5962
6273
|
continue;
|
|
6274
|
+
}
|
|
5963
6275
|
const surfaceRectDevice = shadowReachPx === 0 ? rectDevice : clipFieldRectToCanvas(snapRectToDevicePixels(groupFieldRect(surfaces, union), dpr), dpr, viewportDevice) ?? rectDevice;
|
|
5964
6276
|
const packed = packInstances(surfaces, [
|
|
5965
6277
|
rectDevice.x * cssPerDevice,
|
|
5966
6278
|
rectDevice.y * cssPerDevice
|
|
5967
6279
|
]);
|
|
5968
6280
|
const fields = passes.fieldPass(encoder, {
|
|
5969
|
-
|
|
6281
|
+
resourceId: resourceOf(input.groupId),
|
|
5970
6282
|
family: governor.knobs.fieldFamily,
|
|
5971
6283
|
rectDevice,
|
|
5972
6284
|
cssPerDevice,
|
|
@@ -5984,11 +6296,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
5984
6296
|
const pyramid = sourceId === void 0 ? void 0 : pyramids.resources(sourceId);
|
|
5985
6297
|
const adapt = sourceId === void 0 ? void 0 : adaptationFor(sourceId).values;
|
|
5986
6298
|
const nominalOptics = material.optics[variant];
|
|
5987
|
-
const optics = opticsUnderPolicy(
|
|
5988
|
-
...nominalOptics,
|
|
5989
|
-
tint: input.unsampledMaterial.tint,
|
|
5990
|
-
tintAlpha: input.unsampledMaterial.tintAlpha
|
|
5991
|
-
} : nominalOptics, policy, material);
|
|
6299
|
+
const optics = opticsUnderPolicy(nominalOptics, policy, material);
|
|
5992
6300
|
const backdropTone = [
|
|
5993
6301
|
material.backdropToneLow,
|
|
5994
6302
|
material.backdropToneHigh,
|
|
@@ -5999,7 +6307,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
5999
6307
|
const refraction = effectiveRefraction(accessibilityRefractionCap(policy), state.refraction);
|
|
6000
6308
|
const refractionScale = material.refractionScale[refraction];
|
|
6001
6309
|
passes.opticsPass(encoder, {
|
|
6002
|
-
|
|
6310
|
+
resourceId: resourceOf(input.groupId),
|
|
6003
6311
|
target: active.optics,
|
|
6004
6312
|
targetFormat: active.format,
|
|
6005
6313
|
rectDevice,
|
|
@@ -6043,6 +6351,8 @@ function createWebGPURenderer(options = {}) {
|
|
|
6043
6351
|
tintSeed: (policy.glass === "none" ? void 0 : groupTintSeed(input)) ?? optics.tint,
|
|
6044
6352
|
tintToneAdaptation: tintToneAdaptation(policy, material),
|
|
6045
6353
|
tintShade: [material.tintShadeDark, material.tintShadeLight, material.tintShadeStrength],
|
|
6354
|
+
tintChromaScale: material.tintChromaScale ?? 1,
|
|
6355
|
+
tintShadeCollapseRetention: material.tintShadeCollapseRetention ?? 0,
|
|
6046
6356
|
// The band's half-width is a per-scale reading since W23: the reference's
|
|
6047
6357
|
// rim narrows between the scales where vitrea's widened (claims §5.100
|
|
6048
6358
|
// §5). At dpr 1, and on any variant whose two anchors are equal, this is
|
|
@@ -6091,6 +6401,10 @@ function createWebGPURenderer(options = {}) {
|
|
|
6091
6401
|
// itself is already in the texture, so this pass only chooses which of
|
|
6092
6402
|
// two textures the deep sample comes from.
|
|
6093
6403
|
heavyTapEnabled: pyramid?.heavy !== void 0,
|
|
6404
|
+
...pyramid === void 0 && input.unsampledMaterial !== void 0 ? { domMaterial: {
|
|
6405
|
+
...input.unsampledMaterial,
|
|
6406
|
+
mode: input.backdropTone === void 0 ? 1 : 2
|
|
6407
|
+
} } : {},
|
|
6094
6408
|
shadowDepth: optics.shadowDepth,
|
|
6095
6409
|
shadowAlpha: optics.shadowAlpha,
|
|
6096
6410
|
// The size law's gains, per group (W2); the per-pixel factor they
|
|
@@ -6196,9 +6510,9 @@ function createWebGPURenderer(options = {}) {
|
|
|
6196
6510
|
shadow.thickOcclusionAt160
|
|
6197
6511
|
],
|
|
6198
6512
|
outerShadowLift: [
|
|
6199
|
-
//
|
|
6200
|
-
//
|
|
6201
|
-
pyramid === void 0 ||
|
|
6513
|
+
// A DOM layer can evaluate the lift at its stated tone, but not at
|
|
6514
|
+
// unknown exterior pixels. No tone still means no light to add.
|
|
6515
|
+
policy.glass === "none" || pyramid === void 0 && (input.unsampledMaterial === void 0 || input.backdropTone === void 0) ? 0 : shadow.liftAmplitude,
|
|
6202
6516
|
shadow.liftSpanMin,
|
|
6203
6517
|
shadow.liftSpanFull,
|
|
6204
6518
|
liftChainLod(shadow.liftBlurSigmaCss, pyramid)
|
|
@@ -6214,7 +6528,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
6214
6528
|
if (active.highlight !== void 0) {
|
|
6215
6529
|
const lead = surfaces.reduce((best, surface) => surface.channels.glow > best.channels.glow ? surface : best, surfaces[0]);
|
|
6216
6530
|
passes.highlightPass(encoder, {
|
|
6217
|
-
|
|
6531
|
+
resourceId: resourceOf(input.groupId),
|
|
6218
6532
|
target: active.highlight,
|
|
6219
6533
|
targetFormat: active.format,
|
|
6220
6534
|
// The surface's own rect, not the shadow's — see `surfaceRectDevice`.
|
|
@@ -6361,7 +6675,8 @@ function createWebGPURenderer(options = {}) {
|
|
|
6361
6675
|
},
|
|
6362
6676
|
removeGroup(groupId) {
|
|
6363
6677
|
groups.delete(groupId);
|
|
6364
|
-
|
|
6678
|
+
for (const plane of planesDrawn)
|
|
6679
|
+
runner?.forget(groupResourceId(plane, groupId));
|
|
6365
6680
|
},
|
|
6366
6681
|
setAccessibility(policy) {
|
|
6367
6682
|
accessibility = policy;
|
|
@@ -6377,7 +6692,8 @@ function createWebGPURenderer(options = {}) {
|
|
|
6377
6692
|
targets = {
|
|
6378
6693
|
optics: next.optics,
|
|
6379
6694
|
...next.highlight === void 0 ? {} : { highlight: next.highlight },
|
|
6380
|
-
format: next.format ?? OUTPUT_TEXTURE_FORMAT
|
|
6695
|
+
format: next.format ?? OUTPUT_TEXTURE_FORMAT,
|
|
6696
|
+
plane: next.plane ?? ""
|
|
6381
6697
|
};
|
|
6382
6698
|
},
|
|
6383
6699
|
drawFrame(args) {
|
|
@@ -6385,7 +6701,8 @@ function createWebGPURenderer(options = {}) {
|
|
|
6385
6701
|
targets = {
|
|
6386
6702
|
optics: args.optics,
|
|
6387
6703
|
...args.highlight === void 0 ? {} : { highlight: args.highlight },
|
|
6388
|
-
format: args.format ?? OUTPUT_TEXTURE_FORMAT
|
|
6704
|
+
format: args.format ?? OUTPUT_TEXTURE_FORMAT,
|
|
6705
|
+
plane: args.plane ?? ""
|
|
6389
6706
|
};
|
|
6390
6707
|
pyramids.beginFrame(args.frame.id);
|
|
6391
6708
|
pyramids.setTimeline(args.timing);
|
|
@@ -6503,5 +6820,5 @@ function createWebGPURenderer(options = {}) {
|
|
|
6503
6820
|
}
|
|
6504
6821
|
|
|
6505
6822
|
export { ADAPTIVE_LUMINANCE_HIGH, ADAPTIVE_LUMINANCE_LOW, ADAPTIVE_TINT_DARK, ADAPTIVE_TINT_LIGHT, ANALYSIS_DISPATCH, ANALYSIS_GRID, ANALYSIS_PASS_ID, ANALYSIS_STATS_FLOATS, ANALYSIS_TARGET_EXTENT, ANALYSIS_WORKGROUP, BACKDROP_ALPHA_MODES, BACKDROP_COLOR_SPACES, BACKDROP_KINDS, BACKDROP_PASS_ID, BACKDROP_TONE_HIGH, BACKDROP_TONE_LOW, BACKDROP_TONE_MAX, BACKDROP_TONE_SIZE_BIAS, CANVAS_FORMAT, CHAIN_SIGMA_AT_LEVEL_1, CROSS_CHECK_SHAPE_FLOATS, CROSS_CHECK_WORKGROUP, DEFAULT_MATERIAL_PROFILE, FAMILY_C_CROSS_CHECK, FIELD_PASS_ID, GOVERNOR_LADDER, HIGHLIGHT_PASS_ID, IDENTITY_FIT, IDLE_CHANNELS, INCREASED_OCCLUSION_LIFT, INSTANCE_BYTES, INSTANCE_FLOATS, LENS_AMOUNT_MAX, LENS_AMOUNT_PER_SPAN, LENS_EXTENT_GAIN, LENS_HEIGHT_MAX, LENS_HEIGHT_PER_SPAN, LENS_OVALIZATION, LENS_PROFILE_EXPONENT, LENS_REFRACTION_GAIN, LENS_SIZE_GAIN_MAX, LENS_THICKNESS_REFERENCE, LUMINANCE_WEIGHTS, MATERIAL_OPTICS, MATERIAL_VARIANTS, MAX_CHAIN_LEVELS, MIN_LEVEL_EXTENT, NOMINAL_GOVERNOR, NOMINAL_MATERIAL_POLICY, OPTICS_PASS_ID, OUTER_SHADOW, OUTER_SHADOW_THICK_SPANS, OUTER_SHADOW_THIN_L, OUTER_SHADOW_UNMEASURED_BACKDROP_LUMINANCE, OUTPUT_TEXTURE_FORMAT, PASS_LABEL, REFRACTION_LADDER, REFRACTION_SCALE, RENDERER_ERROR_CODES, RENDERER_PASS_IDS, RendererError, SIZE_OCCLUSION_GAIN, SIZE_SCATTER_FLOOR, SIZE_SCATTER_FLOOR_2X, SIZE_SCATTER_GAIN_FAR_2X, SIZE_SCATTER_GAIN_MAX, SIZE_SCATTER_GAIN_MAX_2X, SIZE_SCATTER_RAMP_REACH_1X_PX, SIZE_SCATTER_RAMP_REACH_2X_PX, SIZE_SCATTER_RAMP_START_FAR_1X, SIZE_SCATTER_RAMP_START_FAR_2X, SIZE_SCATTER_RAMP_START_THICK_1X, SIZE_SCATTER_RAMP_START_THICK_2X, SIZE_SCATTER_RAMP_START_THIN_1X, SIZE_SCATTER_RAMP_START_THIN_2X, SIZE_SCATTER_SPAN_MAX, SIZE_SCATTER_SPAN_MAX_2X, SIZE_SHADOW_GAIN_MAX, SIZE_SPAN_MAX, SIZE_SPAN_MIN, SRGB_ENCODING_EXPONENT, SUPPORTED_APP_TEXTURE_FORMATS, WGSL_ANALYSIS_PASS, WGSL_CROSS_CHECK_PASS, WGSL_DOWNSAMPLE_PASS, WGSL_FIELD_KERNELS, WGSL_FIELD_PASS, WGSL_FIELD_SAMPLE, WGSL_HIGHLIGHT_PASS, WGSL_IMPORT_PASS, WGSL_INSTANCE_STRUCT, WGSL_OPTICS_PASS, WGSL_PRELUDE, WGSL_RSUPN_GRAD, WGSL_RSUP_GRAD, WGSL_SMOOTH_UNION, WORKING_TEXTURE_FORMAT, ZERO_STATS, accessibilityRefractionCap, adaptationStrength, adaptedTintAlpha, adaptedTintColour, adaptiveTint, allShaderSource, alphaNormalisationMode, analysisModule, backdropFit, backdropToneAdaptation, backdropToneResponse, backdropToneSizeBiasUnderPolicy, backdropToneSolveWeight, backdropToneUnderPolicy, bodyBlurPlan, chainModule, clipFieldRectToCanvas, collapsedRimUnderPolicy, coverFit, createAdaptationState, createAppTextureProvider, createCopyProvider, createDeviceHost, createGovernor, createGpuContext, createGradientProvider, createPassRunner, createPipelineCache, createPyramidStore, createRebuildLedger, createStorageSlot, createTexturePool, createTimingCollector, createUniformSlot, createVideoProvider, createWebGPURenderer, crossCheckKernelModule, displayP3ToSrgbLinear, effectiveRefraction, encodeOutput, encodeOutputBytes, fieldModule, fieldPassSource, groupFieldRect, heavyTapSigmaAtScale, highlightModule, importColorMatrix, importModule, importPassSource, isUsablePlacement, lensAmountBasePx, lensDepthPx, lensDirection, lensDisplacementPx, lensExtentPx, lensHeightBasePx, lensMagnitudePx, lensOvalizationAt, lensSizeGain, lensSizeGainFromThickness, linearGradientStops, linearToSrgb, linearToSrgbChannel, occlusionAlphaUnderPolicy, opticsModule, opticsUnderPolicy, outerShadowAlpha, outerShadowFalloff, outerShadowLiftRise, outerShadowOcclusionAt, outerShadowReachPx, outerShadowThickOcclusion, outerShadowThinOcclusion, outerShadowUnderPolicy, packInstances, pipelineKey, placementFit, planPyramid, poolKey, readbackDue, refractionRank, relativeLuminance, rendererError, resolveSurfaces, rimAlongSideFactor, rimAlongSideField, samePlacement, scatterDeepThickness, scatterFloorAtScale, scatterGainAt, scatterGainAtScale, scatterGainFarAtScale, scatterHeavyShareThickAtScale, scatterRampAreaMean, scatterRampReachDevicePx, scatterRampStart, scatterSharpShare, scatterSpanMaxAtScale, scatterThickness, shadowDepthPx, sizeOcclusionAlpha, sizeOcclusionAlphaAt, sizeOuterShadowOcclusion, sizeOuterShadowOcclusionAt, sizeScatterSigma, sizeScatterSigmaAt, sizeShadowDepth, sizeShadowDepthAt, sizeThickness, sizeThicknessUnderPolicy, sizeToneLevelFar, snapRectToDevicePixels, srgbToLinear, srgbToLinearChannel, statsFromBuffer, supportsTimestamps, texelsPerCssPx, tintShade, tintShadeLayer, tintToneAdaptation, tintedMaterialColour, validateAppTexture, withMaterialOverrides };
|
|
6506
|
-
//# sourceMappingURL=dist-
|
|
6507
|
-
//# sourceMappingURL=dist-
|
|
6823
|
+
//# sourceMappingURL=dist-C43H3RKY.js.map
|
|
6824
|
+
//# sourceMappingURL=dist-C43H3RKY.js.map
|