diff --git a/crates/gpu/src/render.rs b/crates/gpu/src/render.rs index 8e6afa3700..de8c7ff16c 100644 --- a/crates/gpu/src/render.rs +++ b/crates/gpu/src/render.rs @@ -1480,7 +1480,7 @@ fn masks(cx: &mut Cx<'_>, lin: &Buf, prep: &Prep, plan: &Plan<'_>, host: &mut Ho let mut first = true; for comp in &m.components { let op = match comp.op { - _ if first && comp.op != MaskOp::Intersect => 0u32, + _ if first => 0u32, MaskOp::Add => 1, MaskOp::Subtract => 2, MaskOp::Intersect => 3, diff --git a/crates/pipeline/src/masks.rs b/crates/pipeline/src/masks.rs index 097e080a7e..b40e3dcd97 100644 --- a/crates/pipeline/src/masks.rs +++ b/crates/pipeline/src/masks.rs @@ -161,7 +161,7 @@ pub fn evaluate_one(m: &Mask, frame: &Frame, w: usize, h: usize, img: &Rgb32f, l if comp.invert { c.data.iter_mut().for_each(|v| *v = 1.0 - *v); } - if first && comp.op != MaskOp::Intersect { + if first { alpha = c; first = false; continue; diff --git a/crates/pipeline/src/masks/tests.rs b/crates/pipeline/src/masks/tests.rs index c97cd290e4..b57f9f6688 100644 --- a/crates/pipeline/src/masks/tests.rs +++ b/crates/pipeline/src/masks/tests.rs @@ -629,3 +629,14 @@ fn people_and_subject_use_person_mattes() { let lips = MaskShape::People { person: 0, parts: vec!["Lips".into()] }; assert_eq!(eval(&lips), shape_alpha(&lips, &f, w, h, &img, &l, 0.0, None)); } + +#[test] +fn intersect_first_component_selects_its_shape() { + let f = frame(100, 100); + let img = Rgb32f::new(100, 100); + let l = Plane::new(100, 100); + let shape = MaskShape::Radial { center: Point::new(0.5, 0.5), rx: 0.2, ry: 0.2, angle: 0.0, feather: 20.0, invert: false }; + let m = Mask { components: vec![MaskComponent { name: None, op: MaskOp::Intersect, invert: false, shape }], ..Default::default() }; + let a = evaluate_one(&m, &f, 100, 100, &img, &l, 0.0, None); + assert!(a.get(50, 50) > 0.99 && a.get(5, 5) < 0.01, "intersect first: {} {}", a.get(50, 50), a.get(5, 5)); +} diff --git a/docs/process-versions.md b/docs/process-versions.md index 7d1ae1927c..154906de0b 100644 --- a/docs/process-versions.md +++ b/docs/process-versions.md @@ -40,6 +40,12 @@ exports. Existing AI masks become 1–2 px tighter at a subject's edges, on ever inside, their outside and edges without contrast in the photo are unchanged. It landed in place as a bug fix: the outline is output that isn't in the photo nor in the edit, not a look anyone chose. +**A mask whose first component is Intersect** starts from that component, on the CPU and the GPU +(issue #1889). It used to start from nothing, so alone it selected nothing, with a later Add it gave +only what was added, and with the mask's Invert it gave the whole photo. Such masks now include the +first component, on every process. It landed in place as a bug fix: intersecting with nothing is not +a look anyone chose. + ## Adding a process 1. Add a variant to `Process` (`V2`), append it to `Process::ALL` (oldest first), give it its number in