mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-24 10:09:32 -06:00
Exposure: After Effects parameter ranges
All twelve sliders (Master, Red, Green, Blue) take After Effects' ranges: Exposure valid -100..100, slider -4..4, 2 decimals (was -20..20, slider -5..5); Offset -2..2, slider -0.5..0.5, 4 decimals (unchanged); Gamma Correction valid and slider 0.1..10, 2 decimals (was 0.01..9.99, slider 0.1..3). Every value inside the old Exposure and Offset ranges stays valid. Saved values are not clamped on load, so a gamma below 0.1 from an older project or a Photoshop import (0.01..9.99) is kept and still renders (the renderer's 0.01 floor is unchanged); only new edits clamp to 0.1. Test of the ranges and of an old gamma surviving the load refresh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c7060e2d75
commit
617b0a578d
@@ -1011,11 +1011,13 @@ pub fn specs() -> Vec<EffectSpec> {
|
||||
"Exposure",
|
||||
{
|
||||
let mut v = vec![p("channels", "Channels", Value::Enum(0), popup(&["Master", "Individual Channels"]))];
|
||||
// After Effects' ranges (valid, slider, decimals). Gamma values below 0.1 from
|
||||
// older projects or Photoshop imports (0.01..9.99) are kept and still render.
|
||||
let group = |ids: [&'static str; 3]| {
|
||||
[
|
||||
p(ids[0], "Exposure", num(0.0), slider(-20.0, 20.0, -5.0, 5.0, 2)),
|
||||
p(ids[0], "Exposure", num(0.0), slider(-100.0, 100.0, -4.0, 4.0, 2)),
|
||||
p(ids[1], "Offset", num(0.0), slider(-2.0, 2.0, -0.5, 0.5, 4)),
|
||||
p(ids[2], "Gamma Correction", num(1.0), slider(0.01, 9.99, 0.1, 3.0, 2)),
|
||||
p(ids[2], "Gamma Correction", num(1.0), slider(0.1, 10.0, 0.1, 10.0, 2)),
|
||||
]
|
||||
};
|
||||
v.extend(group(["master/exposure", "master/offset", "master/gamma"]));
|
||||
@@ -1417,6 +1419,38 @@ mod tests {
|
||||
assert!((neg[0] + 0.5).abs() < 1e-4, "{neg:?}");
|
||||
}
|
||||
|
||||
/// After Effects' Exposure ranges for all twelve sliders; a saved value outside them (a gamma
|
||||
/// of 0.05, valid before, as in Photoshop) survives loading and still renders.
|
||||
#[test]
|
||||
fn exposure_has_after_effects_ranges_and_keeps_old_values() {
|
||||
use effectcraft_project::build::Ids;
|
||||
let spec = crate::find("ec.color.exposure").unwrap();
|
||||
let want = [(-100.0, 100.0, -4.0, 4.0, 2), (-2.0, 2.0, -0.5, 0.5, 4), (0.1, 10.0, 0.1, 10.0, 2)];
|
||||
let sliders: Vec<_> = spec
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|p| match p.ui {
|
||||
ParamUi::Slider { min, max, slider_min, slider_max, decimals } => Some((p.id, (min, max, slider_min, slider_max, decimals))),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(sliders.len(), 12);
|
||||
for (i, (id, r)) in sliders.iter().enumerate() {
|
||||
assert_eq!(*r, want[i % 3], "{id}");
|
||||
}
|
||||
let mut next = 1;
|
||||
let mut g = crate::instantiate(spec, &mut Ids(&mut next), spec.name, [10.0, 10.0]);
|
||||
let gamma = g.prop_mut("master/gamma").unwrap();
|
||||
gamma.value = num(0.05);
|
||||
gamma.ui = slider(0.01, 9.99, 0.1, 3.0, 2);
|
||||
crate::migrate::upgrade_instance(spec, &mut g, &mut Ids(&mut next), [10.0, 10.0]);
|
||||
let gamma = g.prop_mut("master/gamma").unwrap();
|
||||
assert_eq!(gamma.value, num(0.05));
|
||||
assert!(matches!(gamma.ui, ParamUi::Slider { min, .. } if min == 0.1));
|
||||
let o = px("ec.color.exposure", &[("master/gamma", num(0.05)), ("bypassLinearLight", Value::Bool(true))], [0.5, 0.5, 0.5, 1.0]);
|
||||
assert!((o[0] - 0.5f32.powf(20.0)).abs() < 1e-9, "{o:?}");
|
||||
}
|
||||
|
||||
/// Exposure on a red [1, 0, 0] solid against After Effects 2026 renders (sRGB working space,
|
||||
/// not linearised, 32 bpc, 8-bit captures): the linear-light conversion is a pure 2.2 power.
|
||||
/// The piecewise sRGB curve gave 2 / 7 / 39 for the three smallest Offsets.
|
||||
|
||||
@@ -68,6 +68,7 @@ the GPU is performance, not parity.
|
||||
| 2026-10-19 | minor | Black & White's Tint keeps the gray's luminosity (Color blend), measured against After Effects 2026 renders (CPU and GPU) |
|
||||
| 2026-10-18 | minor | Tint uses Rec. 601 luminance weights, measured against After Effects 2026 renders of red, green, blue and grey solids (CPU and GPU) |
|
||||
| 2026-10-18 | minor | Exposure converts to linear light with a pure 2.2 power curve, as measured in After Effects (Offset 0.0005 / 0.002 / 0.02 / 0.1 on black: 8 / 15 / 43 / 90), not the piecewise sRGB curve |
|
||||
| 2026-10-18 | minor | Exposure converts to linear light with a pure 2.2 power curve, as measured in After Effects (Offset 0.0005 / 0.002 / 0.02 / 0.1 on black: 8 / 15 / 43 / 90), not the piecewise sRGB curve; its sliders take After Effects' ranges (Exposure −100..100, slider −4..4; Offset −2..2, slider −0.5..0.5; Gamma Correction 0.1..10) |
|
||||
| 2026-10-12 | minor | Parameters 3,014 to 3,017 (effects.md); #303, #514, #526, #533–#536 marked closed instead of pending |
|
||||
| 2026-10-12 | minor | Effect colour labels (26.5) added in Effect Controls |
|
||||
| 2026-10-12 | minor | Tint's Swap Colors button and agent-drivable command (#963); undo/redo, instance targeting, animated layer-time edits and invalid-input tests |
|
||||
|
||||
Reference in New Issue
Block a user