@vitreajs/vitrea 0.17.0 → 0.19.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-T7PRMUM4.js → dist-VQPRX7BX.js} +511 -32
- package/dist/dist-VQPRX7BX.js.map +1 -0
- package/dist/index.d.ts +80 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/dist-T7PRMUM4.js.map +0 -1
|
@@ -1174,6 +1174,10 @@ function rejectMixedBackdropToneArity(anchorX, thin, thick) {
|
|
|
1174
1174
|
}
|
|
1175
1175
|
function withMaterialOverrides(base, patch) {
|
|
1176
1176
|
rejectRetiredOuterShadowLeaves(patch.outerShadow);
|
|
1177
|
+
const backdropToneAbscissa = patch.backdropToneAbscissa === void 0 ? base.backdropToneAbscissa : patch.backdropToneAbscissa;
|
|
1178
|
+
if (backdropToneAbscissa !== void 0 && backdropToneAbscissa !== "source" && (backdropToneAbscissa === null || typeof backdropToneAbscissa !== "object" || backdropToneAbscissa.kind !== "silhouette" || Object.keys(backdropToneAbscissa).some((key) => key !== "kind"))) {
|
|
1179
|
+
throw new TypeError("backdropToneAbscissa must be source or { kind: silhouette }");
|
|
1180
|
+
}
|
|
1177
1181
|
const optics = {};
|
|
1178
1182
|
for (const variant of MATERIAL_VARIANTS) {
|
|
1179
1183
|
optics[variant] = { ...base.optics[variant], ...patch.optics?.[variant] };
|
|
@@ -1255,6 +1259,7 @@ function withMaterialOverrides(base, patch) {
|
|
|
1255
1259
|
rimCollapsed: patch.rimCollapsed ?? base.rimCollapsed,
|
|
1256
1260
|
rimCollapsedTinted: patch.rimCollapsedTinted ?? base.rimCollapsedTinted,
|
|
1257
1261
|
rimTintChroma: patch.rimTintChroma ?? base.rimTintChroma,
|
|
1262
|
+
...backdropToneAbscissa === void 0 ? {} : { backdropToneAbscissa },
|
|
1258
1263
|
backdropToneAnchorX,
|
|
1259
1264
|
backdropToneResponseThin,
|
|
1260
1265
|
backdropToneResponseThick,
|
|
@@ -3440,7 +3445,7 @@ var WGSL_HIGHLIGHT_PASS = `struct HighlightUniforms {
|
|
|
3440
3445
|
glow : vec4f,
|
|
3441
3446
|
/// highlight colour, linear light (xyz), unused (w)
|
|
3442
3447
|
colour : vec4f,
|
|
3443
|
-
/// fieldSize.xy, fieldUpsampled (z),
|
|
3448
|
+
/// fieldSize.xy, fieldUpsampled (z), local tone field present (w, W28)
|
|
3444
3449
|
flags : vec4f,
|
|
3445
3450
|
/// backdrop tone adaptation (W7), exactly as the optics pass takes it:
|
|
3446
3451
|
/// backdropToneLow, backdropToneHigh, the size bias already divided by the
|
|
@@ -3470,6 +3475,7 @@ var WGSL_HIGHLIGHT_PASS = `struct HighlightUniforms {
|
|
|
3470
3475
|
/// bound here for the same reason the optics pass binds it: a highlight is the
|
|
3471
3476
|
/// material catching light, and a material that is not there catches none.
|
|
3472
3477
|
@group(0) @binding(4) var presenceTexture : texture_2d<f32>;
|
|
3478
|
+
@group(0) @binding(5) var localToneTexture : texture_2d<f32>;
|
|
3473
3479
|
|
|
3474
3480
|
const TAU = 6.283185307179586;
|
|
3475
3481
|
|
|
@@ -3499,6 +3505,16 @@ fn fs_highlight(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
3499
3505
|
aux = textureLoad(auxTexture, texel, 0);
|
|
3500
3506
|
presence = textureLoad(presenceTexture, texel, 0);
|
|
3501
3507
|
}
|
|
3508
|
+
var toneStrength = hu.toneAdapt.w;
|
|
3509
|
+
var toneLevel = hu.toneLevel.x;
|
|
3510
|
+
if (hu.flags.w > 0.5) {
|
|
3511
|
+
if (hu.flags.z > 0.5) {
|
|
3512
|
+
toneLevel = textureSampleLevel(localToneTexture, fieldSampler, fieldUv, 0.0).w;
|
|
3513
|
+
} else {
|
|
3514
|
+
toneLevel = textureLoad(localToneTexture, vec2i(fieldUv * hu.flags.xy), 0).w;
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
if (toneLevel < 0.0) { toneStrength = 0.0; }
|
|
3502
3518
|
let mat = clamp(presence.x, 0.0, 1.0);
|
|
3503
3519
|
let d = field.x;
|
|
3504
3520
|
let normal = field.yz;
|
|
@@ -3547,14 +3563,14 @@ fn fs_highlight(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
3547
3563
|
);
|
|
3548
3564
|
let sizeK = clamp(spanT * spanT * (3.0 - 2.0 * spanT) * hu.toneLevel.w, 0.0, 1.0);
|
|
3549
3565
|
var toneAdapt = 0.0;
|
|
3550
|
-
if (
|
|
3551
|
-
let toneX =
|
|
3566
|
+
if (toneStrength > 0.0) {
|
|
3567
|
+
let toneX = toneLevel + hu.toneAdapt.z * sizeK;
|
|
3552
3568
|
let toneT = clamp(
|
|
3553
3569
|
(toneX - hu.toneAdapt.x) / max(hu.toneAdapt.y - hu.toneAdapt.x, 1e-6),
|
|
3554
3570
|
0.0,
|
|
3555
3571
|
1.0,
|
|
3556
3572
|
);
|
|
3557
|
-
toneAdapt = clamp(
|
|
3573
|
+
toneAdapt = clamp(toneStrength, 0.0, 1.0) * (1.0 - toneT * toneT * (3.0 - 2.0 * toneT));
|
|
3558
3574
|
}
|
|
3559
3575
|
|
|
3560
3576
|
/*
|
|
@@ -3718,6 +3734,8 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
|
|
|
3718
3734
|
/// thick z, and a length gate w. Appended so every three-knot field keeps its
|
|
3719
3735
|
/// byte offset and its original shader branch.
|
|
3720
3736
|
toneExtra : vec4f,
|
|
3737
|
+
/// W28: whether the per-surface reference field is present (x).
|
|
3738
|
+
localTone : vec4f,
|
|
3721
3739
|
};
|
|
3722
3740
|
|
|
3723
3741
|
@group(0) @binding(0) var<uniform> ou : OpticsUniforms;
|
|
@@ -3740,6 +3758,7 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
|
|
|
3740
3758
|
/// channel, unioned in the field pass like every other per-surface scalar. One
|
|
3741
3759
|
/// channel, in the field pass's fourth target \u2014 see 'wgsl/field.ts'.
|
|
3742
3760
|
@group(0) @binding(9) var presenceTexture : texture_2d<f32>;
|
|
3761
|
+
@group(0) @binding(10) var localToneTexture : texture_2d<f32>;
|
|
3743
3762
|
|
|
3744
3763
|
/// One encoded sRGB channel from a linear one \u2014 the space the backdrop tone
|
|
3745
3764
|
/// response's anchors live in (W9). Mirrors material.ts's 'linearToSrgbChannel'.
|
|
@@ -4064,6 +4083,27 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4064
4083
|
presence = textureLoad(presenceTexture, texel, 0);
|
|
4065
4084
|
}
|
|
4066
4085
|
|
|
4086
|
+
// The complete reference changes together: response, collapse colour and
|
|
4087
|
+
// compensation, nominal composition, opacity solve, and the tint/rim readouts.
|
|
4088
|
+
// The source branch retains the old uniforms and arithmetic exactly.
|
|
4089
|
+
var toneStrength = ou.toneAdapt.w;
|
|
4090
|
+
var toneColour = ou.toneColour;
|
|
4091
|
+
var toneLinearMean = ou.toneAnchor.w;
|
|
4092
|
+
if (ou.localTone.x > 0.5) {
|
|
4093
|
+
if (ou.flags.w > 0.5) {
|
|
4094
|
+
toneColour = textureSampleLevel(localToneTexture, fieldSampler, in.uv, 0.0);
|
|
4095
|
+
} else {
|
|
4096
|
+
toneColour = textureLoad(localToneTexture, vec2i(in.uv * ou.flags.yz), 0);
|
|
4097
|
+
}
|
|
4098
|
+
toneLinearMean = dot(toneColour.rgb, vec3f(0.2126, 0.7152, 0.0722));
|
|
4099
|
+
// A fully transparent mask measured no colour and has no local authority.
|
|
4100
|
+
if (toneColour.w < 0.0) {
|
|
4101
|
+
toneStrength = 0.0;
|
|
4102
|
+
toneColour = ou.toneColour;
|
|
4103
|
+
toneLinearMean = ou.toneAnchor.w;
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
|
|
4067
4107
|
let d = field.x;
|
|
4068
4108
|
let normal = field.yz;
|
|
4069
4109
|
let coverage = field.w;
|
|
@@ -4425,13 +4465,13 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4425
4465
|
*/
|
|
4426
4466
|
var toneAdapt = 0.0;
|
|
4427
4467
|
if (ou.toneAdapt.w > 0.0) {
|
|
4428
|
-
let toneX =
|
|
4468
|
+
let toneX = toneColour.w + ou.toneAdapt.z * sizeK;
|
|
4429
4469
|
let toneT = clamp(
|
|
4430
4470
|
(toneX - ou.toneAdapt.x) / max(ou.toneAdapt.y - ou.toneAdapt.x, 1e-6),
|
|
4431
4471
|
0.0,
|
|
4432
4472
|
1.0,
|
|
4433
4473
|
);
|
|
4434
|
-
toneAdapt = clamp(
|
|
4474
|
+
toneAdapt = clamp(toneStrength, 0.0, 1.0) * (1.0 - toneT * toneT * (3.0 - 2.0 * toneT));
|
|
4435
4475
|
}
|
|
4436
4476
|
/*
|
|
4437
4477
|
* Both the colour and the alpha move, together and not separately. What the
|
|
@@ -4471,9 +4511,9 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4471
4511
|
*/
|
|
4472
4512
|
var solvedNeutral = neutral;
|
|
4473
4513
|
var solvedAlpha = sizedAlpha;
|
|
4474
|
-
if (
|
|
4514
|
+
if (toneStrength > 0.0 && ou.toneRowThin.w > 0.0 &&
|
|
4475
4515
|
sizedAlpha > 1e-3 && toneAdapt < 0.995) {
|
|
4476
|
-
let encodedInput = srgb_encode(
|
|
4516
|
+
let encodedInput = srgb_encode(toneColour.w);
|
|
4477
4517
|
let anchor = max(ou.toneAnchor.x, 1e-4);
|
|
4478
4518
|
let authority =
|
|
4479
4519
|
smoothstep(anchor * 0.5, anchor, encodedInput) * clamp(ou.toneRowThin.w, 0.0, 1.0);
|
|
@@ -4481,10 +4521,10 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4481
4521
|
let response = tone_response(encodedInput, sizeK, toneLevelFar);
|
|
4482
4522
|
// The collapse's mean pull is toward L(toneColour.rgb) \u2014 the LINEAR
|
|
4483
4523
|
// mean, which toneAnchor.w carries \u2014 not toward the encoded level.
|
|
4484
|
-
let preCollapse = (response - toneAdapt *
|
|
4524
|
+
let preCollapse = (response - toneAdapt * toneLinearMean) / (1.0 - toneAdapt);
|
|
4485
4525
|
let neutralLuma = dot(neutral, vec3f(0.2126, 0.7152, 0.0722));
|
|
4486
|
-
let nominal = (1.0 - sizedAlpha) *
|
|
4487
|
-
let shift = (preCollapse - nominal) / sizedAlpha * authority *
|
|
4526
|
+
let nominal = (1.0 - sizedAlpha) * toneLinearMean + sizedAlpha * neutralLuma;
|
|
4527
|
+
let shift = (preCollapse - nominal) / sizedAlpha * authority * toneStrength;
|
|
4488
4528
|
solvedNeutral = clamp(neutral + vec3f(shift), vec3f(0.0), vec3f(1.0));
|
|
4489
4529
|
/*
|
|
4490
4530
|
* The light attractor needs OPACITY. The light scheme's neutral is
|
|
@@ -4497,14 +4537,14 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4497
4537
|
* collapse's own axis with its own fitted constants.
|
|
4498
4538
|
*/
|
|
4499
4539
|
let solvedLuma = dot(solvedNeutral, vec3f(0.2126, 0.7152, 0.0722));
|
|
4500
|
-
let achieved = (1.0 - sizedAlpha) *
|
|
4501
|
-
if (preCollapse > achieved + 1e-4 && solvedLuma >
|
|
4540
|
+
let achieved = (1.0 - sizedAlpha) * toneLinearMean + sizedAlpha * solvedLuma;
|
|
4541
|
+
if (preCollapse > achieved + 1e-4 && solvedLuma > toneLinearMean + 1e-3) {
|
|
4502
4542
|
let alphaTarget = clamp(
|
|
4503
|
-
(preCollapse -
|
|
4543
|
+
(preCollapse - toneLinearMean) / (solvedLuma - toneLinearMean),
|
|
4504
4544
|
sizedAlpha,
|
|
4505
4545
|
1.0,
|
|
4506
4546
|
);
|
|
4507
|
-
solvedAlpha = mix(sizedAlpha, alphaTarget, authority *
|
|
4547
|
+
solvedAlpha = mix(sizedAlpha, alphaTarget, authority * toneStrength);
|
|
4508
4548
|
}
|
|
4509
4549
|
}
|
|
4510
4550
|
}
|
|
@@ -4537,7 +4577,7 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4537
4577
|
* lerped toward it would be a black surface rather than a transmitting one.
|
|
4538
4578
|
* There the CSS tier's own 'backdrop-filter' is what carries the transmission.
|
|
4539
4579
|
*/
|
|
4540
|
-
var toneTarget =
|
|
4580
|
+
var toneTarget = toneColour.rgb;
|
|
4541
4581
|
if (ou.flags.x > 0.5 || domMaterial) {
|
|
4542
4582
|
toneTarget = mix(toneTarget, backdrop, clamp(ou.toneRowThick.w, 0.0, 1.0));
|
|
4543
4583
|
}
|
|
@@ -4695,7 +4735,7 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4695
4735
|
// the composite; as a layer it is the layer over the tone the host measured
|
|
4696
4736
|
// for the group \u2014 zero where nothing was measured, the same reference-level
|
|
4697
4737
|
// convention the CSS tier's 'materialLuminance' takes (within its 0.02).
|
|
4698
|
-
let u = bodyAlpha * dot(colour, vec3f(0.2126, 0.7152, 0.0722)) + (1.0 - bodyAlpha) *
|
|
4738
|
+
let u = bodyAlpha * dot(colour, vec3f(0.2126, 0.7152, 0.0722)) + (1.0 - bodyAlpha) * toneColour.w;
|
|
4699
4739
|
let grip = clamp(ou.seed.w, 0.0, 1.0) * clamp(ou.tone.z, 0.0, 1.0) *
|
|
4700
4740
|
(1.0 - toneAdapt * (1.0 - clamp(ou.rim.w, 0.0, 1.0)));
|
|
4701
4741
|
let shade = mix(1.0, clamp(mix(ou.tone.x, ou.tone.y, clamp(u, 0.0, 1.0)), 0.0, 1.0), grip);
|
|
@@ -4812,7 +4852,7 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
|
|
|
4812
4852
|
* author tint layer composites with sixty lines above.
|
|
4813
4853
|
*/
|
|
4814
4854
|
let rimLuma = materialAlpha * dot(materialColour, vec3f(0.2126, 0.7152, 0.0722))
|
|
4815
|
-
+ (1.0 - materialAlpha) *
|
|
4855
|
+
+ (1.0 - materialAlpha) * toneColour.w;
|
|
4816
4856
|
let rimAmplitude = ou.rim.y + ou.rimLaw.x * rimLuma;
|
|
4817
4857
|
let rimCollapsed = mix(ou.rimLaw.y, ou.rimLaw.z, tintK);
|
|
4818
4858
|
/*
|
|
@@ -4986,6 +5026,112 @@ fn vs_fullscreen(@builtin(vertex_index) index : u32) -> FullscreenOut {
|
|
|
4986
5026
|
}
|
|
4987
5027
|
`;
|
|
4988
5028
|
|
|
5029
|
+
// ../renderer-webgpu/dist/wgsl/silhouette-tone.js
|
|
5030
|
+
var silhouetteReductionModule = () => `${WGSL_PRELUDE}
|
|
5031
|
+
struct ToneShape { rect : vec4f, radius : vec4f };
|
|
5032
|
+
struct ToneStat { colour : vec4f, stats : vec4f };
|
|
5033
|
+
struct ToneUniforms { viewport : vec4f, fit : vec4f };
|
|
5034
|
+
@group(0) @binding(0) var<uniform> u : ToneUniforms;
|
|
5035
|
+
@group(0) @binding(1) var source : texture_2d<f32>;
|
|
5036
|
+
@group(0) @binding(3) var<storage, read> shapes : array<ToneShape>;
|
|
5037
|
+
@group(0) @binding(4) var<storage, read_write> tones : array<ToneStat>;
|
|
5038
|
+
var<workgroup> sums : array<vec4f, 256>;
|
|
5039
|
+
var<workgroup> counts : array<f32, 256>;
|
|
5040
|
+
var<workgroup> weights : array<f32, 256>;
|
|
5041
|
+
struct RawTone { value : vec4f, alpha : f32 };
|
|
5042
|
+
|
|
5043
|
+
fn raw_tone(texel : vec2i) -> RawTone {
|
|
5044
|
+
let dims = vec2i(textureDimensions(source));
|
|
5045
|
+
let rgba = textureLoad(source, clamp(texel, vec2i(0), dims - 1), 0);
|
|
5046
|
+
let rgb = rgba.rgb / max(rgba.a, 1e-6);
|
|
5047
|
+
return RawTone(vec4f(rgb, dot(linear_to_srgb(rgb), vec3f(0.2126, 0.7152, 0.0722))) * rgba.a, rgba.a);
|
|
5048
|
+
}
|
|
5049
|
+
|
|
5050
|
+
@compute @workgroup_size(256)
|
|
5051
|
+
fn reduce_tone(@builtin(local_invocation_index) lane : u32,
|
|
5052
|
+
@builtin(workgroup_id) group : vec3u) {
|
|
5053
|
+
let shape = shapes[group.x];
|
|
5054
|
+
// G0 clips to the capture raster. Clip BEFORE deriving the iteration area so
|
|
5055
|
+
// offscreen geometry cannot create unbounded work or overflow its u32 product.
|
|
5056
|
+
// In-bounds rectangles retain exactly the same lane assignment and arithmetic.
|
|
5057
|
+
let lo = vec2i(clamp(floor(shape.rect.xy), vec2f(0.0), u.viewport.xy));
|
|
5058
|
+
let hi = vec2i(clamp(ceil(shape.rect.xy + shape.rect.zw), vec2f(0.0), u.viewport.xy));
|
|
5059
|
+
let extent = vec2u(max(hi - lo, vec2i(0)));
|
|
5060
|
+
let half = shape.rect.zw * 0.5;
|
|
5061
|
+
let centre = shape.rect.xy + half;
|
|
5062
|
+
let radius = min(shape.radius.x, min(half.x, half.y));
|
|
5063
|
+
var sum = vec4f(0.0);
|
|
5064
|
+
var count = 0.0;
|
|
5065
|
+
var weight = 0.0;
|
|
5066
|
+
for (var i = lane; i < extent.x * extent.y; i += 256u) {
|
|
5067
|
+
let pixel = lo + vec2i(vec2u(i % extent.x, i / extent.x));
|
|
5068
|
+
let p = vec2f(pixel) + 0.5;
|
|
5069
|
+
let q = abs(p - centre) - half + radius;
|
|
5070
|
+
let distance = length(max(q, vec2f(0.0))) + min(max(q.x, q.y), 0.0) - radius;
|
|
5071
|
+
if (distance > 0.0) { continue; }
|
|
5072
|
+
let uv = (p / u.viewport.xy) * u.fit.xy + u.fit.zw;
|
|
5073
|
+
// Interpolate encoded and linear statistics separately. Encoding after
|
|
5074
|
+
// bilinear filtering would reintroduce a Jensen gap on a scaled source.
|
|
5075
|
+
let at = uv * vec2f(textureDimensions(source)) - 0.5;
|
|
5076
|
+
let base = vec2i(floor(at));
|
|
5077
|
+
let f = fract(at);
|
|
5078
|
+
let a = raw_tone(base);
|
|
5079
|
+
let b = raw_tone(base + vec2i(1, 0));
|
|
5080
|
+
let c = raw_tone(base + vec2i(0, 1));
|
|
5081
|
+
let d = raw_tone(base + vec2i(1, 1));
|
|
5082
|
+
sum += mix(mix(a.value, b.value, f.x), mix(c.value, d.value, f.x), f.y);
|
|
5083
|
+
weight += mix(mix(a.alpha, b.alpha, f.x), mix(c.alpha, d.alpha, f.x), f.y);
|
|
5084
|
+
count += 1.0;
|
|
5085
|
+
}
|
|
5086
|
+
sums[lane] = sum;
|
|
5087
|
+
counts[lane] = count;
|
|
5088
|
+
weights[lane] = weight;
|
|
5089
|
+
workgroupBarrier();
|
|
5090
|
+
for (var stride = 128u; stride > 0u; stride /= 2u) {
|
|
5091
|
+
if (lane < stride) {
|
|
5092
|
+
sums[lane] += sums[lane + stride];
|
|
5093
|
+
counts[lane] += counts[lane + stride];
|
|
5094
|
+
weights[lane] += weights[lane + stride];
|
|
5095
|
+
}
|
|
5096
|
+
workgroupBarrier();
|
|
5097
|
+
}
|
|
5098
|
+
if (lane == 0u) {
|
|
5099
|
+
let mean = sums[0] / max(weights[0], 1e-6);
|
|
5100
|
+
let level = srgb_to_linear(vec3f(mean.w)).x;
|
|
5101
|
+
tones[group.x].colour = vec4f(mean.rgb, level);
|
|
5102
|
+
tones[group.x].stats = vec4f(mean.w, luminance(mean.rgb), counts[0], weights[0]);
|
|
5103
|
+
}
|
|
5104
|
+
}
|
|
5105
|
+
`;
|
|
5106
|
+
var silhouetteFieldModule = (family) => `${WGSL_PRELUDE}
|
|
5107
|
+
${WGSL_FIELD_KERNELS}
|
|
5108
|
+
struct FieldUniforms { screen : vec4f, unionP : vec4f, counts : vec4u, fallback : vec4f };
|
|
5109
|
+
struct ToneStat { colour : vec4f, stats : vec4f };
|
|
5110
|
+
@group(0) @binding(0) var<uniform> u : FieldUniforms;
|
|
5111
|
+
@group(0) @binding(1) var<storage, read> instances : array<Instance>;
|
|
5112
|
+
@group(0) @binding(2) var<storage, read> tones : array<ToneStat>;
|
|
5113
|
+
fn member_distance(i : u32, p : vec2f) -> f32 {
|
|
5114
|
+
let s = instances[i];
|
|
5115
|
+
return ${family === "rsupn" ? "sd_rsupn_grad" : "sd_rsup_grad"}(
|
|
5116
|
+
p - s.centre, s.half, s.re, vec4f(s.k0, s.k1, s.k2, s.k3), s.k4).d + s.inset;
|
|
5117
|
+
}
|
|
5118
|
+
fn member_tone(i : u32) -> vec4f {
|
|
5119
|
+
return select(u.fallback, tones[i].colour, tones[i].stats.w > 0.0);
|
|
5120
|
+
}
|
|
5121
|
+
@fragment
|
|
5122
|
+
fn fs_tone(in : FullscreenOut) -> @location(0) vec4f {
|
|
5123
|
+
let p = in.uv * u.screen.xy * u.screen.z;
|
|
5124
|
+
var distance = member_distance(0u, p);
|
|
5125
|
+
var colour = member_tone(0u);
|
|
5126
|
+
for (var i = 1u; i < u.counts.x; i += 1u) {
|
|
5127
|
+
let blend = union_blend(distance, member_distance(i, p), u.unionP.xyz);
|
|
5128
|
+
distance = blend.x;
|
|
5129
|
+
colour = mix(member_tone(i), colour, blend.y);
|
|
5130
|
+
}
|
|
5131
|
+
return colour;
|
|
5132
|
+
}
|
|
5133
|
+
`;
|
|
5134
|
+
|
|
4989
5135
|
// ../renderer-webgpu/dist/wgsl/index.js
|
|
4990
5136
|
var withPrelude = (pass) => `${WGSL_PRELUDE}
|
|
4991
5137
|
${pass}
|
|
@@ -5006,6 +5152,9 @@ function allShaderSource() {
|
|
|
5006
5152
|
importPassSource("external"),
|
|
5007
5153
|
WGSL_DOWNSAMPLE_PASS,
|
|
5008
5154
|
WGSL_ANALYSIS_PASS,
|
|
5155
|
+
silhouetteReductionModule(),
|
|
5156
|
+
silhouetteFieldModule("rsupn"),
|
|
5157
|
+
silhouetteFieldModule("rsup"),
|
|
5009
5158
|
WGSL_OPTICS_PASS,
|
|
5010
5159
|
WGSL_HIGHLIGHT_PASS
|
|
5011
5160
|
].join("\n\n");
|
|
@@ -5210,7 +5359,7 @@ function createPassRunner(context) {
|
|
|
5210
5359
|
};
|
|
5211
5360
|
},
|
|
5212
5361
|
opticsPass(encoder, args) {
|
|
5213
|
-
const slot = uniformSlot(`optics:${args.resourceId}`,
|
|
5362
|
+
const slot = uniformSlot(`optics:${args.resourceId}`, 120);
|
|
5214
5363
|
const d = slot.data;
|
|
5215
5364
|
d[0] = args.viewportDevice[0];
|
|
5216
5365
|
d[1] = args.viewportDevice[1];
|
|
@@ -5328,6 +5477,7 @@ function createPassRunner(context) {
|
|
|
5328
5477
|
d[113] = args.backdropToneResponseThin[3] ?? args.backdropToneResponseThin[2];
|
|
5329
5478
|
d[114] = args.backdropToneResponseThick[3] ?? args.backdropToneResponseThick[2];
|
|
5330
5479
|
d[115] = args.backdropToneAnchorX.length === 4 ? 1 : 0;
|
|
5480
|
+
d[116] = args.localTone === void 0 ? 0 : 1;
|
|
5331
5481
|
slot.write();
|
|
5332
5482
|
const chain = args.backdrop?.chain ?? placeholderView;
|
|
5333
5483
|
const body = args.backdrop?.body ?? placeholderView;
|
|
@@ -5354,7 +5504,8 @@ function createPassRunner(context) {
|
|
|
5354
5504
|
{ binding: 6, resource: context.flatSampler },
|
|
5355
5505
|
{ binding: 7, resource: args.fields.aux2.createView() },
|
|
5356
5506
|
{ binding: 8, resource: heavy },
|
|
5357
|
-
{ binding: 9, resource: args.fields.presence.createView() }
|
|
5507
|
+
{ binding: 9, resource: args.fields.presence.createView() },
|
|
5508
|
+
{ binding: 10, resource: args.localTone ?? placeholderView }
|
|
5358
5509
|
]
|
|
5359
5510
|
}));
|
|
5360
5511
|
pass.draw(3);
|
|
@@ -5382,7 +5533,7 @@ function createPassRunner(context) {
|
|
|
5382
5533
|
d[16] = args.fields.width;
|
|
5383
5534
|
d[17] = args.fields.height;
|
|
5384
5535
|
d[18] = args.fields.upsampled ? 1 : 0;
|
|
5385
|
-
d[19] = 0;
|
|
5536
|
+
d[19] = args.localTone === void 0 ? 0 : 1;
|
|
5386
5537
|
d[20] = args.backdropTone[0];
|
|
5387
5538
|
d[21] = Math.max(args.backdropTone[1], args.backdropTone[0] + 1e-4);
|
|
5388
5539
|
d[22] = args.backdropTone[2];
|
|
@@ -5412,7 +5563,8 @@ function createPassRunner(context) {
|
|
|
5412
5563
|
{ binding: 1, resource: args.fields.field.createView() },
|
|
5413
5564
|
{ binding: 2, resource: args.fields.aux.createView() },
|
|
5414
5565
|
{ binding: 3, resource: context.flatSampler },
|
|
5415
|
-
{ binding: 4, resource: args.fields.presence.createView() }
|
|
5566
|
+
{ binding: 4, resource: args.fields.presence.createView() },
|
|
5567
|
+
{ binding: 5, resource: args.localTone ?? placeholderView }
|
|
5416
5568
|
]
|
|
5417
5569
|
}));
|
|
5418
5570
|
pass.draw(3);
|
|
@@ -6068,6 +6220,263 @@ function createPyramidStore(context) {
|
|
|
6068
6220
|
}
|
|
6069
6221
|
var ANALYSIS_DISPATCH = { workgroupSize: ANALYSIS_WORKGROUP, workgroups: 1 };
|
|
6070
6222
|
|
|
6223
|
+
// ../renderer-webgpu/dist/silhouette-tone.js
|
|
6224
|
+
function packToneShapes(surfaces, dpr) {
|
|
6225
|
+
const data = new Float32Array(surfaces.length * 8);
|
|
6226
|
+
surfaces.forEach((surface, i) => {
|
|
6227
|
+
const [w, h] = surface.shape.channels.size;
|
|
6228
|
+
data.set([
|
|
6229
|
+
(surface.centre[0] - w / 2) * dpr,
|
|
6230
|
+
(surface.centre[1] - h / 2) * dpr,
|
|
6231
|
+
w * dpr,
|
|
6232
|
+
h * dpr,
|
|
6233
|
+
surface.shape.corner.radius * dpr,
|
|
6234
|
+
0,
|
|
6235
|
+
0,
|
|
6236
|
+
0
|
|
6237
|
+
], i * 8);
|
|
6238
|
+
});
|
|
6239
|
+
return data;
|
|
6240
|
+
}
|
|
6241
|
+
function toneReadingsFromBuffer(values, metadata, fallback) {
|
|
6242
|
+
return metadata.flatMap((meta, i) => {
|
|
6243
|
+
if (values[i * 8 + 7] > 0)
|
|
6244
|
+
return [{
|
|
6245
|
+
...meta,
|
|
6246
|
+
kind: "silhouette",
|
|
6247
|
+
level: 0,
|
|
6248
|
+
color: [values[i * 8], values[i * 8 + 1], values[i * 8 + 2]],
|
|
6249
|
+
luminance: values[i * 8 + 3],
|
|
6250
|
+
encodedLuminance: values[i * 8 + 4],
|
|
6251
|
+
linearLuminance: values[i * 8 + 5],
|
|
6252
|
+
sampleCount: values[i * 8 + 6]
|
|
6253
|
+
}];
|
|
6254
|
+
if (fallback === void 0 || fallback[3] < 0)
|
|
6255
|
+
return [];
|
|
6256
|
+
const [r, g, b, luminance] = fallback;
|
|
6257
|
+
return [{
|
|
6258
|
+
surfaceId: meta.surfaceId,
|
|
6259
|
+
kind: "source",
|
|
6260
|
+
color: [r, g, b],
|
|
6261
|
+
luminance,
|
|
6262
|
+
encodedLuminance: linearToSrgbChannel(luminance),
|
|
6263
|
+
// The local optics field derives this channel from RGB, including fallback.
|
|
6264
|
+
linearLuminance: relativeLuminance([r, g, b]),
|
|
6265
|
+
sampleCount: 0,
|
|
6266
|
+
level: 0,
|
|
6267
|
+
sourceWidth: 0,
|
|
6268
|
+
sourceHeight: 0,
|
|
6269
|
+
sampledWidth: 0,
|
|
6270
|
+
sampledHeight: 0
|
|
6271
|
+
}];
|
|
6272
|
+
});
|
|
6273
|
+
}
|
|
6274
|
+
function createSilhouetteTonePass(context) {
|
|
6275
|
+
const { device, cache, pool } = context;
|
|
6276
|
+
const createEntry = (count, groupId) => ({
|
|
6277
|
+
groupId,
|
|
6278
|
+
count,
|
|
6279
|
+
shapes: createStorageSlot(device, count * 32, "vitrea:tone-shapes"),
|
|
6280
|
+
instances: createStorageSlot(device, count * 72, "vitrea:tone-instances"),
|
|
6281
|
+
uniform: createUniformSlot(device, 8, "vitrea:tone-uniform"),
|
|
6282
|
+
fieldUniform: createUniformSlot(device, 16, "vitrea:tone-field-uniform"),
|
|
6283
|
+
tones: device.createBuffer({
|
|
6284
|
+
size: count * 32,
|
|
6285
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
|
|
6286
|
+
}),
|
|
6287
|
+
readback: device.createBuffer({
|
|
6288
|
+
size: count * 32,
|
|
6289
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
|
6290
|
+
}),
|
|
6291
|
+
reduced: void 0,
|
|
6292
|
+
encodedReduction: false,
|
|
6293
|
+
observation: void 0,
|
|
6294
|
+
fallback: void 0,
|
|
6295
|
+
encodedFallback: void 0,
|
|
6296
|
+
queued: void 0,
|
|
6297
|
+
pending: void 0
|
|
6298
|
+
});
|
|
6299
|
+
const entries = /* @__PURE__ */ new Map();
|
|
6300
|
+
const destroyEntry = (entry) => {
|
|
6301
|
+
entry.shapes.destroy();
|
|
6302
|
+
entry.instances.destroy();
|
|
6303
|
+
entry.uniform.buffer.destroy();
|
|
6304
|
+
entry.fieldUniform.buffer.destroy();
|
|
6305
|
+
entry.tones.destroy();
|
|
6306
|
+
entry.readback.destroy();
|
|
6307
|
+
};
|
|
6308
|
+
const forget = (resourceId) => {
|
|
6309
|
+
const entry = entries.get(resourceId);
|
|
6310
|
+
if (entry !== void 0)
|
|
6311
|
+
destroyEntry(entry);
|
|
6312
|
+
entries.delete(resourceId);
|
|
6313
|
+
pool.release(`tone-field:${resourceId}`);
|
|
6314
|
+
};
|
|
6315
|
+
return {
|
|
6316
|
+
draw(encoder, args) {
|
|
6317
|
+
const { field, pyramid, fields } = args;
|
|
6318
|
+
let entry = entries.get(field.resourceId);
|
|
6319
|
+
if (entry !== void 0 && entry.count !== field.instanceCount) {
|
|
6320
|
+
forget(field.resourceId);
|
|
6321
|
+
entry = void 0;
|
|
6322
|
+
}
|
|
6323
|
+
if (entry === void 0) {
|
|
6324
|
+
entry = createEntry(field.instanceCount, args.groupId);
|
|
6325
|
+
entries.set(field.resourceId, entry);
|
|
6326
|
+
}
|
|
6327
|
+
const shapeData = packToneShapes(args.surfaces, 1 / field.cssPerDevice);
|
|
6328
|
+
const geometryKey = JSON.stringify([
|
|
6329
|
+
pyramid.sourceId,
|
|
6330
|
+
pyramid.sizeEpoch,
|
|
6331
|
+
pyramid.sourceWidth,
|
|
6332
|
+
pyramid.sourceHeight,
|
|
6333
|
+
pyramid.plan.width,
|
|
6334
|
+
pyramid.plan.height,
|
|
6335
|
+
...shapeData,
|
|
6336
|
+
...args.viewportDevice,
|
|
6337
|
+
...args.fit,
|
|
6338
|
+
...args.surfaces.map((surface) => surface.nodeId)
|
|
6339
|
+
]);
|
|
6340
|
+
const previous = entry.reduced;
|
|
6341
|
+
if (previous === void 0 || previous.chain !== pyramid.chain || previous.geometryKey !== geometryKey || previous.builtEpoch !== pyramid.builtEpoch && (!args.liveSource || readbackDue(previous.timeMs, args.timeMs, args.cadenceHz))) {
|
|
6342
|
+
entry.reduced = {
|
|
6343
|
+
chain: pyramid.chain,
|
|
6344
|
+
geometryKey,
|
|
6345
|
+
builtEpoch: pyramid.builtEpoch,
|
|
6346
|
+
timeMs: args.timeMs,
|
|
6347
|
+
metadata: args.surfaces.map((surface) => ({
|
|
6348
|
+
surfaceId: surface.nodeId,
|
|
6349
|
+
sourceWidth: pyramid.sourceWidth,
|
|
6350
|
+
sourceHeight: pyramid.sourceHeight,
|
|
6351
|
+
sampledWidth: pyramid.plan.width,
|
|
6352
|
+
sampledHeight: pyramid.plan.height
|
|
6353
|
+
}))
|
|
6354
|
+
};
|
|
6355
|
+
entry.encodedReduction = true;
|
|
6356
|
+
entry.shapes.write(shapeData, shapeData.length);
|
|
6357
|
+
entry.uniform.data.set([...args.viewportDevice, 0, 0, ...args.fit]);
|
|
6358
|
+
entry.uniform.write();
|
|
6359
|
+
const pipeline = cache.computePipeline("silhouette-reduction", () => ({
|
|
6360
|
+
layout: "auto",
|
|
6361
|
+
compute: {
|
|
6362
|
+
module: cache.module("silhouette-reduction", silhouetteReductionModule),
|
|
6363
|
+
entryPoint: "reduce_tone"
|
|
6364
|
+
}
|
|
6365
|
+
}));
|
|
6366
|
+
const pass = encoder.beginComputePass({ label: "vitrea:silhouette-reduction" });
|
|
6367
|
+
pass.setPipeline(pipeline);
|
|
6368
|
+
pass.setBindGroup(0, device.createBindGroup({
|
|
6369
|
+
layout: pipeline.getBindGroupLayout(0),
|
|
6370
|
+
entries: [
|
|
6371
|
+
{ binding: 0, resource: { buffer: entry.uniform.buffer } },
|
|
6372
|
+
{ binding: 1, resource: pyramid.chain.createView({ baseMipLevel: 0, mipLevelCount: 1 }) },
|
|
6373
|
+
{ binding: 3, resource: { buffer: entry.shapes.buffer } },
|
|
6374
|
+
{ binding: 4, resource: { buffer: entry.tones } }
|
|
6375
|
+
]
|
|
6376
|
+
}));
|
|
6377
|
+
pass.dispatchWorkgroups(field.instanceCount);
|
|
6378
|
+
pass.end();
|
|
6379
|
+
}
|
|
6380
|
+
entry.instances.write(field.instances, field.instanceCount * 18);
|
|
6381
|
+
entry.encodedFallback = args.fallbackTone;
|
|
6382
|
+
if (entry.queued === void 0 && entry.pending === void 0 && entry.observation?.reduction !== entry.reduced) {
|
|
6383
|
+
encoder.copyBufferToBuffer(entry.tones, 0, entry.readback, 0, entry.count * 32);
|
|
6384
|
+
entry.queued = entry.reduced;
|
|
6385
|
+
}
|
|
6386
|
+
const texture = pool.acquire(`tone-field:${field.resourceId}`, {
|
|
6387
|
+
width: fields.width,
|
|
6388
|
+
height: fields.height,
|
|
6389
|
+
format: "rgba16float",
|
|
6390
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
|
|
6391
|
+
});
|
|
6392
|
+
const u = entry.fieldUniform;
|
|
6393
|
+
u.data.set([
|
|
6394
|
+
field.rectDevice.width,
|
|
6395
|
+
field.rectDevice.height,
|
|
6396
|
+
field.cssPerDevice,
|
|
6397
|
+
0,
|
|
6398
|
+
field.union.neckWidth,
|
|
6399
|
+
field.union.maxBulge,
|
|
6400
|
+
field.union.separationThreshold,
|
|
6401
|
+
0
|
|
6402
|
+
]);
|
|
6403
|
+
new Uint32Array(u.data.buffer)[8] = field.instanceCount;
|
|
6404
|
+
u.data.set(args.fallbackTone, 12);
|
|
6405
|
+
u.write();
|
|
6406
|
+
const fieldPipeline = cache.renderPipeline(`silhouette-field:${field.family}`, () => ({
|
|
6407
|
+
layout: "auto",
|
|
6408
|
+
vertex: { module: cache.module(`silhouette-field:${field.family}`, () => silhouetteFieldModule(field.family)), entryPoint: "vs_fullscreen" },
|
|
6409
|
+
fragment: {
|
|
6410
|
+
module: cache.module(`silhouette-field:${field.family}`, () => silhouetteFieldModule(field.family)),
|
|
6411
|
+
entryPoint: "fs_tone",
|
|
6412
|
+
targets: [{ format: "rgba16float" }]
|
|
6413
|
+
},
|
|
6414
|
+
primitive: { topology: "triangle-list" }
|
|
6415
|
+
}));
|
|
6416
|
+
const view = texture.createView();
|
|
6417
|
+
const fieldPass = encoder.beginRenderPass({
|
|
6418
|
+
label: "vitrea:silhouette-field",
|
|
6419
|
+
colorAttachments: [{ view, loadOp: "clear", storeOp: "store" }]
|
|
6420
|
+
});
|
|
6421
|
+
fieldPass.setPipeline(fieldPipeline);
|
|
6422
|
+
fieldPass.setBindGroup(0, device.createBindGroup({
|
|
6423
|
+
layout: fieldPipeline.getBindGroupLayout(0),
|
|
6424
|
+
entries: [
|
|
6425
|
+
{ binding: 0, resource: { buffer: u.buffer } },
|
|
6426
|
+
{ binding: 1, resource: { buffer: entry.instances.buffer } },
|
|
6427
|
+
{ binding: 2, resource: { buffer: entry.tones } }
|
|
6428
|
+
]
|
|
6429
|
+
}));
|
|
6430
|
+
fieldPass.draw(3);
|
|
6431
|
+
fieldPass.end();
|
|
6432
|
+
return view;
|
|
6433
|
+
},
|
|
6434
|
+
afterSubmit() {
|
|
6435
|
+
for (const entry of entries.values()) {
|
|
6436
|
+
entry.encodedReduction = false;
|
|
6437
|
+
if (entry.encodedFallback !== void 0)
|
|
6438
|
+
entry.fallback = entry.encodedFallback;
|
|
6439
|
+
entry.encodedFallback = void 0;
|
|
6440
|
+
const reduction = entry.queued;
|
|
6441
|
+
if (reduction === void 0)
|
|
6442
|
+
continue;
|
|
6443
|
+
entry.queued = void 0;
|
|
6444
|
+
entry.pending = entry.readback.mapAsync(GPUMapMode.READ).then(() => {
|
|
6445
|
+
entry.observation = {
|
|
6446
|
+
reduction,
|
|
6447
|
+
values: new Float32Array(entry.readback.getMappedRange()).slice()
|
|
6448
|
+
};
|
|
6449
|
+
entry.readback.unmap();
|
|
6450
|
+
}).catch(() => {
|
|
6451
|
+
entry.observation = void 0;
|
|
6452
|
+
}).finally(() => {
|
|
6453
|
+
entry.pending = void 0;
|
|
6454
|
+
});
|
|
6455
|
+
}
|
|
6456
|
+
},
|
|
6457
|
+
cancelQueued() {
|
|
6458
|
+
for (const entry of entries.values()) {
|
|
6459
|
+
if (entry.encodedReduction)
|
|
6460
|
+
entry.reduced = void 0;
|
|
6461
|
+
entry.encodedReduction = false;
|
|
6462
|
+
entry.encodedFallback = void 0;
|
|
6463
|
+
entry.queued = void 0;
|
|
6464
|
+
}
|
|
6465
|
+
},
|
|
6466
|
+
async collect() {
|
|
6467
|
+
await Promise.all([...entries.values()].map((entry) => entry.pending));
|
|
6468
|
+
},
|
|
6469
|
+
readings(groupId) {
|
|
6470
|
+
return [...entries.values()].filter((entry) => entry.groupId === groupId).flatMap((entry) => entry.observation === void 0 || entry.observation.reduction !== entry.reduced ? [] : toneReadingsFromBuffer(entry.observation.values, entry.observation.reduction.metadata, entry.fallback));
|
|
6471
|
+
},
|
|
6472
|
+
forget,
|
|
6473
|
+
destroy() {
|
|
6474
|
+
for (const resourceId of entries.keys())
|
|
6475
|
+
forget(resourceId);
|
|
6476
|
+
}
|
|
6477
|
+
};
|
|
6478
|
+
}
|
|
6479
|
+
|
|
6071
6480
|
// ../renderer-webgpu/dist/renderer.js
|
|
6072
6481
|
var OPTICS_PASS_ID = "vitrea.optics";
|
|
6073
6482
|
var HIGHLIGHT_PASS_ID = "vitrea.highlight";
|
|
@@ -6089,6 +6498,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
6089
6498
|
const groups = /* @__PURE__ */ new Map();
|
|
6090
6499
|
const adaptation = /* @__PURE__ */ new Map();
|
|
6091
6500
|
const lastReadbackAt = /* @__PURE__ */ new Map();
|
|
6501
|
+
const hintedTones = /* @__PURE__ */ new Map();
|
|
6092
6502
|
let accessibility = NOMINAL_MATERIAL_POLICY;
|
|
6093
6503
|
let material = withMaterialOverrides(DEFAULT_MATERIAL_PROFILE, options.materialProfile ?? {});
|
|
6094
6504
|
let viewport = options.viewport ?? {
|
|
@@ -6100,6 +6510,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
6100
6510
|
let builtGeneration;
|
|
6101
6511
|
let store;
|
|
6102
6512
|
let runner;
|
|
6513
|
+
let silhouetteTone;
|
|
6103
6514
|
let framesDrawn = 0;
|
|
6104
6515
|
let generations = 0;
|
|
6105
6516
|
let lastFrameTimeMs;
|
|
@@ -6123,6 +6534,9 @@ function createWebGPURenderer(options = {}) {
|
|
|
6123
6534
|
});
|
|
6124
6535
|
const dropContext = () => {
|
|
6125
6536
|
store?.destroy();
|
|
6537
|
+
silhouetteTone?.destroy();
|
|
6538
|
+
silhouetteTone = void 0;
|
|
6539
|
+
hintedTones.clear();
|
|
6126
6540
|
runner?.destroy();
|
|
6127
6541
|
context?.destroy();
|
|
6128
6542
|
store = void 0;
|
|
@@ -6154,6 +6568,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
6154
6568
|
builtGeneration = generation;
|
|
6155
6569
|
store = createPyramidStore(context);
|
|
6156
6570
|
runner = createPassRunner(context);
|
|
6571
|
+
silhouetteTone = createSilhouetteTonePass(context);
|
|
6157
6572
|
if (superseded !== void 0 && superseded !== generation) {
|
|
6158
6573
|
for (const provider of providers.values()) {
|
|
6159
6574
|
if (provider.generation !== generation)
|
|
@@ -6314,7 +6729,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
6314
6729
|
}
|
|
6315
6730
|
return { built, unbuilt };
|
|
6316
6731
|
}
|
|
6317
|
-
function drawGroups(encoder, resolution) {
|
|
6732
|
+
function drawGroups(encoder, resolution, timeMs) {
|
|
6318
6733
|
const { store: pyramids, runner: passes } = ensureContext();
|
|
6319
6734
|
const active = targets;
|
|
6320
6735
|
if (active === void 0) {
|
|
@@ -6330,7 +6745,11 @@ function createWebGPURenderer(options = {}) {
|
|
|
6330
6745
|
let drawn = 0;
|
|
6331
6746
|
planesDrawn.add(active.plane);
|
|
6332
6747
|
const resourceOf = (groupId) => groupResourceId(active.plane, groupId);
|
|
6333
|
-
const releaseIdle = (groupId) =>
|
|
6748
|
+
const releaseIdle = (groupId) => {
|
|
6749
|
+
passes.forget(resourceOf(groupId));
|
|
6750
|
+
silhouetteTone?.forget(resourceOf(groupId));
|
|
6751
|
+
hintedTones.delete(resourceOf(groupId));
|
|
6752
|
+
};
|
|
6334
6753
|
for (const entry of groups.values()) {
|
|
6335
6754
|
const input = entry.input;
|
|
6336
6755
|
if (input.surfaces.length === 0) {
|
|
@@ -6368,7 +6787,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
6368
6787
|
rectDevice.x * cssPerDevice,
|
|
6369
6788
|
rectDevice.y * cssPerDevice
|
|
6370
6789
|
]);
|
|
6371
|
-
const
|
|
6790
|
+
const fieldArgs = {
|
|
6372
6791
|
resourceId: resourceOf(input.groupId),
|
|
6373
6792
|
family: governor.knobs.fieldFamily,
|
|
6374
6793
|
rectDevice,
|
|
@@ -6380,19 +6799,62 @@ function createWebGPURenderer(options = {}) {
|
|
|
6380
6799
|
instances: packed.data,
|
|
6381
6800
|
instanceCount: packed.count,
|
|
6382
6801
|
union
|
|
6383
|
-
}
|
|
6802
|
+
};
|
|
6803
|
+
const fields = passes.fieldPass(encoder, fieldArgs);
|
|
6384
6804
|
const state = stateOf(input, resolution);
|
|
6385
6805
|
const variant = variantOf(input);
|
|
6386
6806
|
const sourceId = input.backdropSourceId;
|
|
6387
6807
|
const pyramid = sourceId === void 0 ? void 0 : pyramids.resources(sourceId);
|
|
6388
6808
|
const adapt = sourceId === void 0 ? void 0 : adaptationFor(sourceId).values;
|
|
6809
|
+
const localTone = typeof material.backdropToneAbscissa === "object" && input.backdropToneHint !== true && pyramid !== void 0 && sourceId !== void 0 && surfaces.length > 0 ? silhouetteTone?.draw(encoder, {
|
|
6810
|
+
groupId: input.groupId,
|
|
6811
|
+
field: fieldArgs,
|
|
6812
|
+
fields,
|
|
6813
|
+
surfaces,
|
|
6814
|
+
pyramid,
|
|
6815
|
+
viewportDevice,
|
|
6816
|
+
fit: fitFor(sourceId, pyramid),
|
|
6817
|
+
timeMs,
|
|
6818
|
+
cadenceHz: governor.knobs.adaptationCadenceHz,
|
|
6819
|
+
liveSource: providers.get(sourceId)?.kind !== "image" && providers.get(sourceId)?.kind !== "gradient",
|
|
6820
|
+
fallbackTone: [
|
|
6821
|
+
input.backdropTone?.[0] ?? 0,
|
|
6822
|
+
input.backdropTone?.[1] ?? 0,
|
|
6823
|
+
input.backdropTone?.[2] ?? 0,
|
|
6824
|
+
input.backdropTone === void 0 ? -1 : input.backdropToneLevel ?? relativeLuminance(input.backdropTone)
|
|
6825
|
+
]
|
|
6826
|
+
}) : void 0;
|
|
6827
|
+
if (localTone === void 0)
|
|
6828
|
+
silhouetteTone?.forget(resourceOf(input.groupId));
|
|
6829
|
+
const hintLevel = input.backdropToneLevel ?? (input.backdropTone === void 0 ? void 0 : relativeLuminance(input.backdropTone));
|
|
6830
|
+
if (typeof material.backdropToneAbscissa === "object" && input.backdropToneHint === true && hintLevel !== void 0 && input.backdropTone !== void 0) {
|
|
6831
|
+
const color = input.backdropTone;
|
|
6832
|
+
hintedTones.set(resourceOf(input.groupId), {
|
|
6833
|
+
groupId: input.groupId,
|
|
6834
|
+
readings: surfaces.map((surface) => ({
|
|
6835
|
+
surfaceId: surface.nodeId,
|
|
6836
|
+
kind: "hint",
|
|
6837
|
+
color,
|
|
6838
|
+
encodedLuminance: linearToSrgbChannel(hintLevel),
|
|
6839
|
+
luminance: hintLevel,
|
|
6840
|
+
linearLuminance: input.backdropToneLinearLuminance ?? hintLevel,
|
|
6841
|
+
sampleCount: 0,
|
|
6842
|
+
level: 0,
|
|
6843
|
+
sourceWidth: 0,
|
|
6844
|
+
sourceHeight: 0,
|
|
6845
|
+
sampledWidth: 0,
|
|
6846
|
+
sampledHeight: 0
|
|
6847
|
+
}))
|
|
6848
|
+
});
|
|
6849
|
+
} else
|
|
6850
|
+
hintedTones.delete(resourceOf(input.groupId));
|
|
6389
6851
|
const nominalOptics = material.optics[variant];
|
|
6390
6852
|
const optics = opticsUnderPolicy(nominalOptics, policy, material);
|
|
6391
6853
|
const backdropTone = [
|
|
6392
6854
|
material.backdropToneLow,
|
|
6393
6855
|
material.backdropToneHigh,
|
|
6394
6856
|
backdropToneSizeBiasUnderPolicy(policy, material),
|
|
6395
|
-
input.backdropTone === void 0 ? 0 : backdropToneUnderPolicy(policy, material) * material.backdropToneMax
|
|
6857
|
+
input.backdropTone === void 0 && localTone === void 0 ? 0 : backdropToneUnderPolicy(policy, material) * material.backdropToneMax
|
|
6396
6858
|
];
|
|
6397
6859
|
const backdropToneLevel = shadowBackdropLuminance ?? 0;
|
|
6398
6860
|
const refraction = effectiveRefraction(accessibilityRefractionCap(policy), state.refraction);
|
|
@@ -6403,6 +6865,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
6403
6865
|
targetFormat: active.format,
|
|
6404
6866
|
rectDevice,
|
|
6405
6867
|
fields,
|
|
6868
|
+
...localTone === void 0 ? {} : { localTone },
|
|
6406
6869
|
viewportDevice,
|
|
6407
6870
|
cssPerDevice,
|
|
6408
6871
|
coverageRampCss: cssPerDevice,
|
|
@@ -6626,6 +7089,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
6626
7089
|
rectDevice: surfaceRectDevice,
|
|
6627
7090
|
fieldRectDevice: rectDevice,
|
|
6628
7091
|
fields,
|
|
7092
|
+
...localTone === void 0 ? {} : { localTone },
|
|
6629
7093
|
viewportDevice,
|
|
6630
7094
|
cssPerDevice,
|
|
6631
7095
|
sweep: lead.channels.sweep,
|
|
@@ -6766,8 +7230,11 @@ function createWebGPURenderer(options = {}) {
|
|
|
6766
7230
|
},
|
|
6767
7231
|
removeGroup(groupId) {
|
|
6768
7232
|
groups.delete(groupId);
|
|
6769
|
-
for (const plane of planesDrawn)
|
|
7233
|
+
for (const plane of planesDrawn) {
|
|
6770
7234
|
runner?.forget(groupResourceId(plane, groupId));
|
|
7235
|
+
silhouetteTone?.forget(groupResourceId(plane, groupId));
|
|
7236
|
+
hintedTones.delete(groupResourceId(plane, groupId));
|
|
7237
|
+
}
|
|
6771
7238
|
},
|
|
6772
7239
|
setAccessibility(policy) {
|
|
6773
7240
|
accessibility = policy;
|
|
@@ -6811,12 +7278,14 @@ function createWebGPURenderer(options = {}) {
|
|
|
6811
7278
|
if (args.highlight !== void 0)
|
|
6812
7279
|
passes.clearPass(encoder, args.highlight);
|
|
6813
7280
|
}
|
|
6814
|
-
result = drawGroups(encoder, args.resolution);
|
|
7281
|
+
result = drawGroups(encoder, args.resolution, args.frame.timeMs);
|
|
6815
7282
|
args.timing?.resolve(encoder);
|
|
6816
7283
|
gpu.device.queue.submit([encoder.finish()]);
|
|
6817
7284
|
pyramids.afterSubmit();
|
|
7285
|
+
silhouetteTone?.afterSubmit();
|
|
6818
7286
|
} finally {
|
|
6819
7287
|
pyramids.releaseAcquired();
|
|
7288
|
+
silhouetteTone?.cancelQueued();
|
|
6820
7289
|
}
|
|
6821
7290
|
const delta = lastFrameTimeMs === void 0 ? 0 : args.frame.timeMs - lastFrameTimeMs;
|
|
6822
7291
|
lastFrameTimeMs = args.frame.timeMs;
|
|
@@ -6849,6 +7318,7 @@ function createWebGPURenderer(options = {}) {
|
|
|
6849
7318
|
} catch (error) {
|
|
6850
7319
|
pendingEncoder = void 0;
|
|
6851
7320
|
pyramids.releaseAcquired();
|
|
7321
|
+
silhouetteTone?.cancelQueued();
|
|
6852
7322
|
throw error;
|
|
6853
7323
|
}
|
|
6854
7324
|
},
|
|
@@ -6864,12 +7334,14 @@ function createWebGPURenderer(options = {}) {
|
|
|
6864
7334
|
passes.clearPass(encoder, targets.optics);
|
|
6865
7335
|
if (targets.highlight !== void 0)
|
|
6866
7336
|
passes.clearPass(encoder, targets.highlight);
|
|
6867
|
-
drawGroups(encoder, frameContext.resolution);
|
|
7337
|
+
drawGroups(encoder, frameContext.resolution, frameContext.frame.timeMs);
|
|
6868
7338
|
}
|
|
6869
7339
|
context.device.queue.submit([encoder.finish()]);
|
|
6870
7340
|
pyramids.afterSubmit();
|
|
7341
|
+
silhouetteTone?.afterSubmit();
|
|
6871
7342
|
} finally {
|
|
6872
7343
|
pyramids.releaseAcquired();
|
|
7344
|
+
silhouetteTone?.cancelQueued();
|
|
6873
7345
|
}
|
|
6874
7346
|
const delta = lastFrameTimeMs === void 0 ? 0 : frameContext.frame.timeMs - lastFrameTimeMs;
|
|
6875
7347
|
lastFrameTimeMs = frameContext.frame.timeMs;
|
|
@@ -6881,7 +7353,14 @@ function createWebGPURenderer(options = {}) {
|
|
|
6881
7353
|
}
|
|
6882
7354
|
};
|
|
6883
7355
|
},
|
|
7356
|
+
backdropToneAbscissae(groupId) {
|
|
7357
|
+
return [
|
|
7358
|
+
...silhouetteTone?.readings(groupId) ?? [],
|
|
7359
|
+
...[...hintedTones.values()].filter((entry) => entry.groupId === groupId).flatMap((entry) => entry.readings)
|
|
7360
|
+
];
|
|
7361
|
+
},
|
|
6884
7362
|
async collectAdaptation() {
|
|
7363
|
+
await silhouetteTone?.collect();
|
|
6885
7364
|
if (store === void 0)
|
|
6886
7365
|
return 0;
|
|
6887
7366
|
const stats = await store.collectStats();
|
|
@@ -6911,5 +7390,5 @@ function createWebGPURenderer(options = {}) {
|
|
|
6911
7390
|
}
|
|
6912
7391
|
|
|
6913
7392
|
export { ADAPTIVE_LUMINANCE_HIGH, ADAPTIVE_LUMINANCE_LOW, ADAPTIVE_TINT_DARK, ADAPTIVE_TINT_LIGHT, ANALYSIS_DISPATCH, ANALYSIS_GRID, ANALYSIS_PASS_ID, ANALYSIS_STATS_FLOATS, ANALYSIS_TARGET_EXTENT, ANALYSIS_WORKGROUP, BACKDROP_ALPHA_MODES, BACKDROP_COLOR_SPACES, BACKDROP_KINDS, BACKDROP_PASS_ID, BACKDROP_TONE_HIGH, BACKDROP_TONE_LOW, BACKDROP_TONE_MAX, BACKDROP_TONE_SIZE_BIAS, CANVAS_FORMAT, CHAIN_SIGMA_AT_LEVEL_1, CROSS_CHECK_SHAPE_FLOATS, CROSS_CHECK_WORKGROUP, DEFAULT_MATERIAL_PROFILE, FAMILY_C_CROSS_CHECK, FIELD_PASS_ID, GOVERNOR_LADDER, HIGHLIGHT_PASS_ID, IDENTITY_FIT, IDLE_CHANNELS, INCREASED_OCCLUSION_LIFT, INSTANCE_BYTES, INSTANCE_FLOATS, LENS_AMOUNT_MAX, LENS_AMOUNT_PER_SPAN, LENS_EXTENT_GAIN, LENS_HEIGHT_MAX, LENS_HEIGHT_PER_SPAN, LENS_OVALIZATION, LENS_PROFILE_EXPONENT, LENS_REFRACTION_GAIN, LENS_SIZE_GAIN_MAX, LENS_THICKNESS_REFERENCE, LUMINANCE_WEIGHTS, MATERIAL_OPTICS, MATERIAL_VARIANTS, MAX_CHAIN_LEVELS, MIN_LEVEL_EXTENT, NOMINAL_GOVERNOR, NOMINAL_MATERIAL_POLICY, OPTICS_PASS_ID, OUTER_SHADOW, OUTER_SHADOW_THICK_SPANS, OUTER_SHADOW_THIN_L, OUTER_SHADOW_UNMEASURED_BACKDROP_LUMINANCE, OUTPUT_TEXTURE_FORMAT, PASS_LABEL, REFRACTION_LADDER, REFRACTION_SCALE, RENDERER_ERROR_CODES, RENDERER_PASS_IDS, RendererError, SIZE_OCCLUSION_GAIN, SIZE_SCATTER_FLOOR, SIZE_SCATTER_FLOOR_2X, SIZE_SCATTER_GAIN_FAR_2X, SIZE_SCATTER_GAIN_MAX, SIZE_SCATTER_GAIN_MAX_2X, SIZE_SCATTER_RAMP_REACH_1X_PX, SIZE_SCATTER_RAMP_REACH_2X_PX, SIZE_SCATTER_RAMP_START_FAR_1X, SIZE_SCATTER_RAMP_START_FAR_2X, SIZE_SCATTER_RAMP_START_THICK_1X, SIZE_SCATTER_RAMP_START_THICK_2X, SIZE_SCATTER_RAMP_START_THIN_1X, SIZE_SCATTER_RAMP_START_THIN_2X, SIZE_SCATTER_SPAN_MAX, SIZE_SCATTER_SPAN_MAX_2X, SIZE_SHADOW_GAIN_MAX, SIZE_SPAN_MAX, SIZE_SPAN_MIN, SRGB_ENCODING_EXPONENT, SUPPORTED_APP_TEXTURE_FORMATS, WGSL_ANALYSIS_PASS, WGSL_CROSS_CHECK_PASS, WGSL_DOWNSAMPLE_PASS, WGSL_FIELD_KERNELS, WGSL_FIELD_PASS, WGSL_FIELD_SAMPLE, WGSL_HIGHLIGHT_PASS, WGSL_IMPORT_PASS, WGSL_INSTANCE_STRUCT, WGSL_OPTICS_PASS, WGSL_PRELUDE, WGSL_RSUPN_GRAD, WGSL_RSUP_GRAD, WGSL_SMOOTH_UNION, WORKING_TEXTURE_FORMAT, ZERO_STATS, accessibilityRefractionCap, adaptationStrength, adaptedTintAlpha, adaptedTintColour, adaptiveTint, allShaderSource, alphaNormalisationMode, analysisModule, backdropFit, backdropToneAdaptation, backdropToneResponse, backdropToneSizeBiasUnderPolicy, backdropToneSolveWeight, backdropToneUnderPolicy, bodyBlurPlan, chainModule, clipFieldRectToCanvas, collapsedRimUnderPolicy, coverFit, createAdaptationState, createAppTextureProvider, createCopyProvider, createDeviceHost, createGovernor, createGpuContext, createGradientProvider, createPassRunner, createPipelineCache, createPyramidStore, createRebuildLedger, createStorageSlot, createTexturePool, createTimingCollector, createUniformSlot, createVideoProvider, createWebGPURenderer, crossCheckKernelModule, displayP3ToSrgbLinear, effectiveRefraction, encodeOutput, encodeOutputBytes, fieldModule, fieldPassSource, groupFieldRect, heavyTapSigmaAtScale, highlightModule, importColorMatrix, importModule, importPassSource, isUsablePlacement, lensAmountBasePx, lensDepthPx, lensDirection, lensDisplacementPx, lensExtentPx, lensHeightBasePx, lensMagnitudePx, lensOvalizationAt, lensSizeGain, lensSizeGainFromThickness, linearGradientStops, linearToSrgb, linearToSrgbChannel, occlusionAlphaUnderPolicy, occlusionLiftForPolicy, opticsModule, opticsUnderPolicy, outerShadowAlpha, outerShadowFalloff, outerShadowLiftRise, outerShadowOcclusionAt, outerShadowReachPx, outerShadowThickOcclusion, outerShadowThinOcclusion, outerShadowUnderPolicy, packInstances, pipelineKey, placementFit, planPyramid, poolKey, readbackDue, refractionRank, relativeLuminance, rendererError, resolveSurfaces, rimAlongSideFactor, rimAlongSideField, samePlacement, scatterDeepThickness, scatterFloorAtScale, scatterGainAt, scatterGainAtScale, scatterGainFarAtScale, scatterHeavyShareThickAtScale, scatterRampAreaMean, scatterRampReachDevicePx, scatterRampStart, scatterSharpShare, scatterSpanMaxAtScale, scatterThickness, shadowDepthPx, sizeOcclusionAlpha, sizeOcclusionAlphaAt, sizeOuterShadowOcclusion, sizeOuterShadowOcclusionAt, sizeScatterSigma, sizeScatterSigmaAt, sizeShadowDepth, sizeShadowDepthAt, sizeThickness, sizeThicknessUnderPolicy, sizeToneLevelFar, snapRectToDevicePixels, srgbToLinear, srgbToLinearChannel, statsFromBuffer, supportsTimestamps, texelsPerCssPx, tintShade, tintShadeLayer, tintToneAdaptation, tintedMaterialColour, validateAppTexture, withMaterialOverrides };
|
|
6914
|
-
//# sourceMappingURL=dist-
|
|
6915
|
-
//# sourceMappingURL=dist-
|
|
7393
|
+
//# sourceMappingURL=dist-VQPRX7BX.js.map
|
|
7394
|
+
//# sourceMappingURL=dist-VQPRX7BX.js.map
|