mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-12 21:32:52 +00:00
Blend goes up to 10000 (it keeps its minimum of 1, below After Effects' 5) and Jitter up to 500 %, After Effects' recorded valid ranges in the same units. Defaults and sliders are unchanged. The CPU and GPU renderers capped Jitter's dither at 100 %, so higher values would be stored but render as 100. Both now take it from one function, four_color_jitter, which keeps the dither linear up to 500 %. Blend 10000 is a finite softening (Blend squared) at the same cost. Jitter was written as "percent" in keyframe text because its range was 0..100; a UNITS row keeps that unit.
This commit is contained in:
8 files changed
+53
-9
No files matched your search
@@ -743,8 +743,6 @@ mod tests {
|
||||
("ec.generate.beam", "endThickness", 3475),
|
||||
("ec.generate.grid", "border", 3476),
|
||||
("ec.stylize.scatter", "amount", 3477),
|
||||
("ec.generate.fourcolor", "blend", 3478),
|
||||
("ec.generate.fourcolor", "jitter", 3479),
|
||||
("ec.color.changecolor", "hueTransform", 3480),
|
||||
("ec.time.pixelmotionblur", "shutterAngle", 3481),
|
||||
("ec.time.pixelmotionblur", "shutterSamples", 3482),
|
||||
|
||||
@@ -121,11 +121,17 @@ pub fn four_color_softening(blend: f64, scale: f64) -> f64 {
|
||||
(b * b).max(1e-6)
|
||||
}
|
||||
|
||||
/// 4-Color Gradient's Jitter (percent, up to After Effects' 500 %) as the dither's strength: 1 at
|
||||
/// 100 %, a few code values of noise per unit.
|
||||
pub fn four_color_jitter(jitter: f64) -> f32 {
|
||||
(jitter / 100.0).clamp(0.0, 5.0) as f32
|
||||
}
|
||||
|
||||
fn four_color(ctx: &EffectCtx, mut b: Buf) -> Buf {
|
||||
let pts: Vec<((f64, f64), [f32; 4])> =
|
||||
(1..=4).map(|i| (b.to_px(ctx.params.v2(&format!("positionsColors/point{i}"))), ctx.params.color(&format!("positionsColors/color{i}")))).collect();
|
||||
let k = four_color_softening(ctx.params.f("blend"), b.scale);
|
||||
let jitter = (ctx.params.f("jitter") / 100.0).clamp(0.0, 1.0) as f32;
|
||||
let jitter = four_color_jitter(ctx.params.f("jitter"));
|
||||
let op = ctx.params.f("opacity") as f32 / 100.0;
|
||||
let mode = ctx.params.e("blendingMode");
|
||||
let seed = ctx.seed;
|
||||
@@ -349,8 +355,9 @@ pub fn specs() -> Vec<EffectSpec> {
|
||||
p("positionsColors/color3", "Color 3", col(1.0, 0.0, 1.0), ParamUi::Color),
|
||||
p("positionsColors/point4", "Point 4", pt(0.9, 0.9), ParamUi::Point),
|
||||
p("positionsColors/color4", "Color 4", col(0.0, 0.0, 1.0), ParamUi::Color),
|
||||
p("blend", "Blend", num(100.0), slider(1.0, 1000.0, 1.0, 1000.0, 1)),
|
||||
p("jitter", "Jitter", num(0.0), slider(0.0, 100.0, 0.0, 100.0, 1)),
|
||||
// After Effects' valid ranges (#3478, #3479); Blend keeps its lower minimum (1, not 5).
|
||||
p("blend", "Blend", num(100.0), slider(1.0, 10000.0, 1.0, 1000.0, 1)),
|
||||
p("jitter", "Jitter", num(0.0), slider(0.0, 500.0, 0.0, 100.0, 1)),
|
||||
p("opacity", "Opacity", num(100.0), slider(0.0, 100.0, 0.0, 100.0, 1)),
|
||||
p("blendingMode", "Blending Mode", Value::Enum(0), popup(&GEN_BLEND_MODES[..18])),
|
||||
],
|
||||
@@ -465,6 +472,21 @@ mod generator_tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// #3479: Jitter goes up to After Effects' 500 %, and more jitter dithers more (the dither
|
||||
/// stopped growing at 100 %).
|
||||
#[test]
|
||||
fn four_color_jitter_grows_up_to_five_hundred_percent() {
|
||||
let img = Image::filled(32, 32, [0.0, 0.0, 0.0, 1.0]);
|
||||
let spread = |jitter: f64| {
|
||||
let o = run_fx("ec.generate.fourcolor", &[("jitter", num(jitter))], img.clone(), 0.0, EffectEnv::default()).img;
|
||||
let flat = run_fx("ec.generate.fourcolor", &[], img.clone(), 0.0, EffectEnv::default()).img;
|
||||
o.data.iter().zip(&flat.data).map(|(a, b)| (a[0] - b[0]).abs()).fold(0.0f32, f32::max)
|
||||
};
|
||||
let (at100, at500) = (spread(100.0), spread(500.0));
|
||||
assert!(at100 > 0.0 && at500 > 4.0 * at100, "{at100} {at500}");
|
||||
assert!(at500 < 0.2, "a few code values: {at500}");
|
||||
}
|
||||
|
||||
/// After Effects 2026, 4-Color Gradient defaults (yellow, green, magenta, blue at 10 % / 90 %
|
||||
/// of a 1920 × 1080 layer) at Blend 100 and 300, here on a tenth-size layer with Blend 10
|
||||
/// and 30 (the weights scale with the layer): colours at AE pixels (10x + 5, 10y + 5).
|
||||
|
||||
@@ -99,7 +99,7 @@ pub use sim3::{PgBlit, PgPlan, playground_plan, playground_state};
|
||||
pub use stylize2::strobe_on;
|
||||
// CPU helpers the GPU kernels share (effectcraft-gpu).
|
||||
pub use blur2::{CAMERA_LENS_MAX_RADIUS, camera_lens_plain, camera_lens_radius, camera_lens_spans, radial_fast_pad};
|
||||
pub use generate::{four_color_softening, gen_mode};
|
||||
pub use generate::{four_color_jitter, four_color_softening, gen_mode};
|
||||
pub use generate2::pattern_kind as cell_pattern_kind;
|
||||
pub use generate2::{BoltSeg, Contour, Ghost, RadioPlan, Wave, flare_ghosts, lightning_segments, radio_plan};
|
||||
pub use generate3::{
|
||||
|
||||
@@ -273,6 +273,7 @@ pub(crate) const UNITS: &[(&str, &str, &str)] = &[
|
||||
("ec.distort.wavewarp", "width", "percent"),
|
||||
("ec.distort.wavewarp", "speed", "pixels"),
|
||||
("ec.generate.fourcolor", "blend", "percent"),
|
||||
("ec.generate.fourcolor", "jitter", "percent"),
|
||||
("ec.generate.advancedlightning", "coreSettings/coreRadius", ""),
|
||||
("ec.generate.advancedlightning", "glowSettings/glowRadius", "percent"),
|
||||
("ec.generate.advancedlightning", "alphaObstacle", "pixels"),
|
||||
|
||||
@@ -9,8 +9,9 @@ use serde_json::{Value, json};
|
||||
|
||||
use crate::Session;
|
||||
|
||||
/// (issue, effect, parameter path, lowest, highest): the ends of After Effects' valid range,
|
||||
/// in EffectCraft's units, each outside the range the effect accepted before the issue.
|
||||
/// (issue, effect, parameter path, lowest, highest): the ends of the range the effect now accepts,
|
||||
/// in EffectCraft's units: After Effects' valid range, or wider where EffectCraft already was.
|
||||
/// At least one end of each is outside the range accepted before the issue.
|
||||
#[rustfmt::skip]
|
||||
const ROWS: &[(u32, &str, &str, f64, f64)] = &[
|
||||
(3487, "ec.color.levelsic", "rgb/rgbInBlack", -10000.0, 10000.0),
|
||||
@@ -38,6 +39,8 @@ const ROWS: &[(u32, &str, &str, f64, f64)] = &[
|
||||
(3489, "ec.color.levelsic", "alpha/alphaOutBlack", -10000.0, 10000.0),
|
||||
(3490, "ec.color.levelsic", "alpha/alphaOutWhite", -10000.0, 10000.0),
|
||||
(3491, "ec.color.levelsic", "alpha/alphaGamma", 0.0, 10.0),
|
||||
(3478, "ec.generate.fourcolor", "blend", 1.0, 10000.0),
|
||||
(3479, "ec.generate.fourcolor", "jitter", 0.0, 500.0),
|
||||
];
|
||||
|
||||
fn path(effect: &str, param: &str) -> String {
|
||||
|
||||
@@ -480,3 +480,21 @@ fn camera_light_and_material_options_are_written_as_after_effects_does() {
|
||||
assert!(text.contains(block), "{block}in\n{text}");
|
||||
}
|
||||
}
|
||||
|
||||
/// The unit column of `name`'s block in copied keyframe text.
|
||||
fn unit_of<'a>(text: &'a str, name: &str) -> &'a str {
|
||||
let mut lines = text.lines().skip_while(|l| !l.contains(&format!("\t{name} #")));
|
||||
lines.next().unwrap_or_else(|| panic!("no {name} in\n{text}"));
|
||||
lines.next().and_then(|l| l.strip_prefix("\tFrame\t")).and_then(|l| l.strip_suffix('\t')).unwrap_or_else(|| panic!("{name} in\n{text}"))
|
||||
}
|
||||
|
||||
/// Widening a 0..100 slider to After Effects' range (#3479, #3483, #3484) keeps the unit the
|
||||
/// keyframe text writes for it.
|
||||
#[test]
|
||||
fn widened_effect_ranges_keep_their_keyframe_text_units() {
|
||||
let (mut s, l) = session();
|
||||
s.execute("effect.apply", json!({"layer": l.0, "effect": "ec.generate.fourcolor"})).unwrap();
|
||||
let text = copy_props(&mut s, l, &["effects/#1/blend", "effects/#1/jitter"]);
|
||||
assert_eq!(unit_of(&text, "Blend"), "percent");
|
||||
assert_eq!(unit_of(&text, "Jitter"), "percent");
|
||||
}
|
||||
@@ -385,7 +385,7 @@ fn four_color(e: &mut Enc, ctx: &EffectCtx, b: GBuf) -> Option<GBuf> {
|
||||
p.f[4 + i] = ctx.params.color(&format!("positionsColors/color{}", i + 1));
|
||||
}
|
||||
let k = effectcraft_effects::four_color_softening(ctx.params.f("blend"), b.scale);
|
||||
let jitter = (ctx.params.f("jitter") / 100.0).clamp(0.0, 1.0) as f32;
|
||||
let jitter = effectcraft_effects::four_color_jitter(ctx.params.f("jitter"));
|
||||
p.u[0] = [gen_mode(ctx.params.e("blendingMode")), ctx.seed, 0, 0];
|
||||
p.f[8] = [k as f32, jitter, ctx.params.f("opacity") as f32 / 100.0, 0.0];
|
||||
run(e, "gen_fourcolor", &p, b, None, None)
|
||||
|
||||
@@ -167,6 +167,8 @@ fn generators() {
|
||||
effect_case("ec.generate.fourcolor", &[]);
|
||||
effect_case("ec.generate.fourcolor", &[("blend", n(40.0)), ("jitter", n(50.0)), ("opacity", n(80.0)), ("blendingMode", e(3))]);
|
||||
effect_case("ec.generate.fourcolor", &[("blend", n(600.0)), ("blendingMode", e(16)), ("positionsColors/point2", pt(30.0, 20.0))]);
|
||||
// #3478, #3479: the top of After Effects' ranges.
|
||||
effect_case("ec.generate.fourcolor", &[("blend", n(10000.0)), ("jitter", n(500.0))]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user