mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-09 20:31:29 +11:00
Introduce test scenes that demonstrates conflation artifacts
Added two scenes that demonstrate conflation artifacts as described in https://github.com/linebender/vello/issues/49. The first scene demonstrates adjacent triangles and rects that belong to the same path and use opposite winding. The second scene demonstrates strokes with overlapping square caps (these strokes are currently expressed as rects painted with the NonZero fill rule).
This commit is contained in:
parent
020a7f5c01
commit
dc2e6690c4
|
@ -30,6 +30,8 @@ pub fn test_scenes() -> SceneSet {
|
|||
scene!(animated_text: animated),
|
||||
scene!(brush_transform: animated),
|
||||
scene!(blend_grid),
|
||||
scene!(conflation_artifacts),
|
||||
scene!(labyrinth),
|
||||
];
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
scenes.push(ExampleScene {
|
||||
|
@ -403,6 +405,169 @@ fn blend_square(blend: BlendMode) -> SceneFragment {
|
|||
fragment
|
||||
}
|
||||
|
||||
fn conflation_artifacts(sb: &mut SceneBuilder, _: &mut SceneParams) {
|
||||
use PathEl::*;
|
||||
const N: f64 = 50.0;
|
||||
const S: f64 = 4.0;
|
||||
|
||||
let scale = Affine::scale(S);
|
||||
let x = N + 0.5; // Fraction pixel offset reveals the problem on axis-aligned edges.
|
||||
let mut y = N;
|
||||
|
||||
// Two adjacent triangles touching at diagonal edge with opposing winding numbers
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
Affine::translate((x, y)) * scale,
|
||||
Color::RED,
|
||||
None,
|
||||
&[
|
||||
// triangle 1
|
||||
MoveTo((0.0, 0.0).into()),
|
||||
LineTo((N, N).into()),
|
||||
LineTo((0.0, N).into()),
|
||||
LineTo((0.0, 0.0).into()),
|
||||
// triangle 2
|
||||
MoveTo((0.0, 0.0).into()),
|
||||
LineTo((N, N).into()),
|
||||
LineTo((N, 0.0).into()),
|
||||
LineTo((0.0, 0.0).into()),
|
||||
],
|
||||
);
|
||||
|
||||
// Adjacent rects, opposite winding
|
||||
y += S * N + 10.0;
|
||||
sb.fill(
|
||||
Fill::EvenOdd,
|
||||
Affine::translate((x, y)) * scale,
|
||||
Color::RED,
|
||||
None,
|
||||
&Rect::new(0.0, 0.0, N, N),
|
||||
);
|
||||
sb.fill(
|
||||
Fill::EvenOdd,
|
||||
Affine::translate((x, y)) * scale,
|
||||
Color::GREEN,
|
||||
None,
|
||||
&[
|
||||
// left rect
|
||||
MoveTo((0.0, 0.0).into()),
|
||||
LineTo((0.0, N).into()),
|
||||
LineTo((N * 0.5, N).into()),
|
||||
LineTo((N * 0.5, 0.0).into()),
|
||||
// right rect
|
||||
MoveTo((N * 0.5, 0.0).into()),
|
||||
LineTo((N, 0.0).into()),
|
||||
LineTo((N, N).into()),
|
||||
LineTo((N * 0.5, N).into()),
|
||||
],
|
||||
);
|
||||
|
||||
// Adjacent rects, same winding
|
||||
y += S * N + 10.0;
|
||||
sb.fill(
|
||||
Fill::EvenOdd,
|
||||
Affine::translate((x, y)) * scale,
|
||||
Color::RED,
|
||||
None,
|
||||
&Rect::new(0.0, 0.0, N, N),
|
||||
);
|
||||
sb.fill(
|
||||
Fill::EvenOdd,
|
||||
Affine::translate((x, y)) * scale,
|
||||
Color::GREEN,
|
||||
None,
|
||||
&[
|
||||
// left rect
|
||||
MoveTo((0.0, 0.0).into()),
|
||||
LineTo((0.0, N).into()),
|
||||
LineTo((N * 0.5, N).into()),
|
||||
LineTo((N * 0.5, 0.0).into()),
|
||||
// right rect
|
||||
MoveTo((N * 0.5, 0.0).into()),
|
||||
LineTo((N * 0.5, N).into()),
|
||||
LineTo((N, N).into()),
|
||||
LineTo((N, 0.0).into()),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
fn labyrinth(sb: &mut SceneBuilder, _: &mut SceneParams) {
|
||||
use PathEl::*;
|
||||
|
||||
let rows: &[[u8; 12]] = &[
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1],
|
||||
[1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1],
|
||||
[1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0],
|
||||
[0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0],
|
||||
[1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1],
|
||||
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1],
|
||||
[0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
];
|
||||
let cols: &[[u8; 10]] = &[
|
||||
[1, 1, 1, 1, 0, 1, 1, 1, 1, 1],
|
||||
[0, 0, 1, 0, 0, 0, 1, 1, 1, 0],
|
||||
[0, 1, 1, 0, 1, 1, 1, 0, 0, 1],
|
||||
[1, 1, 0, 0, 0, 0, 1, 0, 1, 0],
|
||||
[0, 0, 1, 0, 1, 0, 0, 0, 0, 1],
|
||||
[0, 0, 1, 1, 1, 0, 0, 0, 1, 0],
|
||||
[0, 1, 0, 1, 1, 1, 0, 0, 0, 0],
|
||||
[1, 1, 1, 0, 1, 1, 1, 0, 1, 0],
|
||||
[1, 1, 0, 1, 1, 0, 0, 0, 1, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 1],
|
||||
[0, 0, 1, 1, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 0, 0, 1],
|
||||
[1, 1, 1, 1, 1, 1, 0, 1, 1, 1],
|
||||
];
|
||||
let mut path = BezPath::new();
|
||||
for (y, row) in rows.iter().enumerate() {
|
||||
for (x, flag) in row.iter().enumerate() {
|
||||
let x = x as f64;
|
||||
let y = y as f64;
|
||||
if *flag == 1 {
|
||||
path.push(MoveTo((x - 0.1, y + 0.1).into()));
|
||||
path.push(LineTo((x + 1.1, y + 0.1).into()));
|
||||
path.push(LineTo((x + 1.1, y - 0.1).into()));
|
||||
path.push(LineTo((x - 0.1, y - 0.1).into()));
|
||||
|
||||
// The above is equivalent to the following stroke with width 0.2 and square
|
||||
// caps.
|
||||
//path.push(MoveTo((x, y).into()));
|
||||
//path.push(LineTo((x + 1.0, y).into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (x, col) in cols.iter().enumerate() {
|
||||
for (y, flag) in col.iter().enumerate() {
|
||||
let x = x as f64;
|
||||
let y = y as f64;
|
||||
if *flag == 1 {
|
||||
path.push(MoveTo((x - 0.1, y - 0.1).into()));
|
||||
path.push(LineTo((x - 0.1, y + 1.1).into()));
|
||||
path.push(LineTo((x + 0.1, y + 1.1).into()));
|
||||
path.push(LineTo((x + 0.1, y - 0.1).into()));
|
||||
// The above is equivalent to the following stroke with width 0.2 and square
|
||||
// caps.
|
||||
//path.push(MoveTo((x, y).into()));
|
||||
//path.push(LineTo((x, y + 1.0).into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note the artifacts are clearly visible at a fractional pixel offset/translation. They
|
||||
// disappear if the translation amount below is a whole number.
|
||||
sb.fill(
|
||||
Fill::NonZero,
|
||||
Affine::translate((20.5, 20.5)) * Affine::scale(80.0),
|
||||
Color::rgba8(0x70, 0x80, 0x80, 0xff),
|
||||
None,
|
||||
&path,
|
||||
)
|
||||
}
|
||||
|
||||
fn around_center(xform: Affine, center: Point) -> Affine {
|
||||
Affine::translate(center.to_vec2()) * xform * Affine::translate(-center.to_vec2())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue