@vitreajs/vitrea 0.13.0 → 0.15.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/{dist-2V7EQHSR.js → dist-PT4PUS4K.js} +343 -33
- package/dist/dist-PT4PUS4K.js.map +1 -0
- package/dist/index.d.ts +314 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/dist-2V7EQHSR.js.map +0 -1
|
@@ -414,8 +414,64 @@ var DEFAULT_MATERIAL_PROFILE = {
|
|
|
414
414
|
*
|
|
415
415
|
* The `clear` variant keeps 0 below: no scene on either bed declares it, so
|
|
416
416
|
* it has no rows and nothing to be fitted on (C9a §6.2).
|
|
417
|
+
*
|
|
418
|
+
* RE-FITTED 1.15 → 0.85 (W25 G3b, on the parent's ruling; claims §5.115,
|
|
419
|
+
* W25 Decision Log 6), JOINTLY with `rimAlongSideSlope` below and not
|
|
420
|
+
* separately, because the two multiply the same rim amplitude and both peak
|
|
421
|
+
* on this same diagonal. W24 fitted this exponent with the position term
|
|
422
|
+
* ABSENT, over 285 bins that include the corner arcs, so it absorbed part of
|
|
423
|
+
* a grading that is not a function of the normal at all — and W25 G0's
|
|
424
|
+
* along-side reader, which walks only the STRAIGHT part of a side where this
|
|
425
|
+
* factor is exactly 1, could not see the overlap from its side either.
|
|
426
|
+
* W25 G3's dry run measured the consequence: at slope 0.45 under exponent
|
|
427
|
+
* 1.15 the NW and SE bins of the 1x light `dark-solid__rrect-md` went 0.142
|
|
428
|
+
* → 0.203 against a reference of 0.122, and the thick solids' mean bin error
|
|
429
|
+
* rose on 26 rows of 28.
|
|
430
|
+
*
|
|
431
|
+
* The joint fit is a rendered GRID over the plane — 46 points, each a real
|
|
432
|
+
* render of the solid rows of all four standard profiles, read by W24's
|
|
433
|
+
* angular reader and W25's along-side reader together
|
|
434
|
+
* (`results/2026-09-09-w25-thick-span-composite/g3/g3b-fit.txt`). The pair
|
|
435
|
+
* below is the joint objective's minimum among the pairs that keep the thick
|
|
436
|
+
* solids' angular error at or under the 0.13.0 bed's — the ruling's own
|
|
437
|
+
* acceptance condition — AND that leave every cell of the bed measurable:
|
|
438
|
+
* thick bin error 0.17527 → 0.17208 and thick range error 0.43269 → 0.37472,
|
|
439
|
+
* on 16 rows improving against 12. The objective's own minimum over the
|
|
440
|
+
* allowed set is (0.70, 0.15), and it is refused for a reason no metric
|
|
441
|
+
* carries: at that pair the collapsed `dark-solid__capsule-button` loses its
|
|
442
|
+
* contour on the GPU tier at 1x in both schemes — the capsule's band is
|
|
443
|
+
* entirely corner arc, which is where both of these factors dim it, and the
|
|
444
|
+
* extractor reads a 0.00 px contour and drops two calibration cells out of
|
|
445
|
+
* the bed. A change that narrows the instrument is not a fidelity gain.
|
|
446
|
+
*/
|
|
447
|
+
rimLitExponent: 0.85,
|
|
448
|
+
/*
|
|
449
|
+
* W25's along-side field, FITTED (claims §5.113 and §5.115; W25 Decision
|
|
450
|
+
* Log 3 (c), landed at G3's declaration).
|
|
451
|
+
*
|
|
452
|
+
* Its own readers want more of it: G2 fitted 0.45 on the 64 straight sides
|
|
453
|
+
* of the two 1x probe grids' flat solids and G3 re-fitted 0.425–0.479 on the
|
|
454
|
+
* probe set's 64 sides at both scales in both schemes, and at 0.45 the
|
|
455
|
+
* corner-to-corner range reaches 0.743 of the reference's against 0.227
|
|
456
|
+
* without it. What the along-side reader cannot see is the corner ARCS,
|
|
457
|
+
* where this factor multiplies a rim that `rimLitExponent` has already
|
|
458
|
+
* brightened on the same diagonal — so the value here is not that fit's, it
|
|
459
|
+
* is the JOINT one (W25 G3b; W25 Decision Log 6): the minimum over a
|
|
460
|
+
* rendered grid of the two readers' errors together, among the pairs that
|
|
461
|
+
* keep the thick solids' angular error at or under the 0.13.0 bed's.
|
|
462
|
+
*
|
|
463
|
+
* At (0.70, 0.15) the thick solids' bin error falls 0.17527 → 0.17000 and
|
|
464
|
+
* their range error 0.43269 → 0.34919 — a fifth of the grading, where 0.45
|
|
465
|
+
* under the old exponent bought three quarters of it and cost half again as
|
|
466
|
+
* much bin error. The remaining four fifths are not this constant's to buy:
|
|
467
|
+
* the arcs' amplitude is W23's rim law, fitted on the straight spans both of
|
|
468
|
+
* these factors leave alone, and until it moves the two of them are trading
|
|
469
|
+
* against each other rather than against Apple.
|
|
470
|
+
*
|
|
471
|
+
* The `clear` variant keeps 0 below, as the lit edge does: no scene on
|
|
472
|
+
* either bed declares it, so it has no rows (C9a §6.2).
|
|
417
473
|
*/
|
|
418
|
-
|
|
474
|
+
rimAlongSideSlope: 0.1,
|
|
419
475
|
shadowDepth: 0.35,
|
|
420
476
|
/*
|
|
421
477
|
* REFITTED 0.55 → 0.05 (2026-08-31), and it is the largest single
|
|
@@ -450,6 +506,8 @@ var DEFAULT_MATERIAL_PROFILE = {
|
|
|
450
506
|
// No scene declares this variant, so the lit edge has no rows here either
|
|
451
507
|
// and the factor stays inert (C9a §6.2, as `rimLevelGain` above).
|
|
452
508
|
rimLitExponent: 0,
|
|
509
|
+
// Nor does the along-side field have rows here, for the same reason.
|
|
510
|
+
rimAlongSideSlope: 0,
|
|
453
511
|
shadowDepth: 0.22,
|
|
454
512
|
shadowAlpha: 0.4,
|
|
455
513
|
highlight: srgbToLinear(SRGB_WHITE_TINT)
|
|
@@ -636,6 +694,41 @@ var DEFAULT_MATERIAL_PROFILE = {
|
|
|
636
694
|
sizeScatterRampStartFar2x: 0.21,
|
|
637
695
|
sizeScatterRampReach1xPx: 80,
|
|
638
696
|
sizeScatterRampReach2xPx: 100,
|
|
697
|
+
// W25's three mechanisms, all INERT at the defaults (claims §5.113; W25
|
|
698
|
+
// Decision Log 3). The heavy share's thick lift and the level term above the
|
|
699
|
+
// knee are zero, so `kDeep` and the tone response's blend are the curves W11c
|
|
700
|
+
// and W9 fitted, to the bit; the along-side field's slope lives on the optics
|
|
701
|
+
// beside `rimLitExponent` and is zero there. G2 fits them and G3 declares
|
|
702
|
+
// them; what the fits read is recorded in
|
|
703
|
+
// `results/2026-09-09-w25-thick-span-composite/g2/`.
|
|
704
|
+
sizeScatterHeavyShareThick1x: 0,
|
|
705
|
+
sizeScatterHeavyShareThick2x: 0,
|
|
706
|
+
sizeToneLevelFar: 0,
|
|
707
|
+
// The heavy blur, FITTED (W26; claims §5.121 for the identification and §5.122
|
|
708
|
+
// for the fit; W26 Decision Log 6 (a)). Apple's heavy width is 8.6–9.5 device px
|
|
709
|
+
// at BOTH scales, read by the family reader — the one instrument in this wave
|
|
710
|
+
// that passed a control, reproducing vitrea's own drawn width to 0.6 % — and
|
|
711
|
+
// inverted through a ladder whose slope is 0.995–1.111 at an rms of 0.03–0.06
|
|
712
|
+
// device px. What the 0.14.0 material drew at dpr 1 was `CHAIN_LEVEL_SIGMA[4]` =
|
|
713
|
+
// 13.418, the pyramid's LAST level, because `scatterLod` was clamped there: half
|
|
714
|
+
// again too wide, and the share the two previous waves tried to raise was already
|
|
715
|
+
// right to within 0.07. The reference asks 9.48 / 8.63 / 9.19 at dpr 1 (spread
|
|
716
|
+
// 9.8 %, so one number serves both spans) and 8.13 / 9.79 / 8.37 at dpr 2 (spread
|
|
717
|
+
// 20.4 %, so one number does not — the 1.66 device px between spans 96 and 160 is
|
|
718
|
+
// the grading `sizeScatterGainFar2x` used to carry, and one width per source
|
|
719
|
+
// cannot; W26 Decision Log 2 (f) chose that knowingly). Nine is within 1.1 % of
|
|
720
|
+
// the 1x mean and 0.4 % of the 2x light pair's, and it takes
|
|
721
|
+
// |log(read / reference)| from 0.275 to 0.069 over six cells.
|
|
722
|
+
//
|
|
723
|
+
// THE MECHANISM HAS NO SMALL VALUES (W26 Decision Log 6 (c)). `pyramid.ts` builds
|
|
724
|
+
// the heavy texture whenever `heavySigmaCss > 0`, and at σ 0.001 `heavyTapPlan`
|
|
725
|
+
// selects chain level 0 with a residual of a thousandth of a texel — which makes
|
|
726
|
+
// the deep sample the RAW backdrop and moves every 2x row. So 0.001 is not
|
|
727
|
+
// "almost off"; it is the opposite of off. The inert value is exactly 0, and
|
|
728
|
+
// neither anchor may ever carry a small non-zero. The domain is 0 or at least the
|
|
729
|
+
// chain's level-1 width, and the tracker carries the floor that would close it.
|
|
730
|
+
sizeHeavyTapSigma: 9,
|
|
731
|
+
sizeHeavyTapSigma2x: 9,
|
|
639
732
|
sizeOcclusionGain: 0.05,
|
|
640
733
|
sizeShadowGainMax: 1,
|
|
641
734
|
/*
|
|
@@ -1094,6 +1187,11 @@ function withMaterialOverrides(base, patch) {
|
|
|
1094
1187
|
sizeScatterRampStartFar2x: patch.sizeScatterRampStartFar2x ?? base.sizeScatterRampStartFar2x,
|
|
1095
1188
|
sizeScatterRampReach1xPx: patch.sizeScatterRampReach1xPx ?? base.sizeScatterRampReach1xPx,
|
|
1096
1189
|
sizeScatterRampReach2xPx: patch.sizeScatterRampReach2xPx ?? base.sizeScatterRampReach2xPx,
|
|
1190
|
+
sizeScatterHeavyShareThick1x: patch.sizeScatterHeavyShareThick1x ?? base.sizeScatterHeavyShareThick1x,
|
|
1191
|
+
sizeScatterHeavyShareThick2x: patch.sizeScatterHeavyShareThick2x ?? base.sizeScatterHeavyShareThick2x,
|
|
1192
|
+
sizeToneLevelFar: patch.sizeToneLevelFar ?? base.sizeToneLevelFar,
|
|
1193
|
+
sizeHeavyTapSigma: patch.sizeHeavyTapSigma ?? base.sizeHeavyTapSigma,
|
|
1194
|
+
sizeHeavyTapSigma2x: patch.sizeHeavyTapSigma2x ?? base.sizeHeavyTapSigma2x,
|
|
1097
1195
|
sizeOcclusionGain: patch.sizeOcclusionGain ?? base.sizeOcclusionGain,
|
|
1098
1196
|
sizeShadowGainMax: patch.sizeShadowGainMax ?? base.sizeShadowGainMax,
|
|
1099
1197
|
lensRefractionGain: patch.lensRefractionGain ?? base.lensRefractionGain,
|
|
@@ -1157,7 +1255,11 @@ function opticsUnderPolicy(optics, policy, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
|
1157
1255
|
// And the lit edge stands down with it (W24): a border a preference asked
|
|
1158
1256
|
// for is one brightness the whole way round, and a directional factor
|
|
1159
1257
|
// would take it to nothing on two of its four corners.
|
|
1160
|
-
rimLitExponent: 0
|
|
1258
|
+
rimLitExponent: 0,
|
|
1259
|
+
// The along-side field stands down for the same reason (W25): a border a
|
|
1260
|
+
// preference asked for is one brightness the whole way round, and a
|
|
1261
|
+
// position field would grade it corner to corner.
|
|
1262
|
+
rimAlongSideSlope: 0
|
|
1161
1263
|
};
|
|
1162
1264
|
}
|
|
1163
1265
|
return next;
|
|
@@ -1253,7 +1355,7 @@ var smoothstep = (edge0, edge1, x) => {
|
|
|
1253
1355
|
function sizeThickness(spanPx, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
1254
1356
|
return smoothstep(profile.sizeSpanMin, profile.sizeSpanMax, spanPx);
|
|
1255
1357
|
}
|
|
1256
|
-
function backdropToneResponse(encodedInput, thickness, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
1358
|
+
function backdropToneResponse(encodedInput, thickness, profile = DEFAULT_MATERIAL_PROFILE, levelFar = 0) {
|
|
1257
1359
|
const xs = profile.backdropToneAnchorX;
|
|
1258
1360
|
const f = smoothstep(0, 1, thickness);
|
|
1259
1361
|
const ys = [0, 1, 2].map((i) => (profile.backdropToneResponseThin[i] ?? 0) + ((profile.backdropToneResponseThick[i] ?? 0) - (profile.backdropToneResponseThin[i] ?? 0)) * f);
|
|
@@ -1270,7 +1372,7 @@ function backdropToneResponse(encodedInput, thickness, profile = DEFAULT_MATERIA
|
|
|
1270
1372
|
const y1 = seg === 0 ? ys[1] : ys[2];
|
|
1271
1373
|
const s0 = seg === 0 ? d0 : m1;
|
|
1272
1374
|
const s1 = seg === 0 ? m1 : d1;
|
|
1273
|
-
return y0 * (1 + 2 * t) * (1 - t) * (1 - t) + s0 * h * t * (1 - t) * (1 - t) + y1 * t * t * (3 - 2 * t) + s1 * h * t * t * (t - 1);
|
|
1375
|
+
return y0 * (1 + 2 * t) * (1 - t) * (1 - t) + s0 * h * t * (1 - t) * (1 - t) + y1 * t * t * (3 - 2 * t) + s1 * h * t * t * (t - 1) + levelFar;
|
|
1274
1376
|
}
|
|
1275
1377
|
function backdropToneSolveWeight(encodedInput, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
1276
1378
|
const anchor = profile.backdropToneAnchorX[0];
|
|
@@ -1370,7 +1472,25 @@ function scatterSpanMaxAtScale(profile = DEFAULT_MATERIAL_PROFILE, devicePixelRa
|
|
|
1370
1472
|
}
|
|
1371
1473
|
function scatterDeepThickness(spanPx, profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1) {
|
|
1372
1474
|
const floor = scatterFloorAtScale(profile, devicePixelRatio);
|
|
1373
|
-
|
|
1475
|
+
const lift = scatterHeavyShareThickAtScale(profile, devicePixelRatio) * sizeThickness(spanPx, profile);
|
|
1476
|
+
return clampUnit(floor + (1 - floor) * smoothstep(profile.sizeSpanMin, scatterSpanMaxAtScale(profile, devicePixelRatio), spanPx) + lift);
|
|
1477
|
+
}
|
|
1478
|
+
function scatterHeavyShareThickAtScale(profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1) {
|
|
1479
|
+
return rampAtScale(profile.sizeScatterHeavyShareThick1x, profile.sizeScatterHeavyShareThick2x, devicePixelRatio);
|
|
1480
|
+
}
|
|
1481
|
+
function heavyTapSigmaAtScale(profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1) {
|
|
1482
|
+
return rampAtScale(profile.sizeHeavyTapSigma, profile.sizeHeavyTapSigma2x, devicePixelRatio);
|
|
1483
|
+
}
|
|
1484
|
+
function sizeToneLevelFar(spanPx, profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1, fold = 1) {
|
|
1485
|
+
return profile.sizeToneLevelFar * smoothstep(profile.sizeSpanMax, scatterSpanMaxAtScale(profile, devicePixelRatio), spanPx) * fold;
|
|
1486
|
+
}
|
|
1487
|
+
function rimAlongSideField(offset, half) {
|
|
1488
|
+
const x = offset[0] / Math.max(Math.abs(half[0]), 1e-6);
|
|
1489
|
+
const y = offset[1] / Math.max(Math.abs(half[1]), 1e-6);
|
|
1490
|
+
return Math.max(-1, Math.min(1, x * y));
|
|
1491
|
+
}
|
|
1492
|
+
function rimAlongSideFactor(field, spanPx, optics, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
1493
|
+
return Math.max(0, 1 + optics.rimAlongSideSlope * sizeThickness(spanPx, profile) * field);
|
|
1374
1494
|
}
|
|
1375
1495
|
function scatterSharpShare(uDevicePx, devicePixelRatio, profile = DEFAULT_MATERIAL_PROFILE, spanPx = 0) {
|
|
1376
1496
|
const deepSharp = 1 - scatterDeepThickness(spanPx, profile, devicePixelRatio);
|
|
@@ -2374,6 +2494,9 @@ var poolKey = {
|
|
|
2374
2494
|
backdropChainScratch: (sourceId, level) => `backdrop:${sourceId}:chain-scratch:${level}`,
|
|
2375
2495
|
backdropBody: (sourceId) => `backdrop:${sourceId}:body`,
|
|
2376
2496
|
backdropBodyScratch: (sourceId) => `backdrop:${sourceId}:body-scratch`,
|
|
2497
|
+
/** The heavy blur and its scratch (W26) — the body's pair, one width deeper. */
|
|
2498
|
+
backdropHeavy: (sourceId) => `backdrop:${sourceId}:heavy`,
|
|
2499
|
+
backdropHeavyScratch: (sourceId) => `backdrop:${sourceId}:heavy-scratch`,
|
|
2377
2500
|
backdropUpload: (sourceId) => `backdrop:${sourceId}:upload`,
|
|
2378
2501
|
groupField: (groupId) => `group:${groupId}:field`,
|
|
2379
2502
|
groupAux: (groupId) => `group:${groupId}:aux`,
|
|
@@ -3442,8 +3565,21 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
|
|
|
3442
3565
|
/// the lit edge (W24): the axis the rim's directional factor is symmetric
|
|
3443
3566
|
/// about, unit, viewport coordinates with y down (xy), and the factor's
|
|
3444
3567
|
/// exponent (z) \u2014 0 leaves the factor at 1 for every normal and the rim
|
|
3445
|
-
/// exactly as W23 left it. (w) is
|
|
3568
|
+
/// exactly as W23 left it. (w) is the along-side field's slope (W25), in the
|
|
3569
|
+
/// slot W24 left free \u2014 0 leaves the factor at 1 at every position.
|
|
3446
3570
|
rimLit : vec4f,
|
|
3571
|
+
/// the thick-span composite (W25; claims 5.113): the heavy share's thick-end
|
|
3572
|
+
/// lift on 'sizeThickness', resolved at this group's device ratio (x), and the
|
|
3573
|
+
/// level term's gain above the thickness knee (y). Both 0 on the landed
|
|
3574
|
+
/// material, so both terms are one multiplication by zero. (z) and (w) free.
|
|
3575
|
+
thickSpan : vec4f,
|
|
3576
|
+
/// the heavy blur's enable (W26; 'MaterialProfile.sizeHeavyTapSigma', and the
|
|
3577
|
+
/// measured cause in claims 5.116 section 2) \u2014 1 where this group's source
|
|
3578
|
+
/// carries a heavy texture, 0 where it does not. The WIDTH is not here: the
|
|
3579
|
+
/// pyramid blurred it into 'backdropHeavy' before any group was drawn, so all
|
|
3580
|
+
/// this pass decides is which of two textures the deep sample comes from.
|
|
3581
|
+
/// (y) (z) (w) free.
|
|
3582
|
+
heavyTap : vec4f,
|
|
3447
3583
|
};
|
|
3448
3584
|
|
|
3449
3585
|
@group(0) @binding(0) var<uniform> ou : OpticsUniforms;
|
|
@@ -3457,6 +3593,11 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
|
|
|
3457
3593
|
/// centre (xy) and its half-extents (zw), group-local CSS px \u2014 the lens's oval.
|
|
3458
3594
|
@group(0) @binding(7) var aux2Texture : texture_2d<f32>;
|
|
3459
3595
|
|
|
3596
|
+
/// The heavy blur (W26) \u2014 the backdrop taken to the profile's heavy width by the
|
|
3597
|
+
/// pyramid's own separable passes, at the extent of the chain level it was built
|
|
3598
|
+
/// from. Bound at every draw; read only where 'heavyTap.x' says there is one.
|
|
3599
|
+
@group(0) @binding(8) var backdropHeavy : texture_2d<f32>;
|
|
3600
|
+
|
|
3460
3601
|
/// One encoded sRGB channel from a linear one \u2014 the space the backdrop tone
|
|
3461
3602
|
/// response's anchors live in (W9). Mirrors material.ts's 'linearToSrgbChannel'.
|
|
3462
3603
|
fn srgb_encode(c : f32) -> f32 {
|
|
@@ -3468,7 +3609,7 @@ fn srgb_encode(c : f32) -> f32 {
|
|
|
3468
3609
|
/// (Fritsch\u2013Carlson) interpolation through the three anchors, clamped to their
|
|
3469
3610
|
/// span; smoothstep between the thin and thick rows. Mirrors material.ts's
|
|
3470
3611
|
/// 'backdropToneResponse' term for term \u2014 the constants are authored there.
|
|
3471
|
-
fn tone_response(x : f32, sizeK : f32) -> f32 {
|
|
3612
|
+
fn tone_response(x : f32, sizeK : f32, levelFar : f32) -> f32 {
|
|
3472
3613
|
let f = sizeK * sizeK * (3.0 - 2.0 * sizeK);
|
|
3473
3614
|
let ys = mix(ou.toneRowThin.xyz, ou.toneRowThick.xyz, vec3f(f));
|
|
3474
3615
|
let xs = ou.toneAnchor.xyz;
|
|
@@ -3487,10 +3628,18 @@ fn tone_response(x : f32, sizeK : f32) -> f32 {
|
|
|
3487
3628
|
h = h1; t = (xc - xs.y) / h1;
|
|
3488
3629
|
y0 = ys.y; y1 = ys.z; s0 = m1; s1 = d1;
|
|
3489
3630
|
}
|
|
3631
|
+
// 'levelFar' is W25's level term above the thickness knee (claims 5.113; W25
|
|
3632
|
+
// Decision Log 3 (b)) - an OFFSET on the settled level this curve returns, in
|
|
3633
|
+
// its own encoded units, and not a continuation of the thin-to-thick blend
|
|
3634
|
+
// above. The rows chose the shape: the residual against vitrea above span 96
|
|
3635
|
+
// is backdrop-INDEPENDENT where the blend's direction is different at every
|
|
3636
|
+
// backdrop level (G2 'fit-level.txt'). Exactly 0 at and below sizeSpanMax by
|
|
3637
|
+
// the shape of its span curve, and 0 at every span on the landed material.
|
|
3490
3638
|
return y0 * (1.0 + 2.0 * t) * (1.0 - t) * (1.0 - t)
|
|
3491
3639
|
+ s0 * h * t * (1.0 - t) * (1.0 - t)
|
|
3492
3640
|
+ y1 * t * t * (3.0 - 2.0 * t)
|
|
3493
|
-
+ s1 * h * t * t * (t - 1.0)
|
|
3641
|
+
+ s1 * h * t * t * (t - 1.0)
|
|
3642
|
+
+ levelFar;
|
|
3494
3643
|
}
|
|
3495
3644
|
|
|
3496
3645
|
/// Rim proximity: 1 exactly on the contour, falling to 0 by 'width' on either
|
|
@@ -3822,11 +3971,27 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
3822
3971
|
*/
|
|
3823
3972
|
let scatterFloor = clamp(ou.scatter.x, 0.0, 1.0);
|
|
3824
3973
|
let deepT = clamp((span - ou.scatter.z) / max(ou.lensOval.w - ou.scatter.z, 1e-6), 0.0, 1.0);
|
|
3825
|
-
|
|
3974
|
+
// W25's share law (claims 5.113; W25 Decision Log 3 (a)): the thick end's lift
|
|
3975
|
+
// on the material's own thin/thick curve, ADDED to the W11c span curve rather
|
|
3976
|
+
// than replacing it, so the thin end keeps the constants it was fitted with and
|
|
3977
|
+
// 'sizeThick' being exactly 0 at sizeSpanMin makes the thin controls
|
|
3978
|
+
// bit-identical whatever the lift says.
|
|
3979
|
+
let kDeep = clamp(
|
|
3980
|
+
scatterFloor + (1.0 - scatterFloor) * deepT * deepT * (3.0 - 2.0 * deepT)
|
|
3981
|
+
+ ou.thickSpan.x * sizeThick,
|
|
3982
|
+
0.0,
|
|
3983
|
+
1.0,
|
|
3984
|
+
);
|
|
3826
3985
|
let sDeep = 1.0 - kDeep;
|
|
3827
3986
|
let rampT = max(1.0 - max(-d, 0.0) / max(ou.lensOval.z, 1e-6), 0.0);
|
|
3828
3987
|
let farT = clamp((span - ou.scatter.w) / max(ou.lensOval.w - ou.scatter.w, 1e-6), 0.0, 1.0);
|
|
3829
3988
|
let farS = farT * farT * (3.0 - 2.0 * farT);
|
|
3989
|
+
// W25's level term rides the very same curve (claims 5.113): one span
|
|
3990
|
+
// statistic, now read three times \u2014 the ramp's far decline, the 2x heavy
|
|
3991
|
+
// gain's rise and the body's level above the knee. Folded like the response it
|
|
3992
|
+
// extends, because a preference that has stopped the material transmitting has
|
|
3993
|
+
// no thin-to-thick step left to continue.
|
|
3994
|
+
let toneLevelFar = ou.thickSpan.y * farS * fold;
|
|
3830
3995
|
let rampStart = ou.scatter.y + (ou.shadowSize.z - ou.scatter.y) * sizeThick
|
|
3831
3996
|
+ (ou.shadowThick.w - ou.shadowSize.z) * farS;
|
|
3832
3997
|
let sharpShare = clamp(sDeep + max(rampStart - sDeep, 0.0) * rampT, 0.0, 1.0);
|
|
@@ -3894,6 +4059,14 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
3894
4059
|
// along 'farS' \u2014 the very smoothstep the ramp's far anchor already declines
|
|
3895
4060
|
// along, computed above with the share. One curve, two quantities.
|
|
3896
4061
|
let gainEff = ou.size.x + (ou.shadowSize.w - ou.size.x) * farS;
|
|
4062
|
+
/*
|
|
4063
|
+
* Everything above this point grades the GAIN, and claims \xA75.116 \xA72 measured
|
|
4064
|
+
* that the gain stops being a width: 'ou.lens.w' is the chain's own last level,
|
|
4065
|
+
* 4 on the bed's 320 \xD7 200 backdrop, and 'ou.size.w + log2(8)' is 4.06, so the
|
|
4066
|
+
* clamp has been absorbing the gain since the material was fitted. This is the
|
|
4067
|
+
* path a material that names no heavy width still takes, and the heavy blur
|
|
4068
|
+
* below is what replaces it where one is named.
|
|
4069
|
+
*/
|
|
3897
4070
|
let scatterLod = clamp(ou.size.w + log2(max(gainEff, 1e-4)), 0.0, ou.lens.w);
|
|
3898
4071
|
|
|
3899
4072
|
var backdrop = vec3f(0.0);
|
|
@@ -3901,7 +4074,32 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
3901
4074
|
// Both components at the refracted position (W11c G2): the band and the
|
|
3902
4075
|
// interior are one body, and the displacement alone is the lens.
|
|
3903
4076
|
let bodySample = textureSampleLevel(backdropBody, backdropSampler, refractedUv, 0.0);
|
|
3904
|
-
|
|
4077
|
+
var scatterSample = textureSampleLevel(backdropChain, backdropSampler, refractedUv, scatterLod);
|
|
4078
|
+
/*
|
|
4079
|
+
* The heavy blur (W26). Where the profile named a heavy width the deep sample
|
|
4080
|
+
* is not a chain level at all: the pyramid took the chain level whose own
|
|
4081
|
+
* blur is nearest below the target up to the target exactly, with the two
|
|
4082
|
+
* separable passes it already runs for the body, and this pass reads the
|
|
4083
|
+
* result at the same refracted uv the chain tap used.
|
|
4084
|
+
*
|
|
4085
|
+
* That is the whole mechanism, and it is here rather than in a grid of taps
|
|
4086
|
+
* for two measured reasons. The width the chain can reach is bounded by
|
|
4087
|
+
* 'chainMaxLod' \u2014 the pyramid stops when a level's shorter side would fall
|
|
4088
|
+
* under eight texels \u2014 so at dpr 1 on a 320 x 200 backdrop the deep sample
|
|
4089
|
+
* saturates at 13.4 device px against the reference's 19.5, and a residual
|
|
4090
|
+
* Gaussian is the only thing that carries the octave the chain does not have
|
|
4091
|
+
* (claims \xA75.119). And a 9 x 9 grid at the tap costs +1.1 ms on the optics
|
|
4092
|
+
* pass against 0.070 ms for the separable pair (W26 Decision Log 2 (b)).
|
|
4093
|
+
*
|
|
4094
|
+
* The price is that the width is one per SOURCE, not one per pixel: the
|
|
4095
|
+
* texture is built before any group is drawn, so the span grading the gain
|
|
4096
|
+
* carried above no longer reaches the deep sample where this is on. The
|
|
4097
|
+
* reference's heavy width does not grade with the span at 1x (claims
|
|
4098
|
+
* \xA75.113 \xA74), which is what says the material can afford it.
|
|
4099
|
+
*/
|
|
4100
|
+
if (ou.heavyTap.x > 0.5) {
|
|
4101
|
+
scatterSample = textureSampleLevel(backdropHeavy, backdropSampler, refractedUv, 0.0);
|
|
4102
|
+
}
|
|
3905
4103
|
// Premultiplied linear in, straight colour out: the material composites over
|
|
3906
4104
|
// whatever is behind it, so a partially transparent backdrop must not darken
|
|
3907
4105
|
// the glass.
|
|
@@ -3997,7 +4195,7 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
3997
4195
|
let authority =
|
|
3998
4196
|
smoothstep(anchor * 0.5, anchor, encodedInput) * clamp(ou.toneRowThin.w, 0.0, 1.0);
|
|
3999
4197
|
if (authority > 0.0) {
|
|
4000
|
-
let response = tone_response(encodedInput, sizeK);
|
|
4198
|
+
let response = tone_response(encodedInput, sizeK, toneLevelFar);
|
|
4001
4199
|
// The collapse's mean pull is toward L(toneColour.rgb) \u2014 the LINEAR
|
|
4002
4200
|
// mean, which toneAnchor.w carries \u2014 not toward the encoded level.
|
|
4003
4201
|
let preCollapse = (response - toneAdapt * ou.toneAnchor.w) / (1.0 - toneAdapt);
|
|
@@ -4299,7 +4497,34 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4299
4497
|
* does everywhere else, which is what makes this term inert at the defaults.
|
|
4300
4498
|
*/
|
|
4301
4499
|
let lit = pow(max(abs(dot(normal, ou.rimLit.xy)) * 1.4142135, 1e-6), ou.rimLit.z);
|
|
4302
|
-
|
|
4500
|
+
/*
|
|
4501
|
+
* The along-side field (W25; claims 5.113, W25 Decision Log 3 (c)) \u2014 the
|
|
4502
|
+
* POSITION half of the light whose direction half W24 landed.
|
|
4503
|
+
*
|
|
4504
|
+
* W24's factor is a function of the normal, so it is one number on a whole
|
|
4505
|
+
* straight side. Read by position along the side instead, on flat solid
|
|
4506
|
+
* backdrops where a lens has no gradient to refract, the reference's rim is
|
|
4507
|
+
* graded on every thick cell of both probe grids and flat at spans 32 and 44 \u2014
|
|
4508
|
+
* a term on the thickness curve. Its four slopes are equal and OPPOSITE across
|
|
4509
|
+
* opposite sides, which a field linear in position cannot be and the product of
|
|
4510
|
+
* the two normalised coordinates is exactly: +1 at the top-left and
|
|
4511
|
+
* bottom-right corners, -1 at the other two, the same diagonal 'rimLit.xy' is
|
|
4512
|
+
* symmetric about.
|
|
4513
|
+
*
|
|
4514
|
+
* 'aux2.xy' is the pixel's offset from its own surface's centre in CSS px and
|
|
4515
|
+
* 'aux2.zw' its half-extents, so the field is the surface's own coordinate and
|
|
4516
|
+
* a container of differently sized members grades each of them by its own box
|
|
4517
|
+
* out of one pass. The field's mean over any straight side is exactly zero, so
|
|
4518
|
+
* W23's and W24's straight-span amplitudes keep the meaning they were fitted
|
|
4519
|
+
* with and the CSS tier's single inset needs no counterpart.
|
|
4520
|
+
*
|
|
4521
|
+
* 'sizeThick' is the unfolded thickness curve, exactly 0 at sizeSpanMin, so
|
|
4522
|
+
* rrect-sm and every thinner control are untouched by construction; at slope 0
|
|
4523
|
+
* the factor is exactly 1 everywhere.
|
|
4524
|
+
*/
|
|
4525
|
+
let alongSide = clamp((rel.x / halfExt.x) * (rel.y / halfExt.y), -1.0, 1.0);
|
|
4526
|
+
let alongFactor = max(1.0 + ou.rimLit.w * sizeThick * alongSide, 0.0);
|
|
4527
|
+
let rim = rw * lit * alongFactor * (rimAmplitude * present + rimCollapsed * toneAdapt);
|
|
4303
4528
|
let rimLight = rim * rimTintColour;
|
|
4304
4529
|
if (ou.flags.x > 0.5) {
|
|
4305
4530
|
colour = colour + rimLight;
|
|
@@ -4599,7 +4824,7 @@ function createPassRunner(context) {
|
|
|
4599
4824
|
};
|
|
4600
4825
|
},
|
|
4601
4826
|
opticsPass(encoder, args) {
|
|
4602
|
-
const slot = uniformSlot(`optics:${args.groupId}`,
|
|
4827
|
+
const slot = uniformSlot(`optics:${args.groupId}`, 112);
|
|
4603
4828
|
const d = slot.data;
|
|
4604
4829
|
d[0] = args.viewportDevice[0];
|
|
4605
4830
|
d[1] = args.viewportDevice[1];
|
|
@@ -4704,9 +4929,19 @@ function createPassRunner(context) {
|
|
|
4704
4929
|
d[100] = args.rimLitAxis[0];
|
|
4705
4930
|
d[101] = args.rimLitAxis[1];
|
|
4706
4931
|
d[102] = args.rimLitExponent;
|
|
4932
|
+
d[103] = args.rimAlongSideSlope;
|
|
4933
|
+
d[104] = args.sizeScatterHeavyShareThick;
|
|
4934
|
+
d[105] = args.sizeToneLevelFar;
|
|
4935
|
+
d[106] = 0;
|
|
4936
|
+
d[107] = 0;
|
|
4937
|
+
d[108] = args.heavyTapEnabled ? 1 : 0;
|
|
4938
|
+
d[109] = 0;
|
|
4939
|
+
d[110] = 0;
|
|
4940
|
+
d[111] = 0;
|
|
4707
4941
|
slot.write();
|
|
4708
4942
|
const chain = args.backdrop?.chain ?? placeholderView;
|
|
4709
4943
|
const body = args.backdrop?.body ?? placeholderView;
|
|
4944
|
+
const heavy = args.backdrop?.heavy ?? placeholderView;
|
|
4710
4945
|
const pipeline = opticsPipeline(args.targetFormat);
|
|
4711
4946
|
const pass = encoder.beginRenderPass({
|
|
4712
4947
|
label: `vitrea:pass:optics:${args.groupId}`,
|
|
@@ -4727,7 +4962,8 @@ function createPassRunner(context) {
|
|
|
4727
4962
|
// Linear, no mips: the field targets have one level, and this is only
|
|
4728
4963
|
// read at all when the governor shrank them below the group's rect.
|
|
4729
4964
|
{ binding: 6, resource: context.flatSampler },
|
|
4730
|
-
{ binding: 7, resource: args.fields.aux2.createView() }
|
|
4965
|
+
{ binding: 7, resource: args.fields.aux2.createView() },
|
|
4966
|
+
{ binding: 8, resource: heavy }
|
|
4731
4967
|
]
|
|
4732
4968
|
}));
|
|
4733
4969
|
pass.draw(3);
|
|
@@ -4901,6 +5137,29 @@ function bodyBlurPlan(sigmaPx, plan) {
|
|
|
4901
5137
|
const residualLevel0 = Math.sqrt(Math.max(sigmaPx * sigmaPx - covered * covered, 0));
|
|
4902
5138
|
return { level, residualSigmaTexels: residualLevel0 / Math.pow(2, level) };
|
|
4903
5139
|
}
|
|
5140
|
+
var CHAIN_LEVEL_SIGMA = [0, 1.542, 3.281, 6.679, 13.418, 26.867];
|
|
5141
|
+
function chainLevelSigma(level) {
|
|
5142
|
+
if (level <= 0)
|
|
5143
|
+
return 0;
|
|
5144
|
+
if (level < CHAIN_LEVEL_SIGMA.length)
|
|
5145
|
+
return CHAIN_LEVEL_SIGMA[level];
|
|
5146
|
+
const last = CHAIN_LEVEL_SIGMA[CHAIN_LEVEL_SIGMA.length - 1];
|
|
5147
|
+
return last * Math.pow(2, level - (CHAIN_LEVEL_SIGMA.length - 1));
|
|
5148
|
+
}
|
|
5149
|
+
function heavyTapPlan(sigmaTexels, plan) {
|
|
5150
|
+
let level = 0;
|
|
5151
|
+
if (sigmaTexels > 0) {
|
|
5152
|
+
for (let i = 1; i < plan.levelCount; i += 1) {
|
|
5153
|
+
if (chainLevelSigma(i) > sigmaTexels)
|
|
5154
|
+
break;
|
|
5155
|
+
level = i;
|
|
5156
|
+
}
|
|
5157
|
+
}
|
|
5158
|
+
const scale = Math.pow(2, level);
|
|
5159
|
+
const covered = chainLevelSigma(level);
|
|
5160
|
+
const residual = Math.sqrt(Math.max(sigmaTexels * sigmaTexels - covered * covered, 0)) / scale;
|
|
5161
|
+
return { level, residualSigmaTexels: residual };
|
|
5162
|
+
}
|
|
4904
5163
|
|
|
4905
5164
|
// ../renderer-webgpu/dist/rebuild-ledger.js
|
|
4906
5165
|
function createRebuildLedger() {
|
|
@@ -4957,7 +5216,8 @@ function createRebuildLedger() {
|
|
|
4957
5216
|
var chainUsage = () => GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING;
|
|
4958
5217
|
var densityOf = (source, request) => texelsPerCssPx(source.width, source.height, request.placement, request.viewportCss[0], request.viewportCss[1]);
|
|
4959
5218
|
var same = (next, existing) => Math.abs(next - existing) <= 1e-6 * Math.max(1, Math.abs(existing));
|
|
4960
|
-
var
|
|
5219
|
+
var sameHeavySigma = (next, existing) => next > 0 === existing > 0 && same(next, existing);
|
|
5220
|
+
var sameBody = (existing, request) => same(densityOf({ width: existing.sourceWidth, height: existing.sourceHeight }, request), existing.texelsPerCss) && same(request.bodySigmaCss, existing.bodySigmaCss) && sameHeavySigma(request.heavySigmaCss, existing.heavySigmaCss);
|
|
4961
5221
|
function createPyramidStore(context) {
|
|
4962
5222
|
const { device, pool, cache } = context;
|
|
4963
5223
|
const resources = /* @__PURE__ */ new Map();
|
|
@@ -5030,13 +5290,17 @@ function createPyramidStore(context) {
|
|
|
5030
5290
|
return void 0;
|
|
5031
5291
|
if (pool.peek(poolKey.backdropBody(sourceId)) !== target.body)
|
|
5032
5292
|
return void 0;
|
|
5293
|
+
if (target.heavy !== void 0 && pool.peek(poolKey.backdropHeavy(sourceId)) !== target.heavy) {
|
|
5294
|
+
return void 0;
|
|
5295
|
+
}
|
|
5033
5296
|
return target;
|
|
5034
5297
|
};
|
|
5035
5298
|
const mipView = (texture, level) => texture.createView({ baseMipLevel: level, mipLevelCount: 1, dimension: "2d" });
|
|
5036
|
-
function allocate(sourceId, plan, bodyLevel, sizeEpoch, builtEpoch, bodySigmaTexels, density, bodySigmaCss) {
|
|
5299
|
+
function allocate(sourceId, plan, bodyLevel, sizeEpoch, builtEpoch, bodySigmaTexels, density, bodySigmaCss, heavyLevel, heavySigmaCss) {
|
|
5037
5300
|
const existing = resources.get(sourceId);
|
|
5038
|
-
const
|
|
5039
|
-
const
|
|
5301
|
+
const levelSize = (level) => plan.levels[level] ?? plan.levels[0];
|
|
5302
|
+
const bodyWidth = levelSize(bodyLevel).width;
|
|
5303
|
+
const bodyHeight = levelSize(bodyLevel).height;
|
|
5040
5304
|
const chain = pool.acquire(poolKey.backdropChain(sourceId), {
|
|
5041
5305
|
width: plan.width,
|
|
5042
5306
|
height: plan.height,
|
|
@@ -5052,6 +5316,19 @@ function createPyramidStore(context) {
|
|
|
5052
5316
|
usage: chainUsage(),
|
|
5053
5317
|
label: `vitrea:pyramid:${sourceId}:body`
|
|
5054
5318
|
});
|
|
5319
|
+
let heavy;
|
|
5320
|
+
if (heavyLevel === void 0) {
|
|
5321
|
+
pool.release(poolKey.backdropHeavy(sourceId));
|
|
5322
|
+
pool.release(poolKey.backdropHeavyScratch(sourceId));
|
|
5323
|
+
} else {
|
|
5324
|
+
heavy = pool.acquire(poolKey.backdropHeavy(sourceId), {
|
|
5325
|
+
width: levelSize(heavyLevel).width,
|
|
5326
|
+
height: levelSize(heavyLevel).height,
|
|
5327
|
+
format: WORKING_TEXTURE_FORMAT,
|
|
5328
|
+
usage: chainUsage(),
|
|
5329
|
+
label: `vitrea:pyramid:${sourceId}:heavy`
|
|
5330
|
+
});
|
|
5331
|
+
}
|
|
5055
5332
|
let stats = existing?.stats;
|
|
5056
5333
|
if (stats === void 0) {
|
|
5057
5334
|
stats = device.createBuffer({
|
|
@@ -5060,7 +5337,7 @@ function createPyramidStore(context) {
|
|
|
5060
5337
|
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
|
|
5061
5338
|
});
|
|
5062
5339
|
}
|
|
5063
|
-
if (existing === void 0 || existing.chain !== chain || existing.body !== body) {
|
|
5340
|
+
if (existing === void 0 || existing.chain !== chain || existing.body !== body || existing.heavy !== heavy) {
|
|
5064
5341
|
reallocations += 1;
|
|
5065
5342
|
}
|
|
5066
5343
|
const next = {
|
|
@@ -5068,6 +5345,7 @@ function createPyramidStore(context) {
|
|
|
5068
5345
|
plan,
|
|
5069
5346
|
chain,
|
|
5070
5347
|
body,
|
|
5348
|
+
heavy,
|
|
5071
5349
|
stats,
|
|
5072
5350
|
sizeEpoch,
|
|
5073
5351
|
builtEpoch,
|
|
@@ -5075,7 +5353,8 @@ function createPyramidStore(context) {
|
|
|
5075
5353
|
texelsPerCss: density.texelsPerCss,
|
|
5076
5354
|
sourceWidth: density.sourceWidth,
|
|
5077
5355
|
sourceHeight: density.sourceHeight,
|
|
5078
|
-
bodySigmaCss
|
|
5356
|
+
bodySigmaCss,
|
|
5357
|
+
heavySigmaCss
|
|
5079
5358
|
};
|
|
5080
5359
|
resources.set(sourceId, next);
|
|
5081
5360
|
return next;
|
|
@@ -5156,22 +5435,23 @@ function createPyramidStore(context) {
|
|
|
5156
5435
|
pass.end();
|
|
5157
5436
|
}
|
|
5158
5437
|
}
|
|
5159
|
-
function
|
|
5438
|
+
function runSeparableBlur(encoder, sourceId, kind, plan, chain, target, level, residualSigmaTexels) {
|
|
5160
5439
|
const pipeline = chainPipeline("fs_blur");
|
|
5161
5440
|
const size = plan.levels[level] ?? plan.levels[0];
|
|
5162
|
-
const
|
|
5441
|
+
const scratchKey = kind === "body" ? poolKey.backdropBodyScratch(sourceId) : poolKey.backdropHeavyScratch(sourceId);
|
|
5442
|
+
const scratch = pool.acquire(scratchKey, {
|
|
5163
5443
|
width: size.width,
|
|
5164
5444
|
height: size.height,
|
|
5165
5445
|
format: WORKING_TEXTURE_FORMAT,
|
|
5166
5446
|
usage: chainUsage(),
|
|
5167
|
-
label: `vitrea:pyramid:${sourceId}
|
|
5447
|
+
label: `vitrea:pyramid:${sourceId}:${kind}-scratch`
|
|
5168
5448
|
});
|
|
5169
5449
|
const stages = [
|
|
5170
5450
|
{ target: scratch, source: mipView(chain, level), dir: [1, 0], tag: "h" },
|
|
5171
|
-
{ target
|
|
5451
|
+
{ target, source: scratch.createView(), dir: [0, 1], tag: "v" }
|
|
5172
5452
|
];
|
|
5173
5453
|
for (const stage of stages) {
|
|
5174
|
-
const slot = uniformSlot(
|
|
5454
|
+
const slot = uniformSlot(`${kind}:${sourceId}:${stage.tag}`, 8);
|
|
5175
5455
|
slot.data[0] = 1 / size.width;
|
|
5176
5456
|
slot.data[1] = 1 / size.height;
|
|
5177
5457
|
slot.data[2] = 0;
|
|
@@ -5182,7 +5462,7 @@ function createPyramidStore(context) {
|
|
|
5182
5462
|
slot.data[7] = 0;
|
|
5183
5463
|
slot.write();
|
|
5184
5464
|
const pass = encoder.beginRenderPass({
|
|
5185
|
-
label: `vitrea:pass
|
|
5465
|
+
label: `vitrea:pass:${kind}-blur-${stage.tag}:${sourceId}`,
|
|
5186
5466
|
...timedRender(PASS_LABEL.bodyBlur),
|
|
5187
5467
|
colorAttachments: [
|
|
5188
5468
|
{ view: stage.target.createView(), loadOp: "clear", storeOp: "store", clearValue: { r: 0, g: 0, b: 0, a: 0 } }
|
|
@@ -5285,10 +5565,14 @@ function createPyramidStore(context) {
|
|
|
5285
5565
|
const planScale = frame.width > 0 ? plan.width / frame.width : 1;
|
|
5286
5566
|
const bodySigmaTexels = request.bodySigmaCss * texelsPerCss * planScale;
|
|
5287
5567
|
const bodyPlan = bodyBlurPlan(bodySigmaTexels, plan);
|
|
5288
|
-
const
|
|
5568
|
+
const heavyPlan = request.heavySigmaCss > 0 ? heavyTapPlan(request.heavySigmaCss * texelsPerCss * planScale, plan) : void 0;
|
|
5569
|
+
const target = allocate(request.sourceId, plan, bodyPlan.level, frame.sizeEpoch, request.epoch, bodySigmaTexels, { texelsPerCss, sourceWidth: frame.width, sourceHeight: frame.height }, request.bodySigmaCss, heavyPlan?.level, request.heavySigmaCss);
|
|
5289
5570
|
runImport(encoder, request.sourceId, frame, target.chain);
|
|
5290
5571
|
runChain(encoder, request.sourceId, plan, target.chain);
|
|
5291
|
-
|
|
5572
|
+
runSeparableBlur(encoder, request.sourceId, "body", plan, target.chain, target.body, bodyPlan.level, bodyPlan.residualSigmaTexels);
|
|
5573
|
+
if (heavyPlan !== void 0 && target.heavy !== void 0) {
|
|
5574
|
+
runSeparableBlur(encoder, request.sourceId, "heavy", plan, target.chain, target.heavy, heavyPlan.level, heavyPlan.residualSigmaTexels);
|
|
5575
|
+
}
|
|
5292
5576
|
runAnalysis(encoder, request.sourceId, plan, target.chain, target.stats);
|
|
5293
5577
|
provider.markImported();
|
|
5294
5578
|
return { status: "built", resources: target };
|
|
@@ -5366,6 +5650,8 @@ function createPyramidStore(context) {
|
|
|
5366
5650
|
pool.release(poolKey.backdropChain(sourceId));
|
|
5367
5651
|
pool.release(poolKey.backdropBody(sourceId));
|
|
5368
5652
|
pool.release(poolKey.backdropBodyScratch(sourceId));
|
|
5653
|
+
pool.release(poolKey.backdropHeavy(sourceId));
|
|
5654
|
+
pool.release(poolKey.backdropHeavyScratch(sourceId));
|
|
5369
5655
|
resources.get(sourceId)?.stats.destroy();
|
|
5370
5656
|
resources.delete(sourceId);
|
|
5371
5657
|
readbacks.get(sourceId)?.staging.destroy();
|
|
@@ -5518,7 +5804,8 @@ function createWebGPURenderer(options = {}) {
|
|
|
5518
5804
|
const sameDensity = Math.abs(next - existing.texelsPerCss) <= 1e-6 * Math.max(1, existing.texelsPerCss);
|
|
5519
5805
|
const sigmaCss = bodySigmaCssFor(sourceId);
|
|
5520
5806
|
const sameSigma = Math.abs(sigmaCss - existing.bodySigmaCss) <= 1e-6 * Math.max(1, existing.bodySigmaCss);
|
|
5521
|
-
|
|
5807
|
+
const sameHeavy = sameHeavySigma(heavySigmaCssFor(sourceId), existing.heavySigmaCss);
|
|
5808
|
+
if (sameDensity && sameSigma && sameHeavy)
|
|
5522
5809
|
continue;
|
|
5523
5810
|
requests.push({
|
|
5524
5811
|
sourceId,
|
|
@@ -5539,6 +5826,11 @@ function createWebGPURenderer(options = {}) {
|
|
|
5539
5826
|
const optics = opticsUnderPolicy(material.optics[sourceVariant(sourceId)], accessibility, material);
|
|
5540
5827
|
return optics.blurSigma / Math.max(viewport.devicePixelRatio, 1e-3);
|
|
5541
5828
|
};
|
|
5829
|
+
const heavySigmaCssFor = (sourceId) => {
|
|
5830
|
+
if (bodySigmaCssFor(sourceId) <= 0)
|
|
5831
|
+
return 0;
|
|
5832
|
+
return heavyTapSigmaAtScale(material, viewport.devicePixelRatio) / Math.max(viewport.devicePixelRatio, 1e-3);
|
|
5833
|
+
};
|
|
5542
5834
|
const groupTintSeed = (input) => input.surfaces.find((surface) => surface.fieldReferenceOnly !== true && (surface.tint?.strength ?? 0) > 0)?.tint?.color;
|
|
5543
5835
|
const stateOf = (input, resolution) => {
|
|
5544
5836
|
const resolved = resolution?.groups.find((group) => group.groupId === input.groupId);
|
|
@@ -5605,6 +5897,9 @@ function createWebGPURenderer(options = {}) {
|
|
|
5605
5897
|
// scale. At dpr 1 this is `optics.blurSigma` unchanged, which is what
|
|
5606
5898
|
// leaves the 1x law exactly as landed.
|
|
5607
5899
|
bodySigmaCss: bodySigmaCssFor(request.sourceId),
|
|
5900
|
+
// The heavy blur's own σ, through the same conversion (W26). At 0 the
|
|
5901
|
+
// pyramid allocates nothing and encodes nothing.
|
|
5902
|
+
heavySigmaCss: heavySigmaCssFor(request.sourceId),
|
|
5608
5903
|
viewportCss: [viewport.widthCss, viewport.heightCss],
|
|
5609
5904
|
...isUsablePlacement(placement) ? { placement } : {}
|
|
5610
5905
|
}, provider, encoder);
|
|
@@ -5782,6 +6077,20 @@ function createWebGPURenderer(options = {}) {
|
|
|
5782
6077
|
// brightness the whole way round.
|
|
5783
6078
|
rimLitAxis: material.rimLitAxis,
|
|
5784
6079
|
rimLitExponent: optics.rimLitExponent,
|
|
6080
|
+
// W25's three mechanisms (claims §5.113; W25 Decision Log 3), each of
|
|
6081
|
+
// them 0 on the landed material. The along-side field's slope is the
|
|
6082
|
+
// variant's under the same accessibility fold as the exponent it grades;
|
|
6083
|
+
// the heavy share's thick lift is resolved at the ratio this group draws
|
|
6084
|
+
// at, on the pattern every second-scale constant already has; the level
|
|
6085
|
+
// term's gain is the profile's, and the span curve it rides is the
|
|
6086
|
+
// shader's own `farS`.
|
|
6087
|
+
rimAlongSideSlope: optics.rimAlongSideSlope,
|
|
6088
|
+
sizeScatterHeavyShareThick: scatterHeavyShareThickAtScale(material, dpr),
|
|
6089
|
+
sizeToneLevelFar: material.sizeToneLevelFar,
|
|
6090
|
+
// The heavy blur (W26): whether this group's source carries one. The width
|
|
6091
|
+
// itself is already in the texture, so this pass only chooses which of
|
|
6092
|
+
// two textures the deep sample comes from.
|
|
6093
|
+
heavyTapEnabled: pyramid?.heavy !== void 0,
|
|
5785
6094
|
shadowDepth: optics.shadowDepth,
|
|
5786
6095
|
shadowAlpha: optics.shadowAlpha,
|
|
5787
6096
|
// The size law's gains, per group (W2); the per-pixel factor they
|
|
@@ -5898,7 +6207,8 @@ function createWebGPURenderer(options = {}) {
|
|
|
5898
6207
|
outerShadowRectCssHeight: rectDevice.height * cssPerDevice,
|
|
5899
6208
|
backdrop: pyramid === void 0 || policy.glass === "none" ? void 0 : {
|
|
5900
6209
|
chain: pyramid.chain.createView(),
|
|
5901
|
-
body: pyramid.body.createView()
|
|
6210
|
+
body: pyramid.body.createView(),
|
|
6211
|
+
heavy: pyramid.heavy?.createView()
|
|
5902
6212
|
}
|
|
5903
6213
|
});
|
|
5904
6214
|
if (active.highlight !== void 0) {
|
|
@@ -6192,6 +6502,6 @@ function createWebGPURenderer(options = {}) {
|
|
|
6192
6502
|
};
|
|
6193
6503
|
}
|
|
6194
6504
|
|
|
6195
|
-
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, 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, samePlacement, scatterDeepThickness, scatterFloorAtScale, scatterGainAt, scatterGainAtScale, scatterGainFarAtScale, scatterRampAreaMean, scatterRampReachDevicePx, scatterRampStart, scatterSharpShare, scatterSpanMaxAtScale, scatterThickness, shadowDepthPx, sizeOcclusionAlpha, sizeOcclusionAlphaAt, sizeOuterShadowOcclusion, sizeOuterShadowOcclusionAt, sizeScatterSigma, sizeScatterSigmaAt, sizeShadowDepth, sizeShadowDepthAt, sizeThickness, sizeThicknessUnderPolicy, snapRectToDevicePixels, srgbToLinear, srgbToLinearChannel, statsFromBuffer, supportsTimestamps, texelsPerCssPx, tintShade, tintShadeLayer, tintToneAdaptation, tintedMaterialColour, validateAppTexture, withMaterialOverrides };
|
|
6196
|
-
//# sourceMappingURL=dist-
|
|
6197
|
-
//# sourceMappingURL=dist-
|
|
6505
|
+
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-PT4PUS4K.js.map
|
|
6507
|
+
//# sourceMappingURL=dist-PT4PUS4K.js.map
|