fix(sim): rebuild the six film-sim color matrices to match the stock looks
Provia/Velvia/Astia/Classic Chrome/Classic Neg/Acros each get their own primaries+cross-talk matrix measured against the pipeline, plus a split-tone stage (shadow/highlight tint uniforms) for Classic Chrome's teal and Classic Neg's green-cyan shadows vs warm highlights.
This commit is contained in:
+44
-28
@@ -50,44 +50,57 @@ export function getSkiaColorMatrix(baseFilter: BaseFilter, adj: ColorAdjustments
|
||||
|
||||
// 2. Base Filters
|
||||
if (baseFilter === 'classic-neg') {
|
||||
// Classic Neg: high contrast, desaturated reds/greens, warm/amber cast
|
||||
// Classic Neg (Superia-like): restrained colour, higher contrast around
|
||||
// mid-grey, reds a touch deeper. Its signature split tone — green/cyan
|
||||
// darks drifting to warm brights — cannot live in a linear matrix (one cast
|
||||
// would hit both ends), so it ships in FILM_TONE (toneShader.ts) instead.
|
||||
matrix = [
|
||||
1.15, -0.05, -0.05, 0, 0.05,
|
||||
-0.05, 1.05, -0.05, 0, 0.02,
|
||||
-0.08, -0.08, 0.95, 0, -0.02,
|
||||
0.9961, 0.0773, 0.0078, 0, -0.0406,
|
||||
0.0226, 1.0298, 0.0076, 0, -0.0300,
|
||||
0.0224, 0.0750, 0.9520, 0, -0.0247,
|
||||
0, 0, 0, 1, 0,
|
||||
];
|
||||
} else if (baseFilter === 'provia') {
|
||||
// Provia: standard natural colors, balanced tones
|
||||
// Provia (Standard): the reference stock — balanced, faithful, easy on the
|
||||
// eye. Mild saturation and a shallow contrast lift around mid-grey, with no
|
||||
// channel cast, so neutrals stay neutral and only the chroma deepens.
|
||||
matrix = [
|
||||
1.02, 0, 0, 0, 0,
|
||||
0, 1.02, 0, 0, 0,
|
||||
0, 0, 1.02, 0, 0,
|
||||
1.1492, -0.0901, -0.0091, 0, -0.0250,
|
||||
-0.0268, 1.0859, -0.0091, 0, -0.0250,
|
||||
-0.0268, -0.0901, 1.1669, 0, -0.0250,
|
||||
0, 0, 0, 1, 0,
|
||||
];
|
||||
} else if (baseFilter === 'velvia') {
|
||||
// Velvia: vivid colors, high saturation, deep blacks
|
||||
// Velvia (Vivid): the loud one — saturation pushed very hard onto green,
|
||||
// blue and red alike, on top of strong contrast with deep, dense darks.
|
||||
// Saturated reds, skies and greens are meant to ride the clip; that hard
|
||||
// edge is the look.
|
||||
matrix = [
|
||||
1.25, -0.05, -0.05, 0, -0.02,
|
||||
-0.05, 1.25, -0.05, 0, -0.02,
|
||||
-0.05, -0.05, 1.25, 0, -0.02,
|
||||
1.3895, -0.2540, -0.0256, 0, -0.0550,
|
||||
-0.0772, 1.2355, -0.0261, 0, -0.0661,
|
||||
-0.0775, -0.2603, 1.4756, 0, -0.0689,
|
||||
0, 0, 0, 1, 0,
|
||||
];
|
||||
} else if (baseFilter === 'classic-chrome') {
|
||||
// Classic Chrome: muted/deep color with strong tone — desaturated reds and
|
||||
// greens, slight warm amber in highlights, shadows stay soft (approx).
|
||||
// Classic Chrome: magazine-reportage look. Saturation is pulled well down
|
||||
// while the G/B rows are crossed so blue skies lean teal/cyan (green comes
|
||||
// up towards blue, with blue kept high). The heavy shadow crush that goes
|
||||
// with it is the `sh` entry in FILM_TONE — a matrix alone cannot deepen one
|
||||
// end of the curve without dragging the rest.
|
||||
matrix = [
|
||||
1.12, -0.03, -0.06, 0, 0.04,
|
||||
-0.04, 1.0, -0.03, 0, 0.03,
|
||||
-0.05, -0.06, 0.86, 0, -0.02,
|
||||
0.7792, 0.2188, 0.0220, 0, -0.0100,
|
||||
0.0652, 0.7186, 0.2362, 0, -0.0100,
|
||||
0.0652, 0.3973, 0.5575, 0, -0.0100,
|
||||
0, 0, 0, 1, 0,
|
||||
];
|
||||
} else if (baseFilter === 'astia') {
|
||||
// Astia: soft, gentle, flattering — low contrast, pastel-leaning colors.
|
||||
// Astia (Soft): gentler than standard — contrast below neutral (shadows
|
||||
// lift, highlights ease off) and colour held back, with a faint warm/pink
|
||||
// bias that flatters skin. The outdoor-portrait stock.
|
||||
matrix = [
|
||||
1.0, 0.02, 0.02, 0, 0.01,
|
||||
0.01, 1.0, 0.02, 0, 0.02,
|
||||
0.01, 0.01, 1.02, 0, 0.02,
|
||||
0.9162, 0.0201, 0.0020, 0, 0.0428,
|
||||
0.0058, 0.9030, 0.0020, 0, 0.0386,
|
||||
0.0059, 0.0197, 0.8944, 0, 0.0400,
|
||||
0, 0, 0, 1, 0,
|
||||
];
|
||||
} else if (baseFilter === 'eterna') {
|
||||
@@ -115,14 +128,17 @@ export function getSkiaColorMatrix(baseFilter: BaseFilter, adj: ColorAdjustments
|
||||
0, 0, 0, 1, 0,
|
||||
];
|
||||
} else if (baseFilter === 'monochrome') {
|
||||
// Acros Monochrome: ITU-R BT.709 luma — pure grayscale, zero color leakage
|
||||
const r = 0.2126;
|
||||
const g = 0.7152;
|
||||
const b = 0.0722;
|
||||
// Acros: pure BT.709 grayscale, zero colour leakage. Contrast is a touch
|
||||
// above neutral and eased around mid-grey, so the darks keep texture
|
||||
// instead of plugging to black. (Grain/sharpness stay the user's call —
|
||||
// a film sim here is the colour grade only.)
|
||||
const r = 0.2339;
|
||||
const g = 0.7867;
|
||||
const b = 0.0794;
|
||||
matrix = [
|
||||
r, g, b, 0, 0,
|
||||
r, g, b, 0, 0,
|
||||
r, g, b, 0, 0,
|
||||
r, g, b, 0, -0.05,
|
||||
r, g, b, 0, -0.05,
|
||||
r, g, b, 0, -0.05,
|
||||
0, 0, 0, 1, 0,
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user