Skip to content
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

Missing antialiasing on some edges in VgerDemo... #4

Closed
luckyclan opened this issue Feb 10, 2022 · 20 comments
Closed

Missing antialiasing on some edges in VgerDemo... #4

luckyclan opened this issue Feb 10, 2022 · 20 comments
Assignees

Comments

@luckyclan
Copy link

luckyclan commented Feb 10, 2022

I noticed it in VgerDemo on iPad Pro 11 from 2018, and ipadOS 14.8
This also happens on very simple svg, like this:
<path d='M10,10v50h50z' fill='#22ff22'/>

IMG_344AD2AF55DD-1

@luckyclan luckyclan changed the title I noticed a lot of aliased edges in VgerDemo... Missing antialiasing on some edges in VgerDemo... Feb 10, 2022
@luckyclan
Copy link
Author

Here is a basic triangle (M10,10v50h50z) showing both antialiasing issue, and precision problem
IMG_90FA58D57001-1
.

@wtholliday
Copy link
Contributor

wtholliday commented Feb 10, 2022

Yeah I've noticed that too... what do you think is happening there? Shader debugger might shed some light on it.

@wtholliday wtholliday self-assigned this Feb 10, 2022
@wtholliday
Copy link
Contributor

wtholliday commented Feb 10, 2022

I turned off the SDF AA and bezier inside-outside test, leaving only the linear test, and that exhibits numerical issues:

image

Here's the line test returning what is probably the wrong result for a pixel:

image

Actual x coordinate of p is 36.4999961853 which causes the test to give the wrong result. I'd guess the issue here is that the coordinates coming in are slightly inaccurate, not the line test itself.

So the pixel coordinates are exact, it's just the "texture" coordinates (which in the case of path fills are just the local coordinates in the path space) are approximate.

image

If I use the pixel coordinates, it's better:

image

@luckyclan
Copy link
Author

Rendering this triangle without aa will always display wrong pixels. Pixels on the edge are located exactly on the trinagle edge, so sometimes gpu rasterizer, due to rounding, will treat them as inside and sometimes outside the triangle.
However antialiasing should render perfect edges.

@luckyclan
Copy link
Author

Maybe you should increase rendered triangle by one or half pixel?

@wtholliday
Copy link
Contributor

wtholliday commented Feb 10, 2022

@luckyclan you're right, it's an AA issue. It seems that it's an issue with my SDF approximation (sdBezierApprox2). If I set exact=true then I get good results:

image

@luckyclan
Copy link
Author

Much better now. Does it affect the performance?

@wtholliday
Copy link
Contributor

Yep. Tiger goes from .66ms in the fragment shader to 1.2ms on my machine.

@luckyclan
Copy link
Author

Still very good! Did you try to tesselate bezier to lines? I wonder if this is faster or slower.

@wtholliday
Copy link
Contributor

wtholliday commented Feb 10, 2022

I didn't. I think the algorithm would be fairly different if I went that route.

So I got that SDF approximation from this paper: https://hhoppe.com/ravg.pdf

and the paper notes that they perturb the points (section 4.4):

image

Earlier I was lazy and just threw in a flatness check here:

if(abs(det) < 0.01) {

but I wasn't using it for some reason (was using sdBezierApprox2 instead).

Unfortunately, I didn't document why I stopped using the flatness check: 4370abb

@luckyclan
Copy link
Author

Did you try sdf bezier segment from this page / rendertoy: https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm

@wtholliday
Copy link
Contributor

wtholliday commented Feb 10, 2022

@luckyclan Yeah, that's what it uses when exact=true

inline float sdBezier(float2 pos, float2 A, float2 B, float2 C )

@wtholliday
Copy link
Contributor

Here's my old shader toy of that approximation: https://www.shadertoy.com/view/XsX3zf

It's pretty easy to have a degenerate case, or something close where the DF is too steep, so I'm not sure how they got it to work well in the paper.

@luckyclan
Copy link
Author

Yes, approx ver doesn’t look good.

I also wonder if you use naive or smart bounding box calculation for bezier: https://www.shadertoy.com/view/lsyfWc

I bet there is also optimization in sdf bezier so you would use sdf only for some selected pixels…

@wtholliday
Copy link
Contributor

@luckyclan Yeah, I had some trivial rejection code in there already. It seems like using it with the exact bezier calculation doesn't result in too big of a performance regression. I can live with that :)

@luckyclan
Copy link
Author

luckyclan commented Feb 11, 2022

Could you try to work directly on cubic curve (without splitting it to two quadratic), using method from this:
https://www.shadertoy.com/view/4sKyzW

It uses iterations so it will be probably slower, but maybe it is worth trying.

@luckyclan
Copy link
Author

Btw, check my methods of converting cubic to quadratic:
https://www.shadertoy.com/view/7dlfRN

@wtholliday
Copy link
Contributor

wtholliday commented Feb 11, 2022

Could you try to work directly on cubic curve (without splitting it to two quadratic), using method from this: https://www.shadertoy.com/view/4sKyzW

It uses iterations so it will be probably slower, but maybe it is worth trying.

We'd also need an inside/outside test along the lines of bezierTest for cubics:

inline bool bezierTest(float2 p, float2 A, float2 B, float2 C) {

I think Loop-Blinn does that but I haven't had the time to implement it.

Your cubic to quadratic conversion looks really good. Seems like it would be an easy thing to do in vgerCubicApproxTo if that interests you :)

wtholliday added a commit to audulus/vger-rs that referenced this issue Mar 3, 2022
@dumblob
Copy link

dumblob commented Jun 9, 2022

Yep. Tiger goes from .66ms in the fragment shader to 1.2ms on my machine.
...
@luckyclan Yeah, I had some trivial rejection code in there already. It seems like using it with the exact bezier calculation doesn't result in too big of a performance regression. I can live with that :)

Now that you made it the default I wonder how much is "not too big"? Is it around .66ms or rather 1.2ms?

@wtholliday
Copy link
Contributor

@dumblob it made the fragment shader 2x slower. .66ms to 1.2ms.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants