mirror of
https://github.com/storytold/lightcraft.git
synced 2026-11-13 09:20:07 -06:00
Treat a first intersect mask component as its base selection (#3854)
* Treat a first intersect mask component as its base selection A mask created with Intersect as its first component currently renders as empty, so the overlay and local adjustments never appear. Using that component as the base matches how Add and Subtract first components already behave. Change evaluate_one so the first component always sets the base alpha regardless of its combine op. Add a regression test with a single Intersect linear-gradient component asserting the start side is selected. Test: intersect_first_component_selects_its_shape failed before the change and passes after. * Masks: the GPU treats a first Intersect as the base too, and the process doc says so Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Docs: what changes for masks that start with Intersect Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: eliets2 <287273517+eliets2@users.noreply.github.com> Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
eliets2
FredApps
parent
081190c92f
commit
8f638b33bd
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user