2026-07-02 02:07:32 +00:00
|
|
|
"use strict";var t=Object.defineProperty;var n=Object.getOwnPropertyDescriptor;var o=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var s=(e,a)=>{for(var i in a)t(e,i,{get:a[i],enumerable:!0})},f=(e,a,i,r)=>{if(a&&typeof a=="object"||typeof a=="function")for(let l of o(a))!h.call(e,l)&&l!==i&&t(e,l,{get:()=>a[l],enumerable:!(r=n(a,l))||r.enumerable});return e};var p=e=>f(t({},"__esModule",{value:!0}),e);var g={};s(g,{REGION_PAINT_SKSL:()=>u});module.exports=p(g);const u=`
|
2026-06-26 07:23:52 +00:00
|
|
|
uniform shader originTex;
|
|
|
|
|
uniform shader paintColorTex;
|
|
|
|
|
uniform shader lowFreqTex;
|
|
|
|
|
uniform shader highFreqTex;
|
|
|
|
|
|
|
|
|
|
uniform float colorBaseOpacity;
|
|
|
|
|
uniform float lLightOpacity;
|
|
|
|
|
uniform float textureOpacity;
|
|
|
|
|
uniform float showOrigin;
|
|
|
|
|
|
|
|
|
|
float luminance(half3 c) {
|
|
|
|
|
return dot(c, half3(0.2126, 0.7152, 0.0722));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
half3 setLuminance(float lum, half3 base) {
|
|
|
|
|
float diff = lum - luminance(base);
|
|
|
|
|
return base + diff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
half3 luminosityBlend(half3 base, half3 blend) {
|
|
|
|
|
return setLuminance(luminance(blend), base);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
half3 overlayBlend(half3 base, half3 blend) {
|
|
|
|
|
half3 low = 2.0 * base * blend;
|
|
|
|
|
half3 high = 1.0 - 2.0 * (1.0 - base) * (1.0 - blend);
|
|
|
|
|
return mix(low, high, step(half3(0.5), base));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
half4 main(float2 coord) {
|
|
|
|
|
half4 origin = originTex.eval(coord);
|
|
|
|
|
if (showOrigin > 0.5) {
|
|
|
|
|
return origin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
half4 paintEntry = paintColorTex.eval(coord);
|
2026-07-02 02:07:32 +00:00
|
|
|
// The paintColorMap uses Unpremul alpha: painted pixels \u2192 (R,G,B,255),
|
|
|
|
|
// transparent pixels \u2192 (0,0,0,0). GPU bilinear sampling interpolates
|
2026-06-26 07:23:52 +00:00
|
|
|
// straight-alpha values, so at boundaries rgb = trueColor * sampled.a
|
|
|
|
|
// (contaminated with black from the transparent neighbour).
|
|
|
|
|
//
|
|
|
|
|
// Unpremultiply to recover the true paint color:
|
|
|
|
|
// trueColor = sampled.rgb / sampled.a
|
|
|
|
|
// This eliminates dark fringing at region boundaries.
|
|
|
|
|
float pa = paintEntry.a + 0.0001;
|
|
|
|
|
paintEntry.rgb /= pa;
|
|
|
|
|
|
|
|
|
|
// Gate sub-pixel alpha to kill residual sampling noise.
|
2026-07-02 02:07:32 +00:00
|
|
|
// Thresholds are deliberately low (\u22481.3\u20133.8 in byte space) because
|
|
|
|
|
// post-unpremul the RGB is correct at any alpha \u2265 0 \u2014 we only need
|
2026-06-26 07:23:52 +00:00
|
|
|
// to suppress samples that contribute negligibly to the final blend.
|
|
|
|
|
// Using *= preserves the smooth edge; higher-alpha samples pass through.
|
|
|
|
|
paintEntry.a *= smoothstep(0.005, 0.015, paintEntry.a);
|
|
|
|
|
|
|
|
|
|
half3 paintRgb = paintEntry.rgb;
|
|
|
|
|
half lowL = lowFreqTex.eval(coord).r;
|
|
|
|
|
half highL = highFreqTex.eval(coord).r;
|
|
|
|
|
|
|
|
|
|
half3 base = paintRgb * colorBaseOpacity;
|
|
|
|
|
half3 lit = luminosityBlend(base, half3(lowL));
|
|
|
|
|
half3 withLight = mix(base, lit, lLightOpacity);
|
|
|
|
|
half3 tex = overlayBlend(withLight, half3(highL));
|
|
|
|
|
half3 finalRgb = mix(withLight, tex, textureOpacity);
|
|
|
|
|
|
|
|
|
|
// Soft edge blend using the (feathered) alpha from the paint color map as coverage.
|
|
|
|
|
half3 blended = mix(origin.rgb, finalRgb, paintEntry.a);
|
|
|
|
|
return half4(blended, 1.0);
|
|
|
|
|
}
|
|
|
|
|
`;
|