-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Workaround for feathering of sharp edges #7554
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Preview available at https://egui-pr-preview.github.io/pr/7554-feathering-fix View snapshot changes at kitdiff |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks very promising! Thanks for working on this.
There is some related code here:
egui/crates/epaint/src/tessellator.rs
Lines 404 to 418 in b36a259
let normal = (n0 + n1) / 2.0; | |
let length_sq = normal.length_sq(); | |
let right_angle_length_sq = 0.5; | |
let sharper_than_a_right_angle = length_sq < right_angle_length_sq; | |
if sharper_than_a_right_angle { | |
// cut off the sharp corner | |
let center_normal = normal.normalized(); | |
let n0c = (n0 + center_normal) / 2.0; | |
let n1c = (n1 + center_normal) / 2.0; | |
self.add_point(points[i], n0c / n0c.length_sq()); | |
self.add_point(points[i], n1c / n1c.length_sq()); | |
} else { | |
// miter join | |
self.add_point(points[i], normal / length_sq); | |
} |
and here:
egui/crates/epaint/src/tessellator.rs
Lines 450 to 472 in b36a259
// We can't just cut off corners for filled shapes like this, | |
// because the feather will both expand and contract the corner along the provided normals | |
// to make sure it doesn't grow, and the shrinking will make the inner points cross each other. | |
// | |
// A better approach is to shrink the vertices in by half the feather-width here | |
// and then only expand during feathering. | |
// | |
// See https://github.com/emilk/egui/issues/1226 | |
const CUT_OFF_SHARP_CORNERS: bool = false; | |
let right_angle_length_sq = 0.5; | |
let sharper_than_a_right_angle = length_sq < right_angle_length_sq; | |
if CUT_OFF_SHARP_CORNERS && sharper_than_a_right_angle { | |
// cut off the sharp corner | |
let center_normal = normal.normalized(); | |
let n0c = (n0 + center_normal) / 2.0; | |
let n1c = (n1 + center_normal) / 2.0; | |
self.add_point(points[i], n0c / n0c.length_sq()); | |
self.add_point(points[i], n1c / n1c.length_sq()); | |
} else { | |
// miter join | |
self.add_point(points[i], normal / length_sq); | |
} |
I wonder if that is still needed 🤔
Also worth checking that we don't regress on #1226
thanks for adding a test btw 🙏
I did couple of changes to the test, namely to be more like #1226. I've put the limit into Unfortunately, although IMO it's still better to have this, but it seems that there are no golden value here. ![]() ![]() ![]() |
crates/epaint/src/tessellator.rs
Outdated
if normal.length_sq() > max_feathering_normal_length_sq { | ||
normal * (max_feathering_normal_length_sq / normal.length_sq()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is incorrect.
if normal = [10, 0]
for instance, and max_feathering_normal_length = 2, so max_feathering_normal_length_sq = 4, then we would divide by 100/4 instead of 10/2.
if normal.length_sq() > max_feathering_normal_length_sq { | |
normal * (max_feathering_normal_length_sq / normal.length_sq()) | |
if normal.length_sq() > sqr(max_feathering_normal_length) { | |
max_feathering_normal_length * normal.normalize() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Co-authored-by: Emil Ernerfeldt <[email protected]>
be732d9
to
aec79de
Compare
e8350d6
to
be732d9
Compare
I am working on rendering vector maps in Walkers (which looks promising!) and I noticed weird artifacts:
It appears that the issue is caused by edge normals, which kind of explode when the shape is sharp enough. This PR adds a limiter, so that the normal is clamped when it crosses certain length. It's not perfect and most likely can be fixed in more elegant way, but it does seem like an improvement: