@vitreajs/vitrea 0.3.0 → 0.4.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-MVSXUP3K.js → dist-RGWZAZ6J.js} +775 -125
- package/dist/dist-RGWZAZ6J.js.map +1 -0
- package/dist/index.d.ts +454 -43
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/dist-MVSXUP3K.js.map +0 -1
|
@@ -348,6 +348,8 @@ var DEFAULT_MATERIAL_PROFILE = {
|
|
|
348
348
|
*/
|
|
349
349
|
sizeSpanMin: 32,
|
|
350
350
|
sizeSpanMax: 96,
|
|
351
|
+
// The inner shadow's depth gain since W12 G2 (the lens reads its own law
|
|
352
|
+
// below); the value is W2's, unchanged.
|
|
351
353
|
lensSizeGainMax: 2.6,
|
|
352
354
|
/*
|
|
353
355
|
* MEASURED (W2), each with its own status — see the fields' notes.
|
|
@@ -431,16 +433,64 @@ var DEFAULT_MATERIAL_PROFILE = {
|
|
|
431
433
|
sizeScatterGainMax: 8,
|
|
432
434
|
sizeScatterFloor: 0.4,
|
|
433
435
|
sizeScatterSpanMax: 256,
|
|
436
|
+
// The 1x three FITTED in the renderer (W13 G1's third sweep, 44 points over
|
|
437
|
+
// the calibration bed: `results/2026-09-03-w13-ramp/g1/sweep-3/g1-sweep-3.md`
|
|
438
|
+
// §3); the 2x three PROVISIONAL still, because at them the excursion is
|
|
439
|
+
// bit-exactly zero on the whole bed and a sweep cannot fit what does not
|
|
440
|
+
// move (§4). The thin anchor 0.72 is above G0's read-off of 0.637–0.642: the
|
|
441
|
+
// grid runs 0.60 / 0.64 / 0.68 and the refinement 0.72 / 0.76, and 0.72 is an
|
|
442
|
+
// interior optimum of both the interior objective and the interior gap. The
|
|
443
|
+
// thick anchor 0.52 is G0's `rrect-md` reading and is above that cell's deep
|
|
444
|
+
// sharp share of 0.481, where the joint thick fit of 0.47 would have clamped
|
|
445
|
+
// it to nothing. The 2x pair is G0's 2x readings, every one of which is BELOW
|
|
446
|
+
// its cell's deep value, so at dpr 2 the excursion is zero on this whole bed
|
|
447
|
+
// — the law evaluating to no excursion, and the 2x gap located in the deep
|
|
448
|
+
// value instead (claims §5.64 §4). See
|
|
449
|
+
// `MaterialProfile.sizeScatterRampStartThin1x`.
|
|
450
|
+
sizeScatterRampStartThin1x: 0.72,
|
|
451
|
+
sizeScatterRampStartThick1x: 0.52,
|
|
452
|
+
sizeScatterRampStartFar1x: 0.2,
|
|
453
|
+
sizeScatterRampStartThin2x: 0.46,
|
|
454
|
+
sizeScatterRampStartThick2x: 0.17,
|
|
455
|
+
sizeScatterRampStartFar2x: 0.15,
|
|
456
|
+
sizeScatterRampReach1xPx: 80,
|
|
457
|
+
sizeScatterRampReach2xPx: 100,
|
|
434
458
|
sizeOcclusionGain: 0.05,
|
|
435
459
|
sizeShadowGainMax: 1,
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
460
|
+
/*
|
|
461
|
+
* The lens (W12 G2, claims §5.51; Decision Log 3 of the W12 spec).
|
|
462
|
+
*
|
|
463
|
+
* MEASURED from the reference's own layer tree (§5.50): the inner refraction
|
|
464
|
+
* amount and height laws, verified on spans 32 / 44 / 48 … 112 / 128 / 160
|
|
465
|
+
* and the nested base at 130, and the ovalization's knee (0 through span 64,
|
|
466
|
+
* 0.5 from 72). FITTED on the pixels (§5.51, a 2-D band renderer validated on
|
|
467
|
+
* this renderer's own capture): the gain, the extent and the exponent, on
|
|
468
|
+
* `rrect-md` + `-ml` at 1x pitches 16 and 32 with `rrect-lg` held out at both
|
|
469
|
+
* scales; the ovalization's effective value on the box-inscribed ellipse.
|
|
470
|
+
* Predicted before the landing capture: checkerboard SSIM 1x md / ml / lg
|
|
471
|
+
* 0.954 / 0.931 / 0.929 → 0.970 / 0.946 / 0.942, 2x 0.939 / 0.902 / 0.901 →
|
|
472
|
+
* 0.950 / 0.918 / 0.918, the capsule 0.977 → 0.985.
|
|
473
|
+
*
|
|
474
|
+
* What W11c G2 recorded here — 1.6 lens depths on the square profile, fitted
|
|
475
|
+
* per depth shell — was the band's mean, not its shape (§5.48, §5.49); it is
|
|
476
|
+
* kept in git history and in claims §5.43.
|
|
477
|
+
*/
|
|
478
|
+
lensRefractionGain: 0.745,
|
|
479
|
+
lensHeightPerSpan: 0.25,
|
|
480
|
+
lensHeightMax: 20,
|
|
481
|
+
lensAmountPerSpan: 0.8,
|
|
482
|
+
lensAmountMax: 60,
|
|
483
|
+
lensThicknessReference: 8,
|
|
484
|
+
lensExtentGain: 1.337,
|
|
485
|
+
lensProfileExponent: 3.69,
|
|
486
|
+
// 0.8 by eye (W12 Decision Log 6). The pixels preferred 0.6 by a hair — every
|
|
487
|
+
// texture row that can see ω scores 0.001–0.002 lower at 0.8 (claims §5.54) —
|
|
488
|
+
// but the field's measured tilt sits at 0.8–1.0 (§5.49 §3) and the user read
|
|
489
|
+
// the 0.8 sheet as much closer to macOS; the eye overrides a margin that small,
|
|
490
|
+
// and §5.54 §1's rows are the recorded cost.
|
|
491
|
+
lensOvalization: 0.8,
|
|
492
|
+
lensOvalizationSpanMin: 64,
|
|
493
|
+
lensOvalizationSpanMax: 72,
|
|
444
494
|
reducedTransparencyFrost: 1.75,
|
|
445
495
|
increasedOcclusionLift: INCREASED_OCCLUSION_LIFT,
|
|
446
496
|
strongBorderRim: { rimWidth: 2, rimAlpha: 0.95 },
|
|
@@ -568,14 +618,18 @@ var DEFAULT_MATERIAL_PROFILE = {
|
|
|
568
618
|
* instrument's independent shadow axis agrees, so the geometry stands on those
|
|
569
619
|
* two and this objective is not asked to re-decide it.
|
|
570
620
|
*
|
|
571
|
-
* `reducedTransparencyOcclusion` 0.70
|
|
572
|
-
* 3.83× spread over 0.45…0.95 with a clear minimum. It also
|
|
621
|
+
* `reducedTransparencyOcclusion` 0.70 was sharp where the amplitude was flat: a
|
|
622
|
+
* 3.83× spread over 0.45…0.95 with a clear minimum. It also reconciled two
|
|
573
623
|
* routes — 0.285 × 0.70 = 0.1995 against the reference's directly measured
|
|
574
624
|
* reduce-transparency amplitude of 0.203 at a 44 px span. W8's 0.566 was the
|
|
575
|
-
* ratio of the reference's two amplitudes;
|
|
625
|
+
* ratio of the reference's two amplitudes; that was the ratio that made
|
|
576
626
|
* vitrea's shadow match the reference's under the preference, and the two
|
|
577
|
-
*
|
|
578
|
-
* is much wider in the standard profile than under reduced transparency.
|
|
627
|
+
* differed because the base amplitude is a compromise across scenes whose
|
|
628
|
+
* spread is much wider in the standard profile than under reduced transparency.
|
|
629
|
+
* **W14 G1 re-forms the constant as the LEVEL those routes were reconciling
|
|
630
|
+
* to** — 0.197 absolute, replacing both regimes rather than scaling them — for
|
|
631
|
+
* the reason its doc comment gives: a ratio and a level stopped being the same
|
|
632
|
+
* thing when the single amplitude became six unequal anchors.
|
|
579
633
|
*
|
|
580
634
|
* Extracted from the active bed's native fixtures directly —
|
|
581
635
|
* `results/2026-08-31-active-bed-stage0.json` measured the gap, these numbers
|
|
@@ -614,13 +668,33 @@ var DEFAULT_MATERIAL_PROFILE = {
|
|
|
614
668
|
* 44 px span — the dark material's shadow is nearly invisible) and lands as a
|
|
615
669
|
* profile patch, not as a branch here. Both are stated in the claims doc as the
|
|
616
670
|
* open question the cascade's fit inherits.
|
|
671
|
+
*
|
|
672
|
+
* **W14 G1 answers that open question and replaces `occlusion`.** "Over the
|
|
673
|
+
* flat near-white `light-solid` backdrop the same fit reads 0.123 rather than
|
|
674
|
+
* 0.33 … it is not a function of the backdrop's luminance" was read on a bed
|
|
675
|
+
* that had no backdrop between `hc-text` (linear 0.74) and `light-solid`
|
|
676
|
+
* (0.891): it IS a function of the backdrop's luminance, and the whole factor
|
|
677
|
+
* of 2.6 happens inside the gap the bed cannot see (claims §5.62 §5). The
|
|
678
|
+
* single amplitude becomes six anchors on two regimes — three in backdrop
|
|
679
|
+
* luminance below the knee, three in span above it — plus the lift's four
|
|
680
|
+
* constants. The three lengths are untouched; G0 re-read them free on both
|
|
681
|
+
* terms and they came back at W8's values.
|
|
617
682
|
*/
|
|
618
683
|
outerShadow: {
|
|
619
684
|
offsetPx: 7.95,
|
|
620
685
|
sigmaPx: 15.55,
|
|
621
686
|
spreadPx: 3.1,
|
|
622
|
-
|
|
623
|
-
|
|
687
|
+
thinOcclusionDark: 0,
|
|
688
|
+
thinOcclusionMid: 0.33,
|
|
689
|
+
thinOcclusionBright: 0.127,
|
|
690
|
+
thickOcclusionAt96: 0.37,
|
|
691
|
+
thickOcclusionAt128: 0.448,
|
|
692
|
+
thickOcclusionAt160: 0.479,
|
|
693
|
+
liftAmplitude: 0.01,
|
|
694
|
+
liftSpanMin: 64,
|
|
695
|
+
liftSpanFull: 118,
|
|
696
|
+
liftBlurSigmaCss: 40,
|
|
697
|
+
reducedTransparencyOcclusion: 0.197,
|
|
624
698
|
sizeGain: 0
|
|
625
699
|
},
|
|
626
700
|
lightDirection: [-0.3714, -0.9285],
|
|
@@ -641,9 +715,25 @@ var LENS_SIZE_GAIN_MAX = DEFAULT_MATERIAL_PROFILE.lensSizeGainMax;
|
|
|
641
715
|
var SIZE_SCATTER_GAIN_MAX = DEFAULT_MATERIAL_PROFILE.sizeScatterGainMax;
|
|
642
716
|
var SIZE_SCATTER_FLOOR = DEFAULT_MATERIAL_PROFILE.sizeScatterFloor;
|
|
643
717
|
var SIZE_SCATTER_SPAN_MAX = DEFAULT_MATERIAL_PROFILE.sizeScatterSpanMax;
|
|
718
|
+
var SIZE_SCATTER_RAMP_START_THIN_1X = DEFAULT_MATERIAL_PROFILE.sizeScatterRampStartThin1x;
|
|
719
|
+
var SIZE_SCATTER_RAMP_START_THICK_1X = DEFAULT_MATERIAL_PROFILE.sizeScatterRampStartThick1x;
|
|
720
|
+
var SIZE_SCATTER_RAMP_START_THIN_2X = DEFAULT_MATERIAL_PROFILE.sizeScatterRampStartThin2x;
|
|
721
|
+
var SIZE_SCATTER_RAMP_START_THICK_2X = DEFAULT_MATERIAL_PROFILE.sizeScatterRampStartThick2x;
|
|
722
|
+
var SIZE_SCATTER_RAMP_START_FAR_1X = DEFAULT_MATERIAL_PROFILE.sizeScatterRampStartFar1x;
|
|
723
|
+
var SIZE_SCATTER_RAMP_START_FAR_2X = DEFAULT_MATERIAL_PROFILE.sizeScatterRampStartFar2x;
|
|
724
|
+
var SIZE_SCATTER_RAMP_REACH_1X_PX = DEFAULT_MATERIAL_PROFILE.sizeScatterRampReach1xPx;
|
|
725
|
+
var SIZE_SCATTER_RAMP_REACH_2X_PX = DEFAULT_MATERIAL_PROFILE.sizeScatterRampReach2xPx;
|
|
644
726
|
var SIZE_OCCLUSION_GAIN = DEFAULT_MATERIAL_PROFILE.sizeOcclusionGain;
|
|
645
727
|
var SIZE_SHADOW_GAIN_MAX = DEFAULT_MATERIAL_PROFILE.sizeShadowGainMax;
|
|
646
728
|
var LENS_REFRACTION_GAIN = DEFAULT_MATERIAL_PROFILE.lensRefractionGain;
|
|
729
|
+
var LENS_HEIGHT_PER_SPAN = DEFAULT_MATERIAL_PROFILE.lensHeightPerSpan;
|
|
730
|
+
var LENS_HEIGHT_MAX = DEFAULT_MATERIAL_PROFILE.lensHeightMax;
|
|
731
|
+
var LENS_AMOUNT_PER_SPAN = DEFAULT_MATERIAL_PROFILE.lensAmountPerSpan;
|
|
732
|
+
var LENS_AMOUNT_MAX = DEFAULT_MATERIAL_PROFILE.lensAmountMax;
|
|
733
|
+
var LENS_THICKNESS_REFERENCE = DEFAULT_MATERIAL_PROFILE.lensThicknessReference;
|
|
734
|
+
var LENS_EXTENT_GAIN = DEFAULT_MATERIAL_PROFILE.lensExtentGain;
|
|
735
|
+
var LENS_PROFILE_EXPONENT = DEFAULT_MATERIAL_PROFILE.lensProfileExponent;
|
|
736
|
+
var LENS_OVALIZATION = DEFAULT_MATERIAL_PROFILE.lensOvalization;
|
|
647
737
|
var BACKDROP_TONE_MAX = DEFAULT_MATERIAL_PROFILE.backdropToneMax;
|
|
648
738
|
var BACKDROP_TONE_LOW = DEFAULT_MATERIAL_PROFILE.backdropToneLow;
|
|
649
739
|
var BACKDROP_TONE_HIGH = DEFAULT_MATERIAL_PROFILE.backdropToneHigh;
|
|
@@ -653,7 +743,20 @@ DEFAULT_MATERIAL_PROFILE.backdropToneResponseThin;
|
|
|
653
743
|
DEFAULT_MATERIAL_PROFILE.backdropToneResponseThick;
|
|
654
744
|
DEFAULT_MATERIAL_PROFILE.backdropToneResponseStrength;
|
|
655
745
|
var OUTER_SHADOW = DEFAULT_MATERIAL_PROFILE.outerShadow;
|
|
746
|
+
var RETIRED_OUTER_SHADOW_LEAVES = {
|
|
747
|
+
occlusion: "the six amplitude anchors (thinOcclusionDark, thinOcclusionMid, thinOcclusionBright, thickOcclusionAt96, thickOcclusionAt128, thickOcclusionAt160) and liftAmplitude for the second term"
|
|
748
|
+
};
|
|
749
|
+
function rejectRetiredOuterShadowLeaves(patch) {
|
|
750
|
+
if (patch === void 0)
|
|
751
|
+
return;
|
|
752
|
+
for (const [leaf, replacement] of Object.entries(RETIRED_OUTER_SHADOW_LEAVES)) {
|
|
753
|
+
if (!(leaf in patch))
|
|
754
|
+
continue;
|
|
755
|
+
throw new Error(`outerShadow.${leaf} was retired by W14 G1 (claims \xA75.62) and is replaced by ${replacement}. Applying this patch would have rendered the default shadow while recording itself as configured. It is refused rather than mapped: a single span-flat amplitude is the material the measurement retired.`);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
656
758
|
function withMaterialOverrides(base, patch) {
|
|
759
|
+
rejectRetiredOuterShadowLeaves(patch.outerShadow);
|
|
657
760
|
const optics = {};
|
|
658
761
|
for (const variant of MATERIAL_VARIANTS) {
|
|
659
762
|
optics[variant] = { ...base.optics[variant], ...patch.optics?.[variant] };
|
|
@@ -675,9 +778,27 @@ function withMaterialOverrides(base, patch) {
|
|
|
675
778
|
sizeScatterGainMax: patch.sizeScatterGainMax ?? base.sizeScatterGainMax,
|
|
676
779
|
sizeScatterFloor: patch.sizeScatterFloor ?? base.sizeScatterFloor,
|
|
677
780
|
sizeScatterSpanMax: patch.sizeScatterSpanMax ?? base.sizeScatterSpanMax,
|
|
781
|
+
sizeScatterRampStartThin1x: patch.sizeScatterRampStartThin1x ?? base.sizeScatterRampStartThin1x,
|
|
782
|
+
sizeScatterRampStartThick1x: patch.sizeScatterRampStartThick1x ?? base.sizeScatterRampStartThick1x,
|
|
783
|
+
sizeScatterRampStartThin2x: patch.sizeScatterRampStartThin2x ?? base.sizeScatterRampStartThin2x,
|
|
784
|
+
sizeScatterRampStartThick2x: patch.sizeScatterRampStartThick2x ?? base.sizeScatterRampStartThick2x,
|
|
785
|
+
sizeScatterRampStartFar1x: patch.sizeScatterRampStartFar1x ?? base.sizeScatterRampStartFar1x,
|
|
786
|
+
sizeScatterRampStartFar2x: patch.sizeScatterRampStartFar2x ?? base.sizeScatterRampStartFar2x,
|
|
787
|
+
sizeScatterRampReach1xPx: patch.sizeScatterRampReach1xPx ?? base.sizeScatterRampReach1xPx,
|
|
788
|
+
sizeScatterRampReach2xPx: patch.sizeScatterRampReach2xPx ?? base.sizeScatterRampReach2xPx,
|
|
678
789
|
sizeOcclusionGain: patch.sizeOcclusionGain ?? base.sizeOcclusionGain,
|
|
679
790
|
sizeShadowGainMax: patch.sizeShadowGainMax ?? base.sizeShadowGainMax,
|
|
680
791
|
lensRefractionGain: patch.lensRefractionGain ?? base.lensRefractionGain,
|
|
792
|
+
lensHeightPerSpan: patch.lensHeightPerSpan ?? base.lensHeightPerSpan,
|
|
793
|
+
lensHeightMax: patch.lensHeightMax ?? base.lensHeightMax,
|
|
794
|
+
lensAmountPerSpan: patch.lensAmountPerSpan ?? base.lensAmountPerSpan,
|
|
795
|
+
lensAmountMax: patch.lensAmountMax ?? base.lensAmountMax,
|
|
796
|
+
lensThicknessReference: patch.lensThicknessReference ?? base.lensThicknessReference,
|
|
797
|
+
lensExtentGain: patch.lensExtentGain ?? base.lensExtentGain,
|
|
798
|
+
lensProfileExponent: patch.lensProfileExponent ?? base.lensProfileExponent,
|
|
799
|
+
lensOvalization: patch.lensOvalization ?? base.lensOvalization,
|
|
800
|
+
lensOvalizationSpanMin: patch.lensOvalizationSpanMin ?? base.lensOvalizationSpanMin,
|
|
801
|
+
lensOvalizationSpanMax: patch.lensOvalizationSpanMax ?? base.lensOvalizationSpanMax,
|
|
681
802
|
reducedTransparencyFrost: patch.reducedTransparencyFrost ?? base.reducedTransparencyFrost,
|
|
682
803
|
increasedOcclusionLift: patch.increasedOcclusionLift ?? base.increasedOcclusionLift,
|
|
683
804
|
strongBorderRim: { ...base.strongBorderRim, ...patch.strongBorderRim },
|
|
@@ -810,15 +931,102 @@ function lensSizeGain(spanPx, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
|
810
931
|
function lensSizeGainFromThickness(thickness, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
811
932
|
return 1 + (profile.lensSizeGainMax - 1) * thickness;
|
|
812
933
|
}
|
|
813
|
-
function
|
|
814
|
-
return
|
|
934
|
+
function shadowDepthPx(thicknessPx, spanPx, thickness, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
935
|
+
return Math.min(Math.max(thicknessPx, 0) * lensSizeGainFromThickness(thickness, profile), spanPx * 0.5);
|
|
936
|
+
}
|
|
937
|
+
function lensHeightBasePx(spanPx, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
938
|
+
return Math.min(profile.lensHeightPerSpan * Math.max(spanPx, 0), profile.lensHeightMax);
|
|
939
|
+
}
|
|
940
|
+
function lensAmountBasePx(spanPx, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
941
|
+
return Math.min(profile.lensAmountPerSpan * Math.max(spanPx, 0), profile.lensAmountMax);
|
|
942
|
+
}
|
|
943
|
+
function lensOvalizationAt(spanPx, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
944
|
+
return profile.lensOvalization * smoothstep(profile.lensOvalizationSpanMin, profile.lensOvalizationSpanMax, spanPx);
|
|
945
|
+
}
|
|
946
|
+
function lensMagnitudePx(thicknessPx, spanPx, profile = DEFAULT_MATERIAL_PROFILE, fold = 1) {
|
|
947
|
+
const thick = Math.max(thicknessPx, 0);
|
|
948
|
+
if (thick <= 0)
|
|
949
|
+
return 0;
|
|
950
|
+
const scale = thick / profile.lensThicknessReference;
|
|
951
|
+
const unclamped = thick + (lensHeightBasePx(spanPx, profile) * scale - thick) * fold;
|
|
952
|
+
const depth = lensDepthPx(thicknessPx, spanPx, profile, fold);
|
|
953
|
+
const amount = thick + (lensAmountBasePx(spanPx, profile) * scale - thick) * fold;
|
|
954
|
+
return profile.lensRefractionGain * amount * (unclamped > 0 ? depth / unclamped : 0);
|
|
955
|
+
}
|
|
956
|
+
function lensExtentPx(thicknessPx, spanPx, profile = DEFAULT_MATERIAL_PROFILE, fold = 1) {
|
|
957
|
+
return profile.lensExtentGain * lensDepthPx(thicknessPx, spanPx, profile, fold);
|
|
958
|
+
}
|
|
959
|
+
function lensDirection(normal, offset, half, ovalization) {
|
|
960
|
+
const a = Math.max(half[0], 1e-6);
|
|
961
|
+
const b = Math.max(half[1], 1e-6);
|
|
962
|
+
const ex = offset[0] / (a * a);
|
|
963
|
+
const ey = offset[1] / (b * b);
|
|
964
|
+
const r = Math.max(Math.hypot(offset[0] / a, offset[1] / b), 1e-6);
|
|
965
|
+
const scale = Math.min(a, b) / r;
|
|
966
|
+
const gx = (1 - ovalization) * normal[0] + ovalization * ex * scale;
|
|
967
|
+
const gy = (1 - ovalization) * normal[1] + ovalization * ey * scale;
|
|
968
|
+
const len = Math.hypot(gx, gy);
|
|
969
|
+
return len > 1e-9 ? [gx / len, gy / len] : [normal[0], normal[1]];
|
|
970
|
+
}
|
|
971
|
+
function sizeScatterSigma(sigmaPx, spanPx, profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1, extentsCssPx) {
|
|
972
|
+
return sizeScatterSigmaAt(sigmaPx, scatterThickness(spanPx, 1, profile, devicePixelRatio, extentsCssPx), profile);
|
|
973
|
+
}
|
|
974
|
+
function scatterRampStart(devicePixelRatio, profile = DEFAULT_MATERIAL_PROFILE, spanPx = 0) {
|
|
975
|
+
const thin = rampAtScale(profile.sizeScatterRampStartThin1x, profile.sizeScatterRampStartThin2x, devicePixelRatio);
|
|
976
|
+
const thick = rampAtScale(profile.sizeScatterRampStartThick1x, profile.sizeScatterRampStartThick2x, devicePixelRatio);
|
|
977
|
+
const far = rampAtScale(profile.sizeScatterRampStartFar1x, profile.sizeScatterRampStartFar2x, devicePixelRatio);
|
|
978
|
+
const decline = smoothstep(profile.sizeSpanMax, profile.sizeScatterSpanMax, spanPx);
|
|
979
|
+
return thin + (thick - thin) * sizeThickness(spanPx, profile) + (far - thick) * decline;
|
|
980
|
+
}
|
|
981
|
+
function scatterRampReachDevicePx(devicePixelRatio, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
982
|
+
return rampAtScale(profile.sizeScatterRampReach1xPx, profile.sizeScatterRampReach2xPx, devicePixelRatio);
|
|
983
|
+
}
|
|
984
|
+
function rampAtScale(at1x, at2x, devicePixelRatio) {
|
|
985
|
+
const t = devicePixelRatio - 1;
|
|
986
|
+
if (t <= 0)
|
|
987
|
+
return at1x;
|
|
988
|
+
if (t >= 1)
|
|
989
|
+
return at2x;
|
|
990
|
+
return at1x + (at2x - at1x) * t;
|
|
991
|
+
}
|
|
992
|
+
function scatterDeepThickness(spanPx, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
993
|
+
const floor = clampUnit(profile.sizeScatterFloor);
|
|
994
|
+
return floor + (1 - floor) * smoothstep(profile.sizeSpanMin, profile.sizeScatterSpanMax, spanPx);
|
|
815
995
|
}
|
|
816
|
-
function
|
|
817
|
-
const
|
|
818
|
-
|
|
996
|
+
function scatterSharpShare(uDevicePx, devicePixelRatio, profile = DEFAULT_MATERIAL_PROFILE, spanPx = 0) {
|
|
997
|
+
const deepSharp = 1 - scatterDeepThickness(spanPx, profile);
|
|
998
|
+
const start = scatterRampStart(devicePixelRatio, profile, spanPx);
|
|
999
|
+
const reach = Math.max(scatterRampReachDevicePx(devicePixelRatio, profile), 1e-6);
|
|
1000
|
+
const excursion = Math.max(start - deepSharp, 0) * Math.max(1 - Math.max(uDevicePx, 0) / reach, 0);
|
|
1001
|
+
return clampUnit(deepSharp + excursion);
|
|
1002
|
+
}
|
|
1003
|
+
function scatterThickness(spanPx, fold, profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1, extentsCssPx) {
|
|
1004
|
+
const floor = clampUnit(profile.sizeScatterFloor);
|
|
1005
|
+
const mean = scatterRampAreaMean(spanPx, profile, devicePixelRatio, extentsCssPx);
|
|
1006
|
+
return clampUnit(floor + (mean - floor) * fold);
|
|
1007
|
+
}
|
|
1008
|
+
function scatterRampAreaMean(spanPx, profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1, extentsCssPx) {
|
|
1009
|
+
const deep = scatterDeepThickness(spanPx, profile);
|
|
1010
|
+
const amplitude = Math.max(scatterRampStart(devicePixelRatio, profile, spanPx) - (1 - deep), 0);
|
|
1011
|
+
if (amplitude <= 0)
|
|
1012
|
+
return clampUnit(deep);
|
|
1013
|
+
const width = Math.max(extentsCssPx?.[0] ?? spanPx, 0);
|
|
1014
|
+
const height = Math.max(extentsCssPx?.[1] ?? spanPx, 0);
|
|
1015
|
+
const area = width * height;
|
|
1016
|
+
if (area <= 0)
|
|
1017
|
+
return clampUnit(deep - amplitude);
|
|
1018
|
+
const reach = Math.max(scatterRampReachDevicePx(devicePixelRatio, profile) / Math.max(devicePixelRatio, 1e-3), 1e-6);
|
|
1019
|
+
const perimeter = 2 * (width + height);
|
|
1020
|
+
const limit = Math.min(reach, Math.min(width, height) / 2);
|
|
1021
|
+
const triangleMean = (perimeter * limit - 4 * limit * limit - perimeter * limit * limit / (2 * reach) + 8 * limit * limit * limit / (3 * reach)) / area;
|
|
1022
|
+
return clampUnit(deep - amplitude * triangleMean);
|
|
819
1023
|
}
|
|
820
1024
|
function sizeScatterSigmaAt(sigmaPx, scatter, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
821
|
-
|
|
1025
|
+
const mix = clampUnit(scatter);
|
|
1026
|
+
return sigmaPx * (1 + (profile.sizeScatterGainMax - 1) * mix);
|
|
1027
|
+
}
|
|
1028
|
+
function clampUnit(value) {
|
|
1029
|
+
return Math.min(1, Math.max(0, value));
|
|
822
1030
|
}
|
|
823
1031
|
function sizeOcclusionAlpha(alpha, spanPx, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
824
1032
|
return sizeOcclusionAlphaAt(alpha, sizeThickness(spanPx, profile), profile);
|
|
@@ -838,15 +1046,79 @@ function sizeOuterShadowOcclusion(occlusion, spanPx, profile = DEFAULT_MATERIAL_
|
|
|
838
1046
|
function sizeOuterShadowOcclusionAt(occlusion, thickness, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
839
1047
|
return Math.min(1, occlusion + profile.outerShadow.sizeGain * thickness * (1 - occlusion));
|
|
840
1048
|
}
|
|
1049
|
+
var OUTER_SHADOW_THIN_L = {
|
|
1050
|
+
/** At and below this backdrop luminance the black term is `thinOcclusionDark`. */
|
|
1051
|
+
inert: 0.02,
|
|
1052
|
+
/** From here the mid plateau holds. */
|
|
1053
|
+
midFrom: 0.06,
|
|
1054
|
+
/** To here — `hc-text`'s own linear luminance. */
|
|
1055
|
+
midTo: 0.74,
|
|
1056
|
+
/** `light-solid`'s linear luminance, where 0.127 was measured; held above. */
|
|
1057
|
+
bright: 0.891
|
|
1058
|
+
};
|
|
1059
|
+
var OUTER_SHADOW_UNMEASURED_BACKDROP_LUMINANCE = 0.3;
|
|
1060
|
+
function outerShadowThinOcclusion(backdropLuminance, shadow) {
|
|
1061
|
+
const l = backdropLuminance ?? OUTER_SHADOW_UNMEASURED_BACKDROP_LUMINANCE;
|
|
1062
|
+
const { inert, midFrom, midTo, bright } = OUTER_SHADOW_THIN_L;
|
|
1063
|
+
if (l <= inert)
|
|
1064
|
+
return shadow.thinOcclusionDark;
|
|
1065
|
+
if (l < midFrom) {
|
|
1066
|
+
const t2 = (l - inert) / (midFrom - inert);
|
|
1067
|
+
const s = t2 * t2 * (3 - 2 * t2);
|
|
1068
|
+
return shadow.thinOcclusionDark + (shadow.thinOcclusionMid - shadow.thinOcclusionDark) * s;
|
|
1069
|
+
}
|
|
1070
|
+
if (l <= midTo)
|
|
1071
|
+
return shadow.thinOcclusionMid;
|
|
1072
|
+
if (l >= bright)
|
|
1073
|
+
return shadow.thinOcclusionBright;
|
|
1074
|
+
const t = (l - midTo) / (bright - midTo);
|
|
1075
|
+
return shadow.thinOcclusionMid + (shadow.thinOcclusionBright - shadow.thinOcclusionMid) * t;
|
|
1076
|
+
}
|
|
1077
|
+
var OUTER_SHADOW_THICK_SPANS = [96, 128, 160];
|
|
1078
|
+
function outerShadowThickOcclusion(spanPx, shadow) {
|
|
1079
|
+
const [s0, s1, s2] = OUTER_SHADOW_THICK_SPANS;
|
|
1080
|
+
const y0 = shadow.thickOcclusionAt96;
|
|
1081
|
+
const y1 = shadow.thickOcclusionAt128;
|
|
1082
|
+
const y2 = shadow.thickOcclusionAt160;
|
|
1083
|
+
if (spanPx <= s0)
|
|
1084
|
+
return y0;
|
|
1085
|
+
if (spanPx >= s2)
|
|
1086
|
+
return y2;
|
|
1087
|
+
if (spanPx <= s1)
|
|
1088
|
+
return y0 + (y1 - y0) * (spanPx - s0) / (s1 - s0);
|
|
1089
|
+
return y1 + (y2 - y1) * (spanPx - s1) / (s2 - s1);
|
|
1090
|
+
}
|
|
1091
|
+
function outerShadowOcclusionAt(shadow, backdropLuminance, spanPx, thickness, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
1092
|
+
const thin = outerShadowThinOcclusion(backdropLuminance, shadow);
|
|
1093
|
+
const thick = outerShadowThickOcclusion(spanPx, shadow);
|
|
1094
|
+
const k = Math.min(1, Math.max(0, thickness));
|
|
1095
|
+
const blend = k * k * (3 - 2 * k);
|
|
1096
|
+
return sizeOuterShadowOcclusionAt(thin + (thick - thin) * blend, thickness, profile);
|
|
1097
|
+
}
|
|
1098
|
+
function outerShadowLiftRise(spanPx, shadow) {
|
|
1099
|
+
return smoothstep(shadow.liftSpanMin, shadow.liftSpanFull, spanPx);
|
|
1100
|
+
}
|
|
841
1101
|
function outerShadowUnderPolicy(policy, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
842
1102
|
const shadow = profile.outerShadow;
|
|
843
1103
|
if (policy.glass === "none" || policy.frost === "none")
|
|
844
|
-
return
|
|
1104
|
+
return flatOuterShadow(shadow, 0);
|
|
845
1105
|
if (policy.frost === "increased") {
|
|
846
|
-
return
|
|
1106
|
+
return flatOuterShadow(shadow, shadow.reducedTransparencyOcclusion);
|
|
847
1107
|
}
|
|
848
1108
|
return shadow;
|
|
849
1109
|
}
|
|
1110
|
+
function flatOuterShadow(shadow, amplitude) {
|
|
1111
|
+
return {
|
|
1112
|
+
...shadow,
|
|
1113
|
+
thinOcclusionDark: amplitude,
|
|
1114
|
+
thinOcclusionMid: amplitude,
|
|
1115
|
+
thinOcclusionBright: amplitude,
|
|
1116
|
+
thickOcclusionAt96: amplitude,
|
|
1117
|
+
thickOcclusionAt128: amplitude,
|
|
1118
|
+
thickOcclusionAt160: amplitude,
|
|
1119
|
+
liftAmplitude: 0
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
850
1122
|
var SRGB_ENCODING_EXPONENT = 2.4;
|
|
851
1123
|
function outerShadowFalloff(signedDistancePx, sigmaPx) {
|
|
852
1124
|
const x = -signedDistancePx / Math.max(sigmaPx, 1e-4);
|
|
@@ -856,8 +1128,8 @@ function outerShadowAlpha(occlusion) {
|
|
|
856
1128
|
const occ = Math.min(1, Math.max(0, occlusion));
|
|
857
1129
|
return 1 - Math.pow(1 - occ, 1 / SRGB_ENCODING_EXPONENT);
|
|
858
1130
|
}
|
|
859
|
-
function outerShadowReachPx(shadow) {
|
|
860
|
-
const alpha = outerShadowAlpha(
|
|
1131
|
+
function outerShadowReachPx(shadow, occlusion) {
|
|
1132
|
+
const alpha = outerShadowAlpha(occlusion);
|
|
861
1133
|
if (!(alpha > 0))
|
|
862
1134
|
return 0;
|
|
863
1135
|
const cutoff = 1 / 255 / alpha;
|
|
@@ -875,15 +1147,18 @@ function outerShadowReachPx(shadow) {
|
|
|
875
1147
|
}
|
|
876
1148
|
return Math.max(0, hi + Math.abs(shadow.offsetPx) + shadow.spreadPx);
|
|
877
1149
|
}
|
|
878
|
-
function lensDepthPx(thicknessPx, spanPx, profile = DEFAULT_MATERIAL_PROFILE) {
|
|
879
|
-
const
|
|
880
|
-
|
|
1150
|
+
function lensDepthPx(thicknessPx, spanPx, profile = DEFAULT_MATERIAL_PROFILE, fold = 1) {
|
|
1151
|
+
const thick = Math.max(thicknessPx, 0);
|
|
1152
|
+
const scale = thick / profile.lensThicknessReference;
|
|
1153
|
+
const depth = thick + (lensHeightBasePx(spanPx, profile) * scale - thick) * fold;
|
|
1154
|
+
return Math.min(Math.max(depth, 0), spanPx * 0.5);
|
|
881
1155
|
}
|
|
882
|
-
function lensDisplacementPx(depthPx,
|
|
883
|
-
|
|
1156
|
+
function lensDisplacementPx(depthPx, spanPx, thicknessPx, refractionScale, profile = DEFAULT_MATERIAL_PROFILE, fold = 1) {
|
|
1157
|
+
const extent = lensExtentPx(thicknessPx, spanPx, profile, fold);
|
|
1158
|
+
if (extent <= 0)
|
|
884
1159
|
return 0;
|
|
885
|
-
const
|
|
886
|
-
return
|
|
1160
|
+
const t = Math.max(0, 1 - Math.max(depthPx, 0) / extent);
|
|
1161
|
+
return lensMagnitudePx(thicknessPx, spanPx, profile, fold) * Math.pow(t, profile.lensProfileExponent) * refractionScale;
|
|
887
1162
|
}
|
|
888
1163
|
|
|
889
1164
|
// ../renderer-webgpu/dist/analysis.js
|
|
@@ -1721,7 +1996,8 @@ var poolKey = {
|
|
|
1721
1996
|
backdropBodyScratch: (sourceId) => `backdrop:${sourceId}:body-scratch`,
|
|
1722
1997
|
backdropUpload: (sourceId) => `backdrop:${sourceId}:upload`,
|
|
1723
1998
|
groupField: (groupId) => `group:${groupId}:field`,
|
|
1724
|
-
groupAux: (groupId) => `group:${groupId}:aux
|
|
1999
|
+
groupAux: (groupId) => `group:${groupId}:aux`,
|
|
2000
|
+
groupAux2: (groupId) => `group:${groupId}:aux2`
|
|
1725
2001
|
};
|
|
1726
2002
|
|
|
1727
2003
|
// ../renderer-webgpu/dist/gpu-context.js
|
|
@@ -1878,7 +2154,7 @@ function resolveSurfaces(group, family, profile = DEFAULT_MATERIAL_PROFILE, poli
|
|
|
1878
2154
|
centre: [fieldSource.channels.center[0], fieldSource.channels.center[1]],
|
|
1879
2155
|
channels,
|
|
1880
2156
|
spanPx,
|
|
1881
|
-
lensDepthPx:
|
|
2157
|
+
lensDepthPx: lensDepthPx(shape.channels.thickness, spanPx, profile, profile.refractionScale[accessibilityRefractionCap(policy)]),
|
|
1882
2158
|
sizeThickness: thickness,
|
|
1883
2159
|
tintStrength: Math.min(1, Math.max(0, surface.tint?.strength ?? 0))
|
|
1884
2160
|
};
|
|
@@ -1943,7 +2219,7 @@ function packInstances(surfaces, origin, into) {
|
|
|
1943
2219
|
data[o + 11] = s.shape.channels.thickness;
|
|
1944
2220
|
data[o + 12] = s.channels.press;
|
|
1945
2221
|
data[o + 13] = s.channels.glow;
|
|
1946
|
-
data[o + 14] = s.
|
|
2222
|
+
data[o + 14] = Math.max(s.shape.channels.thickness, 0) * Math.min(1, Math.max(0, s.channels.lensStrength));
|
|
1947
2223
|
data[o + 15] = s.tintStrength;
|
|
1948
2224
|
data[o + 16] = s.spanPx;
|
|
1949
2225
|
data[o + 17] = 0;
|
|
@@ -2221,7 +2497,7 @@ var WGSL_INSTANCE_STRUCT = `struct Instance {
|
|
|
2221
2497
|
thick : f32, // 44 material thickness, CSS px
|
|
2222
2498
|
press : f32, // 48 interaction channel value, 0..1
|
|
2223
2499
|
glow : f32, // 52 interaction channel value, 0..1
|
|
2224
|
-
|
|
2500
|
+
lensThick : f32, // 56 authored thickness in CSS px times the lensStrength channel (W12 G2): both depths are evaluated from it per pixel
|
|
2225
2501
|
tintK : f32, // 60 author tint strength, 0..1 \u2014 the seed itself is a group uniform
|
|
2226
2502
|
span : f32, // 64 the surface's shorter extent, CSS px \u2014 the size law's input, both curves (W11c)
|
|
2227
2503
|
_pad : f32, // 68 stride padding: vec2f aligns the struct to 8, so 72 is the next legal size
|
|
@@ -2389,7 +2665,8 @@ var WGSL_FIELD_PASS = `struct FieldUniforms {
|
|
|
2389
2665
|
// field but its members are not one size, and carrying them per pixel is what
|
|
2390
2666
|
// lets a 40 px button and a 320 px platter share a field pass and still lens by
|
|
2391
2667
|
// their own depth \u2014 parent acceptance #2 inside a GlassEffectContainer.
|
|
2392
|
-
// aux
|
|
2668
|
+
// aux = (lensThickPx, glow, spanPx, tintStrength)
|
|
2669
|
+
// aux2 = (p \u2212 centre, half.x, half.y) \u2014 W12 G2, group-local CSS px
|
|
2393
2670
|
//
|
|
2394
2671
|
// The third and fourth slots both changed hands, and neither of the values they
|
|
2395
2672
|
// used to carry was ever read by a fragment stage. 'thick' left because
|
|
@@ -2423,14 +2700,25 @@ var WGSL_FIELD_PASS = `struct FieldUniforms {
|
|
|
2423
2700
|
// their SPANS and evaluates the curves on the blend, where it used to blend the
|
|
2424
2701
|
// evaluated thicknesses. Inside either member the two are identical; only the
|
|
2425
2702
|
// smooth-min neck differs, and nothing measured claims a value there.
|
|
2703
|
+
//
|
|
2704
|
+
// 'aux2' (W12 G2) carries the pixel's offset from the owning surface's centre
|
|
2705
|
+
// and that surface's half-extents, which
|
|
2706
|
+
// the optics pass needs for the lens's direction: the reference displaces along
|
|
2707
|
+
// the gradient of its SDF blended toward the oval inscribed in the shape's box
|
|
2708
|
+
// (claims \xA75.50's 'gradientOvalization'), and an oval is a property of the box,
|
|
2709
|
+
// not of the distance field. Blended by the same weight as 'aux' in a neck, so
|
|
2710
|
+
// two merged members share one oval there \u2014 a value nothing measured either.
|
|
2711
|
+
// For a concentric child the box is the parent's (the child is the parent's
|
|
2712
|
+
// level set), which is the same centre and a slightly larger oval.
|
|
2426
2713
|
|
|
2427
2714
|
@group(0) @binding(0) var<uniform> fu : FieldUniforms;
|
|
2428
2715
|
@group(0) @binding(1) var<storage, read> instances : array<Instance>;
|
|
2429
2716
|
|
|
2430
2717
|
struct Member {
|
|
2431
|
-
d
|
|
2432
|
-
g
|
|
2433
|
-
aux
|
|
2718
|
+
d : f32,
|
|
2719
|
+
g : vec2f,
|
|
2720
|
+
aux : vec4f,
|
|
2721
|
+
aux2 : vec4f,
|
|
2434
2722
|
};
|
|
2435
2723
|
|
|
2436
2724
|
fn eval_instance(i : u32, p : vec2f) -> Member {
|
|
@@ -2443,13 +2731,17 @@ fn eval_instance(i : u32, p : vec2f) -> Member {
|
|
|
2443
2731
|
var m : Member;
|
|
2444
2732
|
m.d = f.d + s.inset;
|
|
2445
2733
|
m.g = f.g;
|
|
2446
|
-
m.aux = vec4f(s.
|
|
2734
|
+
m.aux = vec4f(s.lensThick, s.glow, s.span, s.tintK);
|
|
2735
|
+
// The pixel relative to the surface's centre, and the half-extents: what the
|
|
2736
|
+
// oval's gradient needs, written here where the group-local position is exact.
|
|
2737
|
+
m.aux2 = vec4f(p - s.centre, s.half);
|
|
2447
2738
|
return m;
|
|
2448
2739
|
}
|
|
2449
2740
|
|
|
2450
2741
|
struct FieldOut {
|
|
2451
2742
|
@location(0) field : vec4f,
|
|
2452
2743
|
@location(1) aux : vec4f,
|
|
2744
|
+
@location(2) aux2 : vec4f,
|
|
2453
2745
|
};
|
|
2454
2746
|
|
|
2455
2747
|
@fragment
|
|
@@ -2467,6 +2759,7 @@ fn fs_field(in : FullscreenOut) -> FieldOut {
|
|
|
2467
2759
|
// coverage downstream is not reliably zero.
|
|
2468
2760
|
out.field = vec4f(65000.0, 0.0, -1.0, 0.0);
|
|
2469
2761
|
out.aux = vec4f(0.0);
|
|
2762
|
+
out.aux2 = vec4f(0.0);
|
|
2470
2763
|
return out;
|
|
2471
2764
|
}
|
|
2472
2765
|
|
|
@@ -2479,6 +2772,7 @@ fn fs_field(in : FullscreenOut) -> FieldOut {
|
|
|
2479
2772
|
acc.d = blend.x;
|
|
2480
2773
|
acc.g = mix(s.g, acc.g, h);
|
|
2481
2774
|
acc.aux = mix(s.aux, acc.aux, h);
|
|
2775
|
+
acc.aux2 = mix(s.aux2, acc.aux2, h);
|
|
2482
2776
|
nearest = min(nearest, s.d);
|
|
2483
2777
|
}
|
|
2484
2778
|
// One clamp at the end of the fold, so |union - min| <= maxBulge holds for any
|
|
@@ -2491,6 +2785,7 @@ fn fs_field(in : FullscreenOut) -> FieldOut {
|
|
|
2491
2785
|
|
|
2492
2786
|
out.field = vec4f(acc.d, normal.x, normal.y, coverage);
|
|
2493
2787
|
out.aux = acc.aux;
|
|
2788
|
+
out.aux2 = acc.aux2;
|
|
2494
2789
|
return out;
|
|
2495
2790
|
}`;
|
|
2496
2791
|
function fieldPassSource(family) {
|
|
@@ -2646,7 +2941,9 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
|
|
|
2646
2941
|
screen : vec4f,
|
|
2647
2942
|
/// backdrop uv transform on viewport-normalised coords: scale (xy), offset (zw)
|
|
2648
2943
|
fit : vec4f,
|
|
2649
|
-
/// refractionScale, lensRefractionGain (
|
|
2944
|
+
/// refractionScale, lensRefractionGain (W12 G2: the gain on the reference's
|
|
2945
|
+
/// amount law), the inner shadow's depth gain (W2's lensSizeGainMax, which the
|
|
2946
|
+
/// shadow keeps), chainMaxLod
|
|
2650
2947
|
lens : vec4f,
|
|
2651
2948
|
/// fixed tint colour, linear light (xyz), tint alpha (w)
|
|
2652
2949
|
tint : vec4f,
|
|
@@ -2677,17 +2974,22 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
|
|
|
2677
2974
|
toneAdapt : vec4f,
|
|
2678
2975
|
/// the backdrop source's own average colour, linear (xyz), and its luminance (w)
|
|
2679
2976
|
toneColour : vec4f,
|
|
2680
|
-
/// the outer shadow (W8
|
|
2681
|
-
///
|
|
2682
|
-
///
|
|
2683
|
-
///
|
|
2684
|
-
///
|
|
2685
|
-
///
|
|
2977
|
+
/// the outer shadow (W8, amplitude re-read by W14 G1): the THIN regime's peak
|
|
2978
|
+
/// LINEAR occlusion, already resolved at this group's backdrop luminance and
|
|
2979
|
+
/// already folded under the accessibility policy (x) \u2014 a linear occlusion and
|
|
2980
|
+
/// no longer a compositing alpha, because the shader now blends two regimes
|
|
2981
|
+
/// before it converts; the blur's sigma in group-local CSS px (y), the
|
|
2982
|
+
/// silhouette's outward spread in the same units (z), and the downward offset
|
|
2983
|
+
/// expressed in field-texture UV (w) \u2014 a UV so the offset silhouette is one
|
|
2984
|
+
/// texture read rather than a gradient extrapolation, which is exact only on a
|
|
2985
|
+
/// straight edge and a capsule is mostly not one
|
|
2686
2986
|
shadow : vec4f,
|
|
2687
2987
|
/// the outer shadow's size-law gain (x), read against the casting surface's own
|
|
2688
2988
|
/// thickness, and the field rect's height in CSS px (y) \u2014 the conversion the
|
|
2689
|
-
/// shadow's shift needs when it lands outside the texture;
|
|
2690
|
-
///
|
|
2989
|
+
/// shadow's shift needs when it lands outside the texture; the body depth
|
|
2990
|
+
/// ramp's THICK start (z, W13 G1's third form \u2014 the thin end is scatter.y and
|
|
2991
|
+
/// this pass mixes the two by the pixel's own sizeThickness), and (w) the
|
|
2992
|
+
/// padding a uniform's vec4 alignment requires
|
|
2691
2993
|
shadowSize : vec4f,
|
|
2692
2994
|
/// the backdrop tone response's anchors (W9): the three solid anchors'
|
|
2693
2995
|
/// ENCODED-space means (xyz), and the backdrop's linear-space mean (w) \u2014 the
|
|
@@ -2699,10 +3001,41 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
|
|
|
2699
3001
|
toneRowThin : vec4f,
|
|
2700
3002
|
/// the thick row (sizeThickness saturated), same layout
|
|
2701
3003
|
toneRowThick : vec4f,
|
|
2702
|
-
/// the size law's bands
|
|
2703
|
-
///
|
|
2704
|
-
///
|
|
3004
|
+
/// the size law's bands: the scatter facet's floor (x) and the depth ramp's
|
|
3005
|
+
/// THIN start s0 at the ratio this group draws at (y, W13 G1 \u2014 the CPU has
|
|
3006
|
+
/// already interpolated it between the profile's 1x and 2x anchors; the thick
|
|
3007
|
+
/// end is shadowSize.z), and the
|
|
3008
|
+
/// thickness curve's sizeSpanMin (z) and sizeSpanMax (w); the fold both
|
|
3009
|
+
/// multiply by is tone.w. The scatter span curve's own band top is lensOval.w,
|
|
3010
|
+
/// and it starts at the same z.
|
|
2705
3011
|
scatter : vec4f,
|
|
3012
|
+
/// the lens law (W12 G2): the reference's height law (lensHeightPerSpan,
|
|
3013
|
+
/// lensHeightMax) and amount law (lensAmountPerSpan, lensAmountMax)
|
|
3014
|
+
lensLaw : vec4f,
|
|
3015
|
+
/// the lens profile (W12 G2): lensExtentGain, lensProfileExponent,
|
|
3016
|
+
/// lensOvalization, lensThicknessReference
|
|
3017
|
+
lensShape : vec4f,
|
|
3018
|
+
/// the ovalization's knee (W12 G2): spanMin (x), spanMax (y); the body depth
|
|
3019
|
+
/// ramp's reach in group-local CSS px (z, W13 G1) \u2014 the profile names it in
|
|
3020
|
+
/// device px and the CPU divides by the ratio, so that this shader can read
|
|
3021
|
+
/// the field's own CSS-px depth without a second conversion; the scatter span
|
|
3022
|
+
/// curve's band top sizeScatterSpanMax (w, W11c), which W13 G1 keeps
|
|
3023
|
+
/// underneath the ramp as its deep value
|
|
3024
|
+
lensOval : vec4f,
|
|
3025
|
+
/// the outer shadow's THICK regime (W14 G1): the composite's peak linear
|
|
3026
|
+
/// occlusion at casting spans 96, 128 and 160 CSS px (xyz), already folded
|
|
3027
|
+
/// under the accessibility policy, piecewise-linear between and held outside;
|
|
3028
|
+
/// and (w) the body depth ramp's FAR start (W13 G1's fourth form) \u2014 the start
|
|
3029
|
+
/// at span >= sizeScatterSpanMax, which the ramp declines to from the thick
|
|
3030
|
+
/// end along the scatter span curve, in the slot W14 left free
|
|
3031
|
+
shadowThick : vec4f,
|
|
3032
|
+
/// the lift (W14 G1), the shadow's second term and GPU-tier only: its peak
|
|
3033
|
+
/// amplitude in LINEAR light as a fraction of the blurred backdrop's own
|
|
3034
|
+
/// luminance (x), the span rise's foot and top in CSS px (yz), and the chain
|
|
3035
|
+
/// LOD whose blur is the profile's liftBlurSigmaCss \u2014 resolved on the CPU,
|
|
3036
|
+
/// which is the only place the CSS-px-to-texel conversion is knowable, and
|
|
3037
|
+
/// already clamped to chainMaxLod (w)
|
|
3038
|
+
shadowLift : vec4f,
|
|
2706
3039
|
};
|
|
2707
3040
|
|
|
2708
3041
|
@group(0) @binding(0) var<uniform> ou : OpticsUniforms;
|
|
@@ -2712,6 +3045,9 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
|
|
|
2712
3045
|
@group(0) @binding(4) var backdropChain : texture_2d<f32>;
|
|
2713
3046
|
@group(0) @binding(5) var backdropBody : texture_2d<f32>;
|
|
2714
3047
|
@group(0) @binding(6) var fieldSampler : sampler;
|
|
3048
|
+
/// The owning surface's box per pixel (W12 G2): the pixel's offset from its
|
|
3049
|
+
/// centre (xy) and its half-extents (zw), group-local CSS px \u2014 the lens's oval.
|
|
3050
|
+
@group(0) @binding(7) var aux2Texture : texture_2d<f32>;
|
|
2715
3051
|
|
|
2716
3052
|
/// One encoded sRGB channel from a linear one \u2014 the space the backdrop tone
|
|
2717
3053
|
/// response's anchors live in (W9). Mirrors material.ts's 'linearToSrgbChannel'.
|
|
@@ -2767,7 +3103,33 @@ fn outer_shadow_falloff(signedDistance : f32, sigma : f32) -> f32 {
|
|
|
2767
3103
|
return 0.5 * (1.0 + tanh(0.7978845608028654 * (x + 0.044715 * x * x * x)));
|
|
2768
3104
|
}
|
|
2769
3105
|
|
|
2770
|
-
///
|
|
3106
|
+
/// What one pixel's outer shadow is made of: the compositing-space alpha the
|
|
3107
|
+
/// black term composites at, the falloff BOTH terms ride, and the span of the
|
|
3108
|
+
/// surface that cast it \u2014 which the lift's own rise is read from.
|
|
3109
|
+
///
|
|
3110
|
+
/// One struct rather than three calls because there is one falloff (W14 G0,
|
|
3111
|
+
/// claims \xA75.62 \xA74): the black term's free fit and the lift's free fit return
|
|
3112
|
+
/// the same sigma, offset and spread, so evaluating a second geometry for the
|
|
3113
|
+
/// second term would be asserting a difference the measurement denies.
|
|
3114
|
+
struct ShadowSample {
|
|
3115
|
+
alpha : f32,
|
|
3116
|
+
falloff : f32,
|
|
3117
|
+
castSpanCss : f32,
|
|
3118
|
+
};
|
|
3119
|
+
|
|
3120
|
+
/// The composite's peak linear occlusion above the knee, at a casting span \u2014
|
|
3121
|
+
/// piecewise linear through the three measured anchors (96 / 128 / 160 CSS px)
|
|
3122
|
+
/// and held flat outside them. Mirrors material.ts's
|
|
3123
|
+
/// 'outerShadowThickOcclusion'.
|
|
3124
|
+
fn outer_shadow_thick(spanCss : f32) -> f32 {
|
|
3125
|
+
let y = ou.shadowThick.xyz;
|
|
3126
|
+
if (spanCss <= 96.0) { return y.x; }
|
|
3127
|
+
if (spanCss >= 160.0) { return y.z; }
|
|
3128
|
+
if (spanCss <= 128.0) { return y.x + (y.y - y.x) * (spanCss - 96.0) / 32.0; }
|
|
3129
|
+
return y.y + (y.z - y.y) * (spanCss - 128.0) / 32.0;
|
|
3130
|
+
}
|
|
3131
|
+
|
|
3132
|
+
/// The outer shadow's alpha at this pixel (W8, amplitude W14 G1).
|
|
2771
3133
|
///
|
|
2772
3134
|
/// The shadow is the group's OWN field, translated down by 'shadow.w' in field
|
|
2773
3135
|
/// UV and outset by 'shadow.z', then blurred. Reading the offset silhouette from
|
|
@@ -2778,9 +3140,13 @@ fn outer_shadow_falloff(signedDistance : f32, sigma : f32) -> f32 {
|
|
|
2778
3140
|
/// The value is an ALPHA on pure black, so what it composites to is the backdrop
|
|
2779
3141
|
/// times '1 - alpha' \u2014 multiplicative occlusion, and exactly zero over black,
|
|
2780
3142
|
/// with no branch for it.
|
|
2781
|
-
fn
|
|
2782
|
-
|
|
2783
|
-
|
|
3143
|
+
fn outer_shadow(uv : vec2f, upsampled : f32, fieldSize : vec2f) -> ShadowSample {
|
|
3144
|
+
var out : ShadowSample;
|
|
3145
|
+
out.alpha = 0.0;
|
|
3146
|
+
out.falloff = 0.0;
|
|
3147
|
+
out.castSpanCss = 0.0;
|
|
3148
|
+
if (ou.shadow.x <= 0.0 && ou.shadowThick.x <= 0.0) {
|
|
3149
|
+
return out;
|
|
2784
3150
|
}
|
|
2785
3151
|
/*
|
|
2786
3152
|
* The shift can leave the field texture, and clamping alone reads a lie there.
|
|
@@ -2816,14 +3182,11 @@ fn outer_shadow_alpha(uv : vec2f, upsampled : f32, fieldSize : vec2f) -> f32 {
|
|
|
2816
3182
|
}
|
|
2817
3183
|
|
|
2818
3184
|
// The size law reaches the amplitude and nothing else \u2014 the reference's three
|
|
2819
|
-
// lengths are span-invariant across 32\u2026160 px.
|
|
2820
|
-
// the
|
|
2821
|
-
// position rather than the one under the pixel
|
|
3185
|
+
// lengths are span-invariant across 32\u2026160 px. Every span-keyed quantity here
|
|
3186
|
+
// rides the thickness and the span of the surface that CAST the shadow, which
|
|
3187
|
+
// is the one read at the offset position rather than the one under the pixel
|
|
3188
|
+
// being shaded.
|
|
2822
3189
|
//
|
|
2823
|
-
// Applied on '1 - alpha' rather than on the alpha: the gain is a fraction of
|
|
2824
|
-
// the remaining transparency in LINEAR light ('sizeOuterShadowOcclusionAt'),
|
|
2825
|
-
// and (1 - occ) is exactly what raising to 1/2.4 turns into (1 - alpha), so the
|
|
2826
|
-
// two forms are the same law and neither needs the other's space.
|
|
2827
3190
|
// The thickness curve off the casting surface's span (W11c: the span rides
|
|
2828
3191
|
// the field), written as the body's own is below.
|
|
2829
3192
|
let castT = clamp(
|
|
@@ -2832,10 +3195,65 @@ fn outer_shadow_alpha(uv : vec2f, upsampled : f32, fieldSize : vec2f) -> f32 {
|
|
|
2832
3195
|
1.0,
|
|
2833
3196
|
);
|
|
2834
3197
|
let sizeK = clamp(castT * castT * (3.0 - 2.0 * castT) * clamp(ou.tone.w, 0.0, 1.0), 0.0, 1.0);
|
|
2835
|
-
let sizeFold = pow(max(1.0 - ou.shadowSize.x * sizeK, 0.0), 1.0 / 2.4);
|
|
2836
|
-
let alpha = 1.0 - (1.0 - ou.shadow.x) * sizeFold;
|
|
2837
3198
|
|
|
2838
|
-
|
|
3199
|
+
// The two regimes and the knee between them (W14 G1). The thin amplitude is
|
|
3200
|
+
// resolved on the CPU because its key \u2014 the backdrop's luminance \u2014 is one
|
|
3201
|
+
// number for the whole group; the thick one is a span law and has to be per
|
|
3202
|
+
// pixel. The blend is the smoothstep of 'sizeK', which is exactly the curve
|
|
3203
|
+
// 'tone_response' blends its own thin and thick rows across: one knee for the
|
|
3204
|
+
// face and the shadow, which is the charter's third binding rule read from
|
|
3205
|
+
// the other side.
|
|
3206
|
+
let blend = sizeK * sizeK * (3.0 - 2.0 * sizeK);
|
|
3207
|
+
let regime = mix(ou.shadow.x, outer_shadow_thick(shadowAux.z), blend);
|
|
3208
|
+
// The size gain, on the relative form 'sizeOuterShadowOcclusionAt' uses, in
|
|
3209
|
+
// LINEAR light; then the one conversion to the canvas's compositing space,
|
|
3210
|
+
// which is where the black term is actually composited.
|
|
3211
|
+
let occ = clamp(regime + ou.shadowSize.x * sizeK * (1.0 - regime), 0.0, 1.0);
|
|
3212
|
+
out.alpha = 1.0 - pow(1.0 - occ, 1.0 / 2.4);
|
|
3213
|
+
out.falloff = outer_shadow_falloff(shadowField.x + clampedOffCss - ou.shadow.z, ou.shadow.y);
|
|
3214
|
+
out.castSpanCss = shadowAux.z;
|
|
3215
|
+
return out;
|
|
3216
|
+
}
|
|
3217
|
+
|
|
3218
|
+
/// The lift (W14 G1) \u2014 the shadow's second term, in LINEAR light, premultiplied
|
|
3219
|
+
/// by nothing yet: a blurred copy of the backdrop's own light, at an amplitude
|
|
3220
|
+
/// that is zero below the knee and saturating above it, on the SAME falloff the
|
|
3221
|
+
/// black term rides.
|
|
3222
|
+
///
|
|
3223
|
+
/// 'V' is the backdrop chain read at the pixel's OWN position \u2014 the copy is of
|
|
3224
|
+
/// the backdrop beneath the shadow, not of the backdrop under the surface \u2014 at
|
|
3225
|
+
/// the LOD whose blur is the profile's 40 CSS px. The chain's uv transform is on
|
|
3226
|
+
/// viewport-normalised coordinates, so every pixel this pass draws has a valid
|
|
3227
|
+
/// sample: unlike the field texture, which the offset shift can walk off the top
|
|
3228
|
+
/// of, the chain covers the whole viewport and there is nothing to reconstruct.
|
|
3229
|
+
///
|
|
3230
|
+
/// Zero over black by construction (V = 0), zero below the knee by the rise, and
|
|
3231
|
+
/// zero where the group has no backdrop to copy \u2014 so 'dark-solid', 'impulse',
|
|
3232
|
+
/// every thin cell and every unsampled group stay byte-for-byte what they were.
|
|
3233
|
+
fn outer_shadow_lift(viewport01 : vec2f, shadow : ShadowSample) -> vec3f {
|
|
3234
|
+
if (ou.flags.x <= 0.5 || ou.shadowLift.x <= 0.0 || shadow.falloff <= 0.0) {
|
|
3235
|
+
return vec3f(0.0);
|
|
3236
|
+
}
|
|
3237
|
+
// Written out rather than through WGSL's 'smoothstep', which is undefined
|
|
3238
|
+
// where the two edges coincide \u2014 a profile is entitled to set the rise's foot
|
|
3239
|
+
// and top to one number, and material.ts's own 'smoothstep' degrades that to a
|
|
3240
|
+
// step rather than to a NaN. Same rule as the tone band's divide above.
|
|
3241
|
+
let riseT = clamp(
|
|
3242
|
+
(shadow.castSpanCss - ou.shadowLift.y) / max(ou.shadowLift.z - ou.shadowLift.y, 1e-6),
|
|
3243
|
+
0.0,
|
|
3244
|
+
1.0,
|
|
3245
|
+
);
|
|
3246
|
+
let rise = riseT * riseT * (3.0 - 2.0 * riseT);
|
|
3247
|
+
if (rise <= 0.0) {
|
|
3248
|
+
return vec3f(0.0);
|
|
3249
|
+
}
|
|
3250
|
+
let uv = clamp(viewport01 * ou.fit.xy + ou.fit.zw, vec2f(0.0), vec2f(1.0));
|
|
3251
|
+
let chainSample = textureSampleLevel(backdropChain, backdropSampler, uv, ou.shadowLift.w);
|
|
3252
|
+
// Premultiplied linear in, straight colour out \u2014 the same unpremultiply the
|
|
3253
|
+
// body's own samples take, for the same reason: a partially transparent
|
|
3254
|
+
// backdrop must not darken what the material adds back.
|
|
3255
|
+
let v = chainSample.rgb / max(chainSample.a, 1e-6);
|
|
3256
|
+
return v * (ou.shadowLift.x * rise * shadow.falloff);
|
|
2839
3257
|
}
|
|
2840
3258
|
|
|
2841
3259
|
@fragment
|
|
@@ -2847,13 +3265,16 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
2847
3265
|
// contour to the coarse grid and the rim would step along it.
|
|
2848
3266
|
var field : vec4f;
|
|
2849
3267
|
var aux : vec4f;
|
|
3268
|
+
var aux2 : vec4f;
|
|
2850
3269
|
if (ou.flags.w > 0.5) {
|
|
2851
3270
|
field = textureSampleLevel(fieldTexture, fieldSampler, in.uv, 0.0);
|
|
2852
3271
|
aux = textureSampleLevel(auxTexture, fieldSampler, in.uv, 0.0);
|
|
3272
|
+
aux2 = textureSampleLevel(aux2Texture, fieldSampler, in.uv, 0.0);
|
|
2853
3273
|
} else {
|
|
2854
3274
|
let texel = vec2i(in.uv * ou.flags.yz);
|
|
2855
3275
|
field = textureLoad(fieldTexture, texel, 0);
|
|
2856
3276
|
aux = textureLoad(auxTexture, texel, 0);
|
|
3277
|
+
aux2 = textureLoad(aux2Texture, texel, 0);
|
|
2857
3278
|
}
|
|
2858
3279
|
|
|
2859
3280
|
let d = field.x;
|
|
@@ -2869,46 +3290,172 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
2869
3290
|
* is clipped out of its own border box, and the two meet across the coverage
|
|
2870
3291
|
* ramp with no seam because it is one expression.
|
|
2871
3292
|
*/
|
|
2872
|
-
let
|
|
3293
|
+
let shadowSample = outer_shadow(in.uv, ou.flags.w, ou.flags.yz);
|
|
3294
|
+
let shadowAlpha = shadowSample.alpha * shadowSample.falloff;
|
|
3295
|
+
let viewport01 = in.position.xy / ou.screen.xy;
|
|
3296
|
+
// Resolved once, for both sides of the coverage ramp: the lift fills exactly
|
|
3297
|
+
// what the surface's coverage leaves, on the same rule and in the same
|
|
3298
|
+
// expression as the black term's alpha at the bottom of this function, so the
|
|
3299
|
+
// two meet across the ramp with no seam. At full coverage it is not computed
|
|
3300
|
+
// at all and the chain read is not taken.
|
|
3301
|
+
var liftEncoded = vec3f(0.0);
|
|
3302
|
+
if (coverage < 1.0) {
|
|
3303
|
+
let lift = outer_shadow_lift(viewport01, shadowSample);
|
|
3304
|
+
liftEncoded = min(linear_to_srgb(max(lift, vec3f(0.0))), vec3f(shadowAlpha));
|
|
3305
|
+
}
|
|
2873
3306
|
if (coverage <= 0.0) {
|
|
2874
|
-
|
|
3307
|
+
/*
|
|
3308
|
+
* The lift (W14 G1) makes this a premultiplied COMPOSITE rather than an
|
|
3309
|
+
* alpha on black: the compositor produces 'page\xB7(1 \u2212 shadowAlpha) + lift',
|
|
3310
|
+
* which is the reference's own two-term form outside the coverage.
|
|
3311
|
+
*
|
|
3312
|
+
* The added light is computed in linear light and encoded on its own before
|
|
3313
|
+
* it is emitted, because it IS its own light \u2014 over the checkerboard's black
|
|
3314
|
+
* squares, where the multiply is inert, what the reference adds is exactly
|
|
3315
|
+
* this term and nothing else, and encoding it alone reproduces G0's measured
|
|
3316
|
+
* +0.048 encoded at span 160 from its +0.0038 linear (claims \xA75.62 \xA72, \xA73).
|
|
3317
|
+
* Where the backdrop is bright the encoding of a sum and the sum of the
|
|
3318
|
+
* encodings differ, and this term is the second: the residual is bounded by
|
|
3319
|
+
* the term's own size and is well inside the bed's \xB14/255, on the same
|
|
3320
|
+
* honest-floor argument 'outerShadowAlpha' makes for the black term's space.
|
|
3321
|
+
*
|
|
3322
|
+
* A premultiplied layer may not carry a channel above its own alpha, so the
|
|
3323
|
+
* emitted light is capped at 'shadowAlpha'. At the profile's constants the
|
|
3324
|
+
* cap is inert everywhere on the falloff: both terms are proportional to the
|
|
3325
|
+
* same F, and the lift's encoded value stays at about a sixth of the black
|
|
3326
|
+
* term's alpha from the deepest ring out to where the shadow stops moving a
|
|
3327
|
+
* code. It is here so that a swept amplitude produces a valid layer rather
|
|
3328
|
+
* than an implementation-defined one.
|
|
3329
|
+
*/
|
|
3330
|
+
return vec4f(liftEncoded, shadowAlpha);
|
|
2875
3331
|
}
|
|
2876
3332
|
|
|
2877
|
-
let viewport01 = in.position.xy / ou.screen.xy;
|
|
2878
3333
|
let viewportCss = ou.screen.xy * ou.screen.z;
|
|
2879
3334
|
|
|
2880
|
-
// Per-pixel, unioned through the field pass. See the module note.
|
|
2881
|
-
|
|
2882
|
-
//
|
|
3335
|
+
// Per-pixel, unioned through the field pass. See the module note. 'aux.x' is
|
|
3336
|
+
// the authored thickness times the lensStrength channel (W12 G2); the lens's
|
|
3337
|
+
// depth and the inner shadow's are both evaluated from it and the span below.
|
|
3338
|
+
let lensThick = max(aux.x, 0.0);
|
|
3339
|
+
// The thickness curve off the span of whichever surface owns this pixel
|
|
2883
3340
|
// (W11c). 'sizeK' is the thickness factor, 0..1: zero on anything at or below
|
|
2884
3341
|
// the profile's 'sizeSpanMin', saturated at 'sizeSpanMax', folded under the
|
|
2885
3342
|
// preference \u2014 the occlusion, the inner shadow and the tone response multiply
|
|
2886
|
-
// by it, so a small control takes the pre-law path exactly.
|
|
2887
|
-
//
|
|
2888
|
-
// 'sizeScatterSpanMax' \xB7 fold: the floor is the material's frost at any size
|
|
2889
|
-
// and is not folded, the rise is depth and is. Both written out as
|
|
2890
|
-
// smoothsteps with a guarded denominator, so a profile that collapses a band
|
|
3343
|
+
// by it, so a small control takes the pre-law path exactly. Written out as a
|
|
3344
|
+
// smoothstep with a guarded denominator, so a profile that collapses the band
|
|
2891
3345
|
// degrades to a step rather than to NaN.
|
|
2892
3346
|
let span = aux.z;
|
|
2893
3347
|
let fold = clamp(ou.tone.w, 0.0, 1.0);
|
|
2894
3348
|
let thickT = clamp((span - ou.scatter.z) / max(ou.scatter.w - ou.scatter.z, 1e-6), 0.0, 1.0);
|
|
2895
|
-
|
|
3349
|
+
// The unfolded curve, which the depth ramp's start grades along below, and the
|
|
3350
|
+
// folded factor every other facet multiplies by. One smoothstep, two readings.
|
|
3351
|
+
let sizeThick = thickT * thickT * (3.0 - 2.0 * thickT);
|
|
3352
|
+
let sizeK = clamp(sizeThick * fold, 0.0, 1.0);
|
|
3353
|
+
/*
|
|
3354
|
+
* The body's mix is the span curve W11c fitted with a ramp in DEPTH riding on
|
|
3355
|
+
* top of it near the contour (W13 G1, from the measurement of claims \xA75.61 \xA72
|
|
3356
|
+
* and the re-forming its first runtime sweep forced):
|
|
3357
|
+
*
|
|
3358
|
+
* kDeep = floor + (1 - floor) * smoothstep(sizeSpanMin, sizeScatterSpanMax, span)
|
|
3359
|
+
* s0 = startThin + (startThick - startThin) * sizeThickness(span)
|
|
3360
|
+
* + (startFar - startThick) * smoothstep(sizeSpanMax, sizeScatterSpanMax, span)
|
|
3361
|
+
* s(u) = (1 - kDeep) + max(0, s0 - (1 - kDeep)) * max(0, 1 - u / U)
|
|
3362
|
+
* k(u) = 1 - s(u)
|
|
3363
|
+
*
|
|
3364
|
+
* The first form of the ramp replaced the span curve outright and its sweep
|
|
3365
|
+
* measured what that cost: the ramp's own projection onto one number per
|
|
3366
|
+
* surface runs 0.43-0.56 where the curve it replaced runs 0.41-1.00, so the
|
|
3367
|
+
* family is nearly span-flat where the bed is strongly span-graded and no
|
|
3368
|
+
* point in 81 reached the wave's stops. So the curve stays as the deep value
|
|
3369
|
+
* and the ramp is what it always measured as - a near-contour excursion.
|
|
3370
|
+
*
|
|
3371
|
+
* The SECOND form gave that excursion one start per scale, and its own sweep
|
|
3372
|
+
* refuted that arithmetically (claims \xA75.64 \xA72): the smallest cell's span is
|
|
3373
|
+
* exactly sizeSpanMin, so its deep sharp share is exactly 1 - floor and no
|
|
3374
|
+
* start at or below it can touch that cell, while the next span up only
|
|
3375
|
+
* improves BELOW a start lower still. So the start grades with span too, and
|
|
3376
|
+
* along the material's own thin/thick curve rather than a new one - the same
|
|
3377
|
+
* smoothstep 'sizeK' is built from above, unfolded, because s0 is a share the
|
|
3378
|
+
* reference has and not a rise a preference removes. The fold below still
|
|
3379
|
+
* applies once, on the composed mix.
|
|
3380
|
+
*
|
|
3381
|
+
* The THIRD form stopped there and its holdout failed on one row for the
|
|
3382
|
+
* form's own arithmetic (claims \xA75.67 \xA74): sizeThickness saturates at
|
|
3383
|
+
* sizeSpanMax, so every thick span got the same start while the reference's
|
|
3384
|
+
* start keeps FALLING across the thick spans, and because kDeep keeps rising
|
|
3385
|
+
* to sizeScatterSpanMax the excursion grew with span where the reference's
|
|
3386
|
+
* shrinks. So the FOURTH form declines the start past the knee along the
|
|
3387
|
+
* scatter span curve itself \u2014 the same smoothstep 'deepT' is built from, on
|
|
3388
|
+
* the band above the thickness knee \u2014 from the thick anchor to startFar at
|
|
3389
|
+
* sizeScatterSpanMax. Same curve read twice, no new span statistic.
|
|
3390
|
+
*
|
|
3391
|
+
* '-d' is the depth, in group-local CSS px and unclamped - the same quantity
|
|
3392
|
+
* the lens's 'lensT' and the inner shadow's 'shadowT' are evaluated from,
|
|
3393
|
+
* except that those two divide it by a depth of their own while this reads it
|
|
3394
|
+
* absolutely, because the reach measured as a LENGTH rather than as a fraction
|
|
3395
|
+
* of the span. The reach reaches this shader already divided by the device
|
|
3396
|
+
* ratio ('lensOval.z'), so the ratio 'u / U' is the same number in CSS px as
|
|
3397
|
+
* it is in the device px the profile names.
|
|
3398
|
+
*
|
|
3399
|
+
* 'max(s0 - sDeep, 0)' rather than a signed difference: the excursion is the
|
|
3400
|
+
* band the reference has ABOVE the body, and a span whose deep sharp share
|
|
3401
|
+
* already exceeds s0 has nothing to add rather than something to subtract.
|
|
3402
|
+
*
|
|
3403
|
+
* The fold keeps its W11c semantics on the composed law: the floor is the
|
|
3404
|
+
* frost the material has at any size and is not folded, everything above it -
|
|
3405
|
+
* the span curve's rise and the ramp's excursion alike - is depth and is, so
|
|
3406
|
+
* fold 1 renders the law and fold 0 sits at the floor exactly.
|
|
3407
|
+
*/
|
|
2896
3408
|
let scatterFloor = clamp(ou.scatter.x, 0.0, 1.0);
|
|
2897
|
-
let
|
|
2898
|
-
let
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
);
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
let
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
//
|
|
2910
|
-
//
|
|
2911
|
-
|
|
3409
|
+
let deepT = clamp((span - ou.scatter.z) / max(ou.lensOval.w - ou.scatter.z, 1e-6), 0.0, 1.0);
|
|
3410
|
+
let kDeep = scatterFloor + (1.0 - scatterFloor) * deepT * deepT * (3.0 - 2.0 * deepT);
|
|
3411
|
+
let sDeep = 1.0 - kDeep;
|
|
3412
|
+
let rampT = max(1.0 - max(-d, 0.0) / max(ou.lensOval.z, 1e-6), 0.0);
|
|
3413
|
+
let farT = clamp((span - ou.scatter.w) / max(ou.lensOval.w - ou.scatter.w, 1e-6), 0.0, 1.0);
|
|
3414
|
+
let farS = farT * farT * (3.0 - 2.0 * farT);
|
|
3415
|
+
let rampStart = ou.scatter.y + (ou.shadowSize.z - ou.scatter.y) * sizeThick
|
|
3416
|
+
+ (ou.shadowThick.w - ou.shadowSize.z) * farS;
|
|
3417
|
+
let sharpShare = clamp(sDeep + max(rampStart - sDeep, 0.0) * rampT, 0.0, 1.0);
|
|
3418
|
+
let kScatter = clamp(scatterFloor + ((1.0 - sharpShare) - scatterFloor) * fold, 0.0, 1.0);
|
|
3419
|
+
// The inner shadow's depth and profile: W2's law, byte for byte \u2014 the
|
|
3420
|
+
// thickness times the size gain (folded through 'sizeK'), clamped to the
|
|
3421
|
+
// shorter half extent, and a square on it. The lens ran on this until W12 G2;
|
|
3422
|
+
// the occlusion keeps it, because nothing measured it as wrong, and every
|
|
3423
|
+
// solid-backdrop cell renders exactly as it did.
|
|
3424
|
+
let shadowLensDepth = max(min(lensThick * (1.0 + (ou.lens.z - 1.0) * sizeK), span * 0.5), 1e-4);
|
|
3425
|
+
let shadowT = clamp(-d / shadowLensDepth, 0.0, 1.0);
|
|
3426
|
+
let shadowProfile = (1.0 - shadowT) * (1.0 - shadowT);
|
|
3427
|
+
|
|
3428
|
+
// The lens (W12 G2, claims \xA75.51) \u2014 see the module note. The reference's
|
|
3429
|
+
// height and amount laws off the span, scaled by the thickness over the
|
|
3430
|
+
// reference's unit, folded like the W2 law (at fold 0 the depth is the
|
|
3431
|
+
// authored thickness and nothing more), and clamped to the shorter half
|
|
3432
|
+
// extent with the magnitude clamped by the same ratio.
|
|
3433
|
+
let thickScale = lensThick / max(ou.lensShape.w, 1e-4);
|
|
3434
|
+
let heightBase = min(ou.lensLaw.x * span, ou.lensLaw.y);
|
|
3435
|
+
let amountBase = min(ou.lensLaw.z * span, ou.lensLaw.w);
|
|
3436
|
+
let depthUnclamped = mix(lensThick, heightBase * thickScale, fold);
|
|
3437
|
+
let lensDepth = clamp(depthUnclamped, 0.0, span * 0.5);
|
|
3438
|
+
let clampRatio = select(0.0, lensDepth / depthUnclamped, depthUnclamped > 1e-6);
|
|
3439
|
+
let magnitude = ou.lens.y * mix(lensThick, amountBase * thickScale, fold) * clampRatio;
|
|
3440
|
+
let extent = max(ou.lensShape.x * lensDepth, 1e-4);
|
|
3441
|
+
// One steep power over the extent; '-d' is depth inside the surface.
|
|
3442
|
+
let lensT = max(1.0 - max(-d, 0.0) / extent, 0.0);
|
|
3443
|
+
let displacementCss = magnitude * pow(lensT, ou.lensShape.y) * ou.lens.x;
|
|
3444
|
+
|
|
3445
|
+
// The direction: the field's gradient blended toward the oval inscribed in
|
|
3446
|
+
// the surface's box (the reference's 'gradientOvalization'), on from the
|
|
3447
|
+
// knee, with the magnitude fixed \u2014 which tilts the displacement toward the
|
|
3448
|
+
// edge's midpoint and magnifies the band along the edge.
|
|
3449
|
+
let ovalT = clamp((span - ou.lensOval.x) / max(ou.lensOval.y - ou.lensOval.x, 1e-6), 0.0, 1.0);
|
|
3450
|
+
let omega = ou.lensShape.z * ovalT * ovalT * (3.0 - 2.0 * ovalT);
|
|
3451
|
+
let halfExt = max(aux2.zw, vec2f(1e-4));
|
|
3452
|
+
let rel = aux2.xy;
|
|
3453
|
+
let unitR = max(length(rel / halfExt), 1e-6);
|
|
3454
|
+
let ovalGrad = (rel / (halfExt * halfExt)) * (min(halfExt.x, halfExt.y) / unitR);
|
|
3455
|
+
let blended = (1.0 - omega) * normal + omega * ovalGrad;
|
|
3456
|
+
let blendLen = length(blended);
|
|
3457
|
+
let direction = select(normal, blended / blendLen, blendLen > 1e-6);
|
|
3458
|
+
let displaceCss = -direction * displacementCss;
|
|
2912
3459
|
let refracted01 = viewport01 + displaceCss / viewportCss;
|
|
2913
3460
|
|
|
2914
3461
|
let refractedUv = clamp(refracted01 * ou.fit.xy + ou.fit.zw, vec2f(0.0), vec2f(1.0));
|
|
@@ -3160,7 +3707,7 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
3160
3707
|
// A multiplicative occlusion of the whole composite. As a layer that is the
|
|
3161
3708
|
// colour scaled and the alpha raised \u2014 (k\xB7a\xB7c, 1 \u2212 k\xB7(1 \u2212 a)) composites to
|
|
3162
3709
|
// k times what (a\xB7c, a) would \u2014 and at bodyAlpha 1 it is the plain product.
|
|
3163
|
-
let shadowKeep = 1.0 -
|
|
3710
|
+
let shadowKeep = 1.0 - shadowProfile * shadowDepth * ou.light.w * present;
|
|
3164
3711
|
let shadowedAlpha = 1.0 - shadowKeep * (1.0 - bodyAlpha);
|
|
3165
3712
|
colour = colour * (shadowKeep * bodyAlpha / max(shadowedAlpha, 1e-6));
|
|
3166
3713
|
bodyAlpha = shadowedAlpha;
|
|
@@ -3198,7 +3745,10 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
3198
3745
|
// an opaque body the two are the same quantity, which is how the shadow was
|
|
3199
3746
|
// first written and why the difference only surfaced with the layer form.)
|
|
3200
3747
|
let body = encode_output(max(colour, vec3f(0.0)), coverage * bodyAlpha);
|
|
3201
|
-
return vec4f(
|
|
3748
|
+
return vec4f(
|
|
3749
|
+
body.rgb + liftEncoded * (1.0 - coverage),
|
|
3750
|
+
body.a + shadowAlpha * (1.0 - coverage),
|
|
3751
|
+
);
|
|
3202
3752
|
}`;
|
|
3203
3753
|
|
|
3204
3754
|
// ../renderer-webgpu/dist/wgsl/prelude.js
|
|
@@ -3326,7 +3876,11 @@ function createPassRunner(context) {
|
|
|
3326
3876
|
fragment: {
|
|
3327
3877
|
module,
|
|
3328
3878
|
entryPoint: "fs_field",
|
|
3329
|
-
targets: [
|
|
3879
|
+
targets: [
|
|
3880
|
+
{ format: WORKING_TEXTURE_FORMAT },
|
|
3881
|
+
{ format: WORKING_TEXTURE_FORMAT },
|
|
3882
|
+
{ format: WORKING_TEXTURE_FORMAT }
|
|
3883
|
+
]
|
|
3330
3884
|
},
|
|
3331
3885
|
primitive: { topology: "triangle-list" }
|
|
3332
3886
|
};
|
|
@@ -3390,6 +3944,13 @@ function createPassRunner(context) {
|
|
|
3390
3944
|
usage: fieldUsage(),
|
|
3391
3945
|
label: `vitrea:group:${args.groupId}:aux`
|
|
3392
3946
|
});
|
|
3947
|
+
const aux2 = pool.acquire(poolKey.groupAux2(args.groupId), {
|
|
3948
|
+
width,
|
|
3949
|
+
height,
|
|
3950
|
+
format: WORKING_TEXTURE_FORMAT,
|
|
3951
|
+
usage: fieldUsage(),
|
|
3952
|
+
label: `vitrea:group:${args.groupId}:aux2`
|
|
3953
|
+
});
|
|
3393
3954
|
const slot = uniformSlot(`field:${args.groupId}`, 12);
|
|
3394
3955
|
slot.data[0] = rectWidth;
|
|
3395
3956
|
slot.data[1] = rectHeight;
|
|
@@ -3423,6 +3984,12 @@ function createPassRunner(context) {
|
|
|
3423
3984
|
loadOp: "clear",
|
|
3424
3985
|
storeOp: "store",
|
|
3425
3986
|
clearValue: { r: 0, g: 0, b: 0, a: 0 }
|
|
3987
|
+
},
|
|
3988
|
+
{
|
|
3989
|
+
view: aux2.createView(),
|
|
3990
|
+
loadOp: "clear",
|
|
3991
|
+
storeOp: "store",
|
|
3992
|
+
clearValue: { r: 0, g: 0, b: 0, a: 0 }
|
|
3426
3993
|
}
|
|
3427
3994
|
]
|
|
3428
3995
|
});
|
|
@@ -3439,13 +4006,14 @@ function createPassRunner(context) {
|
|
|
3439
4006
|
return {
|
|
3440
4007
|
field,
|
|
3441
4008
|
aux,
|
|
4009
|
+
aux2,
|
|
3442
4010
|
width,
|
|
3443
4011
|
height,
|
|
3444
4012
|
upsampled: width !== rectWidth || height !== rectHeight
|
|
3445
4013
|
};
|
|
3446
4014
|
},
|
|
3447
4015
|
opticsPass(encoder, args) {
|
|
3448
|
-
const slot = uniformSlot(`optics:${args.groupId}`,
|
|
4016
|
+
const slot = uniformSlot(`optics:${args.groupId}`, 96);
|
|
3449
4017
|
const d = slot.data;
|
|
3450
4018
|
d[0] = args.viewportDevice[0];
|
|
3451
4019
|
d[1] = args.viewportDevice[1];
|
|
@@ -3457,7 +4025,7 @@ function createPassRunner(context) {
|
|
|
3457
4025
|
d[7] = args.fit[3];
|
|
3458
4026
|
d[8] = args.refractionScale;
|
|
3459
4027
|
d[9] = args.lensRefractionGain;
|
|
3460
|
-
d[10] =
|
|
4028
|
+
d[10] = args.shadowDepthSizeGainMax;
|
|
3461
4029
|
d[11] = args.chainMaxLod;
|
|
3462
4030
|
d[12] = args.tint[0];
|
|
3463
4031
|
d[13] = args.tint[1];
|
|
@@ -3505,7 +4073,7 @@ function createPassRunner(context) {
|
|
|
3505
4073
|
d[55] = args.outerShadow[3];
|
|
3506
4074
|
d[56] = args.outerShadowSizeGain;
|
|
3507
4075
|
d[57] = args.outerShadowRectCssHeight;
|
|
3508
|
-
d[58] =
|
|
4076
|
+
d[58] = args.sizeScatterRampStartThick;
|
|
3509
4077
|
d[59] = 0;
|
|
3510
4078
|
d[60] = args.backdropToneAnchorX[0];
|
|
3511
4079
|
d[61] = args.backdropToneAnchorX[1];
|
|
@@ -3520,9 +4088,29 @@ function createPassRunner(context) {
|
|
|
3520
4088
|
d[70] = args.backdropToneResponseThick[2];
|
|
3521
4089
|
d[71] = 0;
|
|
3522
4090
|
d[72] = args.sizeScatterFloor;
|
|
3523
|
-
d[73] = args.
|
|
4091
|
+
d[73] = args.sizeScatterRampStartThin;
|
|
3524
4092
|
d[74] = args.sizeSpanMin;
|
|
3525
4093
|
d[75] = args.sizeSpanMax;
|
|
4094
|
+
d[76] = args.lensHeightPerSpan;
|
|
4095
|
+
d[77] = args.lensHeightMax;
|
|
4096
|
+
d[78] = args.lensAmountPerSpan;
|
|
4097
|
+
d[79] = args.lensAmountMax;
|
|
4098
|
+
d[80] = args.lensExtentGain;
|
|
4099
|
+
d[81] = args.lensProfileExponent;
|
|
4100
|
+
d[82] = args.lensOvalization;
|
|
4101
|
+
d[83] = args.lensThicknessReference;
|
|
4102
|
+
d[84] = args.lensOvalizationSpanMin;
|
|
4103
|
+
d[85] = args.lensOvalizationSpanMax;
|
|
4104
|
+
d[86] = args.sizeScatterRampReachCssPx;
|
|
4105
|
+
d[87] = args.sizeScatterSpanMax;
|
|
4106
|
+
d[88] = args.outerShadowThick[0];
|
|
4107
|
+
d[89] = args.outerShadowThick[1];
|
|
4108
|
+
d[90] = args.outerShadowThick[2];
|
|
4109
|
+
d[91] = args.sizeScatterRampStartFar;
|
|
4110
|
+
d[92] = args.outerShadowLift[0];
|
|
4111
|
+
d[93] = args.outerShadowLift[1];
|
|
4112
|
+
d[94] = args.outerShadowLift[2];
|
|
4113
|
+
d[95] = args.outerShadowLift[3];
|
|
3526
4114
|
slot.write();
|
|
3527
4115
|
const chain = args.backdrop?.chain ?? placeholderView;
|
|
3528
4116
|
const body = args.backdrop?.body ?? placeholderView;
|
|
@@ -3545,7 +4133,8 @@ function createPassRunner(context) {
|
|
|
3545
4133
|
{ binding: 5, resource: body },
|
|
3546
4134
|
// Linear, no mips: the field targets have one level, and this is only
|
|
3547
4135
|
// read at all when the governor shrank them below the group's rect.
|
|
3548
|
-
{ binding: 6, resource: context.flatSampler }
|
|
4136
|
+
{ binding: 6, resource: context.flatSampler },
|
|
4137
|
+
{ binding: 7, resource: args.fields.aux2.createView() }
|
|
3549
4138
|
]
|
|
3550
4139
|
}));
|
|
3551
4140
|
pass.draw(3);
|
|
@@ -3628,6 +4217,7 @@ function createPassRunner(context) {
|
|
|
3628
4217
|
forget(groupId) {
|
|
3629
4218
|
pool.release(poolKey.groupField(groupId));
|
|
3630
4219
|
pool.release(poolKey.groupAux(groupId));
|
|
4220
|
+
pool.release(poolKey.groupAux2(groupId));
|
|
3631
4221
|
storages.get(groupId)?.destroy();
|
|
3632
4222
|
storages.delete(groupId);
|
|
3633
4223
|
for (const key of [`field:${groupId}`, `optics:${groupId}`, `highlight:${groupId}`]) {
|
|
@@ -3773,10 +4363,8 @@ function createRebuildLedger() {
|
|
|
3773
4363
|
// ../renderer-webgpu/dist/pyramid.js
|
|
3774
4364
|
var chainUsage = () => GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING;
|
|
3775
4365
|
var densityOf = (source, request) => texelsPerCssPx(source.width, source.height, request.placement, request.viewportCss[0], request.viewportCss[1]);
|
|
3776
|
-
var
|
|
3777
|
-
|
|
3778
|
-
return Math.abs(next - existing.texelsPerCss) <= 1e-6 * Math.max(1, existing.texelsPerCss);
|
|
3779
|
-
};
|
|
4366
|
+
var same = (next, existing) => Math.abs(next - existing) <= 1e-6 * Math.max(1, Math.abs(existing));
|
|
4367
|
+
var sameBody = (existing, request) => same(densityOf({ width: existing.sourceWidth, height: existing.sourceHeight }, request), existing.texelsPerCss) && same(request.bodySigmaCss, existing.bodySigmaCss);
|
|
3780
4368
|
function createPyramidStore(context) {
|
|
3781
4369
|
const { device, pool, cache } = context;
|
|
3782
4370
|
const resources = /* @__PURE__ */ new Map();
|
|
@@ -3852,7 +4440,7 @@ function createPyramidStore(context) {
|
|
|
3852
4440
|
return target;
|
|
3853
4441
|
};
|
|
3854
4442
|
const mipView = (texture, level) => texture.createView({ baseMipLevel: level, mipLevelCount: 1, dimension: "2d" });
|
|
3855
|
-
function allocate(sourceId, plan, bodyLevel, sizeEpoch, builtEpoch, bodySigmaTexels, density) {
|
|
4443
|
+
function allocate(sourceId, plan, bodyLevel, sizeEpoch, builtEpoch, bodySigmaTexels, density, bodySigmaCss) {
|
|
3856
4444
|
const existing = resources.get(sourceId);
|
|
3857
4445
|
const bodyWidth = (plan.levels[bodyLevel] ?? plan.levels[0]).width;
|
|
3858
4446
|
const bodyHeight = (plan.levels[bodyLevel] ?? plan.levels[0]).height;
|
|
@@ -3893,7 +4481,8 @@ function createPyramidStore(context) {
|
|
|
3893
4481
|
bodySigmaTexels,
|
|
3894
4482
|
texelsPerCss: density.texelsPerCss,
|
|
3895
4483
|
sourceWidth: density.sourceWidth,
|
|
3896
|
-
sourceHeight: density.sourceHeight
|
|
4484
|
+
sourceHeight: density.sourceHeight,
|
|
4485
|
+
bodySigmaCss
|
|
3897
4486
|
};
|
|
3898
4487
|
resources.set(sourceId, next);
|
|
3899
4488
|
return next;
|
|
@@ -4081,7 +4670,7 @@ function createPyramidStore(context) {
|
|
|
4081
4670
|
},
|
|
4082
4671
|
build(request, provider, encoder) {
|
|
4083
4672
|
const existing = liveResources(request.sourceId);
|
|
4084
|
-
if (existing !== void 0 && existing.builtEpoch >= request.epoch && !provider.isDirty() &&
|
|
4673
|
+
if (existing !== void 0 && existing.builtEpoch >= request.epoch && !provider.isDirty() && sameBody(existing, request)) {
|
|
4085
4674
|
ledger.recordClean();
|
|
4086
4675
|
return { status: "clean", resources: existing };
|
|
4087
4676
|
}
|
|
@@ -4103,7 +4692,7 @@ function createPyramidStore(context) {
|
|
|
4103
4692
|
const planScale = frame.width > 0 ? plan.width / frame.width : 1;
|
|
4104
4693
|
const bodySigmaTexels = request.bodySigmaCss * texelsPerCss * planScale;
|
|
4105
4694
|
const bodyPlan = bodyBlurPlan(bodySigmaTexels, plan);
|
|
4106
|
-
const target = allocate(request.sourceId, plan, bodyPlan.level, frame.sizeEpoch, request.epoch, bodySigmaTexels, { texelsPerCss, sourceWidth: frame.width, sourceHeight: frame.height });
|
|
4695
|
+
const target = allocate(request.sourceId, plan, bodyPlan.level, frame.sizeEpoch, request.epoch, bodySigmaTexels, { texelsPerCss, sourceWidth: frame.width, sourceHeight: frame.height }, request.bodySigmaCss);
|
|
4107
4696
|
runImport(encoder, request.sourceId, frame, target.chain);
|
|
4108
4697
|
runChain(encoder, request.sourceId, plan, target.chain);
|
|
4109
4698
|
runBodyBlur(encoder, request.sourceId, plan, target.chain, target.body, bodyPlan.level, bodyPlan.residualSigmaTexels);
|
|
@@ -4316,7 +4905,14 @@ function createWebGPURenderer(options = {}) {
|
|
|
4316
4905
|
const placement = placements.get(sourceId);
|
|
4317
4906
|
return isUsablePlacement(placement) ? placementFit(placement, viewport.widthCss, viewport.heightCss) : coverFit(pyramid.plan.width, pyramid.plan.height, viewport.widthCss, viewport.heightCss);
|
|
4318
4907
|
};
|
|
4319
|
-
const
|
|
4908
|
+
const liftChainLod = (sigmaCss, pyramid) => {
|
|
4909
|
+
if (pyramid === void 0 || !(sigmaCss > 0))
|
|
4910
|
+
return 0;
|
|
4911
|
+
const planScale = pyramid.sourceWidth > 0 ? pyramid.plan.width / pyramid.sourceWidth : 1;
|
|
4912
|
+
const sigmaTexels = sigmaCss * pyramid.texelsPerCss * planScale;
|
|
4913
|
+
return Math.min(chainLodForSigma(sigmaTexels), pyramid.plan.maxLod);
|
|
4914
|
+
};
|
|
4915
|
+
const staleBodyRebuilds = (explicit, pyramids) => {
|
|
4320
4916
|
const requests = [];
|
|
4321
4917
|
const named = new Set(explicit.map((request) => request.sourceId));
|
|
4322
4918
|
for (const sourceId of providers.keys()) {
|
|
@@ -4326,7 +4922,10 @@ function createWebGPURenderer(options = {}) {
|
|
|
4326
4922
|
if (existing === void 0)
|
|
4327
4923
|
continue;
|
|
4328
4924
|
const next = texelsPerCssPx(existing.sourceWidth, existing.sourceHeight, placements.get(sourceId), viewport.widthCss, viewport.heightCss);
|
|
4329
|
-
|
|
4925
|
+
const sameDensity = Math.abs(next - existing.texelsPerCss) <= 1e-6 * Math.max(1, existing.texelsPerCss);
|
|
4926
|
+
const sigmaCss = bodySigmaCssFor(sourceId);
|
|
4927
|
+
const sameSigma = Math.abs(sigmaCss - existing.bodySigmaCss) <= 1e-6 * Math.max(1, existing.bodySigmaCss);
|
|
4928
|
+
if (sameDensity && sameSigma)
|
|
4330
4929
|
continue;
|
|
4331
4930
|
requests.push({
|
|
4332
4931
|
sourceId,
|
|
@@ -4339,6 +4938,11 @@ function createWebGPURenderer(options = {}) {
|
|
|
4339
4938
|
};
|
|
4340
4939
|
const unionOf = (input) => input.union ?? DEFAULT_GROUP_UNION;
|
|
4341
4940
|
const variantOf = (input) => input.variant ?? "regular";
|
|
4941
|
+
const sourceVariant = (sourceId) => {
|
|
4942
|
+
const input = [...groups.values()].find((entry) => entry.input.backdropSourceId === sourceId)?.input;
|
|
4943
|
+
return input === void 0 ? "regular" : variantOf(input);
|
|
4944
|
+
};
|
|
4945
|
+
const bodySigmaCssFor = (sourceId) => opticsUnderPolicy(material.optics[sourceVariant(sourceId)], accessibility, material).blurSigma;
|
|
4342
4946
|
const groupTintSeed = (input) => input.surfaces.find((surface) => surface.fieldReferenceOnly !== true && (surface.tint?.strength ?? 0) > 0)?.tint?.color;
|
|
4343
4947
|
const stateOf = (input, resolution) => {
|
|
4344
4948
|
const resolved = resolution?.groups.find((group) => group.groupId === input.groupId);
|
|
@@ -4353,8 +4957,8 @@ function createWebGPURenderer(options = {}) {
|
|
|
4353
4957
|
function rebuildRequests(explicit) {
|
|
4354
4958
|
const base = explicit ?? standaloneRequests();
|
|
4355
4959
|
const { store: pyramids } = ensureContext();
|
|
4356
|
-
const
|
|
4357
|
-
return
|
|
4960
|
+
const stale = staleBodyRebuilds(base, pyramids);
|
|
4961
|
+
return stale.length === 0 ? base : [...base, ...stale];
|
|
4358
4962
|
}
|
|
4359
4963
|
function standaloneRequests() {
|
|
4360
4964
|
const sampled = /* @__PURE__ */ new Set();
|
|
@@ -4390,15 +4994,16 @@ function createWebGPURenderer(options = {}) {
|
|
|
4390
4994
|
unbuilt.push(request.sourceId);
|
|
4391
4995
|
continue;
|
|
4392
4996
|
}
|
|
4393
|
-
const variant = variantOf([...groups.values()].find((entry) => entry.input.backdropSourceId === request.sourceId)?.input ?? { });
|
|
4394
|
-
const optics = opticsUnderPolicy(material.optics[variant], accessibility, material);
|
|
4395
4997
|
lastResolution.set(request.sourceId, request.resolution);
|
|
4396
4998
|
const placement = placements.get(request.sourceId);
|
|
4397
4999
|
const outcome = pyramids.build({
|
|
4398
5000
|
sourceId: request.sourceId,
|
|
4399
5001
|
epoch: request.epoch,
|
|
4400
5002
|
resolution: request.resolution,
|
|
4401
|
-
|
|
5003
|
+
// The body's sharp width in CSS px at every device scale (W13 Decision
|
|
5004
|
+
// Log 8); the heavy component rides the same conversion — its level
|
|
5005
|
+
// is this one plus log2(sizeScatterGainMax) octaves.
|
|
5006
|
+
bodySigmaCss: bodySigmaCssFor(request.sourceId),
|
|
4402
5007
|
viewportCss: [viewport.widthCss, viewport.heightCss],
|
|
4403
5008
|
...isUsablePlacement(placement) ? { placement } : {}
|
|
4404
5009
|
}, provider, encoder);
|
|
@@ -4449,11 +5054,12 @@ function createWebGPURenderer(options = {}) {
|
|
|
4449
5054
|
}
|
|
4450
5055
|
const union = unionOf(input);
|
|
4451
5056
|
const shadow = outerShadowUnderPolicy(policy, material);
|
|
4452
|
-
|
|
5057
|
+
const shadowBackdropLuminance = input.backdropTone === void 0 ? void 0 : input.backdropToneLevel ?? relativeLuminance(input.backdropTone);
|
|
5058
|
+
let reachOcclusion = outerShadowThinOcclusion(shadowBackdropLuminance, shadow);
|
|
4453
5059
|
for (const surface of surfaces) {
|
|
4454
|
-
reachOcclusion = Math.max(reachOcclusion,
|
|
5060
|
+
reachOcclusion = Math.max(reachOcclusion, outerShadowOcclusionAt(shadow, shadowBackdropLuminance, surface.spanPx, surface.sizeThickness, material));
|
|
4455
5061
|
}
|
|
4456
|
-
const shadowReachPx = outerShadowReachPx(
|
|
5062
|
+
const shadowReachPx = outerShadowReachPx(shadow, reachOcclusion);
|
|
4457
5063
|
const snapped = snapRectToDevicePixels(groupFieldRect(surfaces, union, void 0, shadowReachPx), dpr);
|
|
4458
5064
|
const rectDevice = clipFieldRectToCanvas(snapped, dpr, viewportDevice);
|
|
4459
5065
|
if (rectDevice === void 0)
|
|
@@ -4493,7 +5099,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
4493
5099
|
backdropToneSizeBiasUnderPolicy(policy, material),
|
|
4494
5100
|
input.backdropTone === void 0 ? 0 : backdropToneUnderPolicy(policy, material) * material.backdropToneMax
|
|
4495
5101
|
];
|
|
4496
|
-
const backdropToneLevel =
|
|
5102
|
+
const backdropToneLevel = shadowBackdropLuminance ?? 0;
|
|
4497
5103
|
const refraction = effectiveRefraction(accessibilityRefractionCap(policy), state.refraction);
|
|
4498
5104
|
const refractionScale = material.refractionScale[refraction];
|
|
4499
5105
|
passes.opticsPass(encoder, {
|
|
@@ -4508,6 +5114,19 @@ function createWebGPURenderer(options = {}) {
|
|
|
4508
5114
|
fit: pyramid === void 0 || sourceId === void 0 ? [1, 1, 0, 0] : fitFor(sourceId, pyramid),
|
|
4509
5115
|
refractionScale,
|
|
4510
5116
|
lensRefractionGain: material.lensRefractionGain,
|
|
5117
|
+
// The lens law (W12 G2) and the inner shadow's own depth gain, both
|
|
5118
|
+
// evaluated per pixel in the shader from the thickness and the span.
|
|
5119
|
+
lensHeightPerSpan: material.lensHeightPerSpan,
|
|
5120
|
+
lensHeightMax: material.lensHeightMax,
|
|
5121
|
+
lensAmountPerSpan: material.lensAmountPerSpan,
|
|
5122
|
+
lensAmountMax: material.lensAmountMax,
|
|
5123
|
+
lensThicknessReference: material.lensThicknessReference,
|
|
5124
|
+
lensExtentGain: material.lensExtentGain,
|
|
5125
|
+
lensProfileExponent: material.lensProfileExponent,
|
|
5126
|
+
lensOvalization: material.lensOvalization,
|
|
5127
|
+
lensOvalizationSpanMin: material.lensOvalizationSpanMin,
|
|
5128
|
+
lensOvalizationSpanMax: material.lensOvalizationSpanMax,
|
|
5129
|
+
shadowDepthSizeGainMax: material.lensSizeGainMax,
|
|
4511
5130
|
chainMaxLod: pyramid?.plan.maxLod ?? 0,
|
|
4512
5131
|
tint: optics.tint,
|
|
4513
5132
|
tintAlpha: optics.tintAlpha,
|
|
@@ -4551,6 +5170,20 @@ function createWebGPURenderer(options = {}) {
|
|
|
4551
5170
|
sizeSpanMax: material.sizeSpanMax,
|
|
4552
5171
|
sizeScatterFloor: material.sizeScatterFloor,
|
|
4553
5172
|
sizeScatterSpanMax: material.sizeScatterSpanMax,
|
|
5173
|
+
// The body's depth ramp (W13 G1, claims §5.61 §2, §5.64 §5), resolved
|
|
5174
|
+
// from the viewport's own ratio: the profile anchors the start's thin
|
|
5175
|
+
// and thick ends and the reach at dpr 1 and dpr 2, and the CPU
|
|
5176
|
+
// interpolates all three in dpr. The start's SPAN grading stays in the
|
|
5177
|
+
// shader, because a group's members are not one size and the span
|
|
5178
|
+
// arrives per pixel on the field's own channel — so the two anchors go
|
|
5179
|
+
// over and `sizeThickness` is evaluated there. The reach is handed over
|
|
5180
|
+
// in CSS px because the field's depth is in CSS px.
|
|
5181
|
+
sizeScatterRampStartThin: scatterRampStart(dpr, material, 0),
|
|
5182
|
+
sizeScatterRampStartThick: scatterRampStart(dpr, material, material.sizeSpanMax),
|
|
5183
|
+
// The fourth form's far end, at the scatter span curve's top; the shader
|
|
5184
|
+
// declines from the thick end to it along that curve.
|
|
5185
|
+
sizeScatterRampStartFar: scatterRampStart(dpr, material, material.sizeScatterSpanMax),
|
|
5186
|
+
sizeScatterRampReachCssPx: scatterRampReachDevicePx(dpr, material) / dpr,
|
|
4554
5187
|
sizeFold: material.refractionScale[accessibilityRefractionCap(policy)],
|
|
4555
5188
|
backdropTone,
|
|
4556
5189
|
backdropToneColour: [
|
|
@@ -4579,7 +5212,11 @@ function createWebGPURenderer(options = {}) {
|
|
|
4579
5212
|
backdropToneResponseStrength: backdropToneUnderPolicy(policy, material) >= 0.999 ? material.backdropToneResponseStrength : 0,
|
|
4580
5213
|
backdropToneLinearMean: input.backdropToneLinearLuminance ?? backdropToneLevel,
|
|
4581
5214
|
outerShadow: [
|
|
4582
|
-
|
|
5215
|
+
// The thin regime's LINEAR occlusion at this group's backdrop (W14
|
|
5216
|
+
// G1). The conversion to the compositing space moved into the shader
|
|
5217
|
+
// with the regimes: it is not linear, so converting one regime here
|
|
5218
|
+
// and blending in the shader would not be the same law.
|
|
5219
|
+
outerShadowThinOcclusion(shadowBackdropLuminance, shadow),
|
|
4583
5220
|
shadow.sigmaPx,
|
|
4584
5221
|
shadow.spreadPx,
|
|
4585
5222
|
// The offset in field-texture UV. The field spans exactly this rect, so
|
|
@@ -4587,6 +5224,19 @@ function createWebGPURenderer(options = {}) {
|
|
|
4587
5224
|
// scaled the rasterisation.
|
|
4588
5225
|
shadow.offsetPx / Math.max(rectDevice.height * cssPerDevice, 1e-6)
|
|
4589
5226
|
],
|
|
5227
|
+
outerShadowThick: [
|
|
5228
|
+
shadow.thickOcclusionAt96,
|
|
5229
|
+
shadow.thickOcclusionAt128,
|
|
5230
|
+
shadow.thickOcclusionAt160
|
|
5231
|
+
],
|
|
5232
|
+
outerShadowLift: [
|
|
5233
|
+
// The lift needs a chain to copy; without one there is nothing to add,
|
|
5234
|
+
// and `hasBackdrop` in the shader says the same thing a second time.
|
|
5235
|
+
pyramid === void 0 || policy.glass === "none" ? 0 : shadow.liftAmplitude,
|
|
5236
|
+
shadow.liftSpanMin,
|
|
5237
|
+
shadow.liftSpanFull,
|
|
5238
|
+
liftChainLod(shadow.liftBlurSigmaCss, pyramid)
|
|
5239
|
+
],
|
|
4590
5240
|
outerShadowSizeGain: shadow.sizeGain,
|
|
4591
5241
|
outerShadowRectCssHeight: rectDevice.height * cssPerDevice,
|
|
4592
5242
|
backdrop: pyramid === void 0 || policy.glass === "none" ? void 0 : {
|
|
@@ -4868,6 +5518,6 @@ function createWebGPURenderer(options = {}) {
|
|
|
4868
5518
|
};
|
|
4869
5519
|
}
|
|
4870
5520
|
|
|
4871
|
-
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_REFRACTION_GAIN, LENS_SIZE_GAIN_MAX, LUMINANCE_WEIGHTS, MATERIAL_OPTICS, MATERIAL_VARIANTS, MAX_CHAIN_LEVELS, MIN_LEVEL_EXTENT, NOMINAL_GOVERNOR, NOMINAL_MATERIAL_POLICY, OPTICS_PASS_ID, OUTER_SHADOW, OUTPUT_TEXTURE_FORMAT, PASS_LABEL, REFRACTION_LADDER, REFRACTION_SCALE, RENDERER_ERROR_CODES, RENDERER_PASS_IDS, RendererError, SIZE_OCCLUSION_GAIN, SIZE_SCATTER_FLOOR, SIZE_SCATTER_GAIN_MAX, SIZE_SCATTER_SPAN_MAX, 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, backdropToneSizeBiasUnderPolicy, backdropToneUnderPolicy, bodyBlurPlan, chainModule, clipFieldRectToCanvas, 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, lensDepthPx, lensDisplacementPx, lensSizeGain, lensSizeGainFromThickness, linearGradientStops, linearToSrgb, linearToSrgbChannel, occlusionAlphaUnderPolicy, opticsModule, opticsUnderPolicy, outerShadowAlpha, outerShadowFalloff, outerShadowReachPx, outerShadowUnderPolicy, packInstances, pipelineKey, placementFit, planPyramid, poolKey, readbackDue, refractionRank, relativeLuminance, rendererError, resolveSurfaces, samePlacement, scatterThickness, sizeOcclusionAlpha, sizeOcclusionAlphaAt, sizeOuterShadowOcclusion, sizeOuterShadowOcclusionAt, sizeScatterSigma, sizeScatterSigmaAt, sizeShadowDepth, sizeShadowDepthAt, sizeThickness, sizeThicknessUnderPolicy, snapRectToDevicePixels, srgbToLinear, srgbToLinearChannel, statsFromBuffer, supportsTimestamps, texelsPerCssPx, tintShade, tintShadeLayer, tintToneAdaptation, tintedMaterialColour, validateAppTexture, withMaterialOverrides };
|
|
4872
|
-
//# sourceMappingURL=dist-
|
|
4873
|
-
//# sourceMappingURL=dist-
|
|
5521
|
+
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_GAIN_MAX, 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_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, backdropToneSizeBiasUnderPolicy, backdropToneUnderPolicy, bodyBlurPlan, chainModule, clipFieldRectToCanvas, 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, scatterRampAreaMean, scatterRampReachDevicePx, scatterRampStart, scatterSharpShare, scatterThickness, shadowDepthPx, sizeOcclusionAlpha, sizeOcclusionAlphaAt, sizeOuterShadowOcclusion, sizeOuterShadowOcclusionAt, sizeScatterSigma, sizeScatterSigmaAt, sizeShadowDepth, sizeShadowDepthAt, sizeThickness, sizeThicknessUnderPolicy, snapRectToDevicePixels, srgbToLinear, srgbToLinearChannel, statsFromBuffer, supportsTimestamps, texelsPerCssPx, tintShade, tintShadeLayer, tintToneAdaptation, tintedMaterialColour, validateAppTexture, withMaterialOverrides };
|
|
5522
|
+
//# sourceMappingURL=dist-RGWZAZ6J.js.map
|
|
5523
|
+
//# sourceMappingURL=dist-RGWZAZ6J.js.map
|