revert(heal): cut the mask's own fade again, not a step over the whole brush
This reverts8809eb8. The step cut takes the whole brush out of the frame, so the fill below has only the rim left to read from. The colour leak that cut was for no longer needs it:49c5c9chanded the mask the whole spot, and heal-colour-pass.mjs measures the repair 1.08 levels off the ground with the fade cut — the same 1.08 it measures with the step.
This commit is contained in:
@@ -448,40 +448,4 @@ assert.ok(worstBand <= 8, `a painted pixel at x=${bandAt} is ${worstBand} levels
|
||||
H = keptH;
|
||||
}
|
||||
|
||||
// 10. The brush put ON the blemish, which is what it is for. Every case above
|
||||
// paints its stroke well inside the brush, so the rim the fill reads is
|
||||
// ground however the hole was cut — and a fill that takes its colour from
|
||||
// the brush's OWN pixels is invisible there. Here the whole of what the
|
||||
// brush covers is the blemish, a disc just smaller than the brush, and the
|
||||
// repair has to come back the colour of the ground around it. This is the
|
||||
// shape the cut's softness leaks in: with the cut written as the mask's fade
|
||||
// — `a = 1 - mask.a` — the outer quarter of the spot stays in the frame at
|
||||
// partial weight, the blemish's rim is exactly in that band, and it is
|
||||
// weighed into the blur the fill is made of. The repair then lands in the
|
||||
// colour of the thing it was repairing, 4 levels off a grey ground on a
|
||||
// 226,34,40 blemish (measured; the cut variants in heal-colour-pass.mjs).
|
||||
{
|
||||
const BLEMISH_R = 0.045 * W; // 7.2px under this 8px brush
|
||||
const shadeBlemish = (x, y) =>
|
||||
Math.hypot(x - cx, y - cy) < BLEMISH_R ? [226, 34, 40] : [GREY, GREY, GREY];
|
||||
const onBlemish = healPass(bytesOf(shadeBlemish), [{ x: cx / W, y: cy / H, r: R }]);
|
||||
let worstOn = 0;
|
||||
let onCount = 0;
|
||||
for (let y = 0; y < H; y++) {
|
||||
for (let x = 0; x < W; x++) {
|
||||
if (onBlemish.mask[(y * W + x) * 4 + 3] < 250) continue;
|
||||
if (Math.hypot(x + 0.5 - cx, y + 0.5 - cy) > 0.5 * R * W * 0.75) continue;
|
||||
onCount++;
|
||||
for (let c = 0; c < 3; c++) {
|
||||
worstOn = Math.max(worstOn, Math.abs(onBlemish.pixels[(y * W + x) * 4 + c] - GREY));
|
||||
}
|
||||
}
|
||||
}
|
||||
assert.ok(onCount > 20, 'the brush painted too little to judge');
|
||||
assert.ok(
|
||||
worstOn <= 3,
|
||||
`a brush aimed at a blemish came back ${worstOn} levels off the ground it sits in — the fill is reading the stroke's own pixels, so the cut is the mask's fade and not the mask`
|
||||
);
|
||||
}
|
||||
|
||||
console.log('ok the stroke is one mask, the fill carries the light, and nothing outside it moved');
|
||||
|
||||
@@ -87,30 +87,19 @@ function num(v: unknown, fallback: number): number {
|
||||
}
|
||||
|
||||
// The first of the fill's two passes: the photo with the painted pixels taken
|
||||
// out of it. The colour of every pixel is kept and its alpha drops to nothing
|
||||
// over the brush, which is what turns the mask into a hole the second pass can
|
||||
// see the rim of. Written as premultiplied — rgb times that alpha — because
|
||||
// out of it. The colour of every pixel is kept and its alpha drops to what the
|
||||
// brush did not touch, which is what turns the mask into a hole the second pass
|
||||
// can see the rim of. Written as premultiplied — rgb times that alpha — because
|
||||
// that is what every surface here holds, and the blur below is built on it: a
|
||||
// blur of premultiplied pixels is a weighted average of the pixels that are
|
||||
// still there, with the hole weighing nothing.
|
||||
//
|
||||
// The cut is the WHOLE stroke, and it is a step rather than the mask's own fade.
|
||||
// The fill below reads the rim of this hole, so whatever is left standing inside
|
||||
// it is weighed into the repair. Cut at the mask's fade instead — `a = 1 -
|
||||
// mask.a`, the obvious reading of "take the mask out" — and the outer quarter of
|
||||
// every spot stays behind at partial weight. A brush aimed at a blemish has the
|
||||
// blemish's own rim in exactly that band, so the repair came back in the colour
|
||||
// of the thing being repaired: on a grey ground with a red blemish, the obvious
|
||||
// cut is 4.1 levels off the ground and the step is 1.1 (measured, the cut
|
||||
// variants in heal-colour-pass.mjs). The threshold is lightcraft's own: the
|
||||
// pixels a heal may read its tone from are the ones at alpha < 0.02 (spots.rs).
|
||||
export const HEAL_CUT_SKSL = `
|
||||
uniform shader img;
|
||||
uniform shader mask;
|
||||
|
||||
half4 main(float2 pos) {
|
||||
half4 c = img.eval(pos);
|
||||
half a = mask.eval(pos).a < 0.02 ? 1.0 : 0.0;
|
||||
half a = 1.0 - mask.eval(pos).a;
|
||||
half3 straight = c.a > 0.0001 ? c.rgb / c.a : c.rgb;
|
||||
return half4(straight * a, a);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user