web: separate global endpoint curves (blacks/whites) from local tone mapping to eliminate grey aura around silhouettes and bump sw cache to v4
This commit is contained in:
@@ -320,30 +320,36 @@ vec3 lightMove(vec3 c, float t, float o) {
|
||||
return clamp(vec3(o) + (c - vec3(t)) * k, 0.0, 1.0);
|
||||
}
|
||||
vec3 toneRamp(vec3 c, float t, float base, float bl, float sh, float hl, float wh, float dr) {
|
||||
// Edge-aware range falloff: when |t - base| is small (flat/fine texture), edgeW is 1.0.
|
||||
// Edge-aware range falloff for local tone mapping: when |t - base| is small (flat/fine texture), edgeW is 1.0.
|
||||
// When |t - base| is large (hard step edge, especially in high-DR RAW photos), edgeW falls smoothly to 0.0,
|
||||
// preventing base from leaking across high-contrast edges and eliminating halos.
|
||||
// preventing base from leaking across high-contrast edges.
|
||||
float diff = abs(t - base);
|
||||
float edgeW = 1.0 - smoothstep(0.08, 0.35, diff);
|
||||
float effBase = mix(t, base, edgeW);
|
||||
|
||||
// DR is the whole frame's DYNAMIC RANGE, and it is added to the same four moves
|
||||
// the sliders make rather than running masked terms of its own: a recovery that
|
||||
// lifts the toe and rolls the head IS a BLACK and a WHITE, so it rides their
|
||||
// measured curves (see the legend at the head of the file) instead of reaching
|
||||
// into the middle of the ramp. A mask has no such knob and hands in 0, which is
|
||||
// what these terms are worth when DR is off on the frame too.
|
||||
float o = toneCurve(effBase, clamp(bl + dr * 0.12, -1.0, 1.0), clamp(sh + dr * 0.06, -1.0, 1.0),
|
||||
clamp(hl - dr * 0.09, -1.0, 1.0), clamp(wh - dr * 0.18, -1.0, 1.0));
|
||||
// A caller with no neighbourhood of its own (a mask) hands in the pixel as its
|
||||
// base, and the difference is then exactly zero: the target is the ramp at t,
|
||||
// the global move, which is what the ratio gave it too.
|
||||
float target = clamp(o + (t - effBase), 0.0, 1.0);
|
||||
float blVal = clamp(bl + dr * 0.12, -1.0, 1.0);
|
||||
float shVal = clamp(sh + dr * 0.06, -1.0, 1.0);
|
||||
float hlVal = clamp(hl - dr * 0.09, -1.0, 1.0);
|
||||
float whVal = clamp(wh - dr * 0.18, -1.0, 1.0);
|
||||
|
||||
// A. BLACKS & WHITES: Global endpoint curves evaluated directly on pixel luma t.
|
||||
// Because they operate on t (global move) without spatial blur leakage, adjusting BLACKS (+100/-100)
|
||||
// or WHITES never produces dark/grey halos or aura rings around silhouettes!
|
||||
float tGlobal = tonebl(t, blVal);
|
||||
tGlobal = tonewh(tGlobal, whVal);
|
||||
|
||||
// B. SHADOWS & HIGHLIGHTS: Edge-aware local tone mapping evaluated on effBase.
|
||||
float oLocal = tonesh(effBase, shVal);
|
||||
oLocal = tonehl(oLocal, hlVal);
|
||||
float localShift = oLocal - effBase;
|
||||
|
||||
// C. Combine global endpoint remapping and local tone fill.
|
||||
float target = clamp(tGlobal + localShift, 0.0, 1.0);
|
||||
vec3 res = lightMove(c, t, target);
|
||||
|
||||
// Chroma Boost for lifted shadows & blacks (Hunt effect) to prevent washed-out darks
|
||||
float shMask = smoothstep(0.02, 0.12, effBase) * (1.0 - smoothstep(0.25, 0.55, effBase));
|
||||
float uBl = clamp(1.0 - effBase / ${TONE_BLACK_EDGE}, 0.0, 1.0);
|
||||
float uBl = clamp(1.0 - t / ${TONE_BLACK_EDGE}, 0.0, 1.0);
|
||||
float blMask = uBl * uBl * uBl;
|
||||
float boost = 1.0 + (shMask * max(sh, 0.0) * 0.35) + (blMask * max(bl, 0.0) * 0.25);
|
||||
if (boost > 1.001) {
|
||||
|
||||
Reference in New Issue
Block a user