Skip to content

Commit

Permalink
Make tangents at subpath end watertight (#695)
Browse files Browse the repository at this point in the history
At subpath end, the last path segment is encoded with the end point
chosen so that the vector from the current point to the end point is the
tangent, ie the same vector as cubic_start_tangent applied to the first
segment in the subpath. In those cases, compute the tangent by
subtracting those two points, rather than cubic_start_tangent applied to
the line. These are mathematically identical, but may give different
results because of roundoff.

There are two cases: an open subpath, in which case the case is applied
to the tangent at draw_start_cap, or a closed subpath, where the logic
is in the tangent calculation in read_neighboring_segment.

Both GPU and CPU shaders are updated. It hasn't been carefully
validated.

Hopefully fixes #616 and #650.
  • Loading branch information
raphlinus authored Sep 23, 2024
1 parent 96457d0 commit 4433203
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 4 deletions.
7 changes: 5 additions & 2 deletions vello_shaders/shader/flatten.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,10 @@ fn read_neighboring_segment(ix: u32) -> NeighboringSegment {
let is_closed = (tag.tag_byte & PATH_TAG_SEG_TYPE) == PATH_TAG_LINETO;
let is_stroke_cap_marker = (tag.tag_byte & PATH_TAG_SUBPATH_END) != 0u;
let do_join = !is_stroke_cap_marker || is_closed;
let tangent = cubic_start_tangent(pts.p0, pts.p1, pts.p2, pts.p3);
var tangent = pts.p3 - pts.p0;
if !is_stroke_cap_marker {
tangent = cubic_start_tangent(pts.p0, pts.p1, pts.p2, pts.p3);
}
return NeighboringSegment(do_join, tangent);
}

Expand Down Expand Up @@ -844,7 +847,7 @@ fn main(
if is_stroke_cap_marker {
if is_open {
// Draw start cap
let tangent = cubic_start_tangent(pts.p0, pts.p1, pts.p2, pts.p3);
let tangent = pts.p3 - pts.p0;
let offset_tangent = offset * normalize(tangent);
let n = offset_tangent.yx * vec2f(-1., 1.);
draw_cap(path_ix, (style_flags & STYLE_FLAGS_START_CAP_MASK) >> 2u,
Expand Down
8 changes: 6 additions & 2 deletions vello_shaders/src/cpu/flatten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,11 @@ fn read_neighboring_segment(
let is_closed = (tag.tag_byte & PATH_TAG_SEG_TYPE) == PATH_TAG_LINETO;
let is_stroke_cap_marker = (tag.tag_byte & PathTag::SUBPATH_END_BIT) != 0;
let do_join = !is_stroke_cap_marker || is_closed;
let tangent = cubic_start_tangent(pts.p0, pts.p1, pts.p2, pts.p3);
let tangent = if is_stroke_cap_marker {
pts.p3 - pts.p0
} else {
cubic_start_tangent(pts.p0, pts.p1, pts.p2, pts.p3)
};
NeighboringSegment { do_join, tangent }
}

Expand Down Expand Up @@ -704,7 +708,7 @@ fn flatten_main(
if is_stroke_cap_marker {
if is_open {
// Draw start cap
let tangent = cubic_start_tangent(pts.p0, pts.p1, pts.p2, pts.p3);
let tangent = pts.p3 - pts.p0;
let offset_tangent = offset * tangent.normalize();
let n = Vec2::new(-offset_tangent.y, offset_tangent.x);
draw_cap(
Expand Down

0 comments on commit 4433203

Please sign in to comment.