Missing antialiasing on some edges in VgerDemo...
luckyclan opened this issue · 20 comments
Yeah I've noticed that too... what do you think is happening there? Shader debugger might shed some light on it.
I turned off the SDF AA and bezier inside-outside test, leaving only the linear test, and that exhibits numerical issues:
Here's the line test returning what is probably the wrong result for a pixel:
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.
If I use the pixel coordinates, it's better:
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.
Maybe you should increase rendered triangle by one or half pixel?
@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:
Much better now. Does it affect the performance?
Yep. Tiger goes from .66ms in the fragment shader to 1.2ms on my machine.
Still very good! Did you try to tesselate bezier to lines? I wonder if this is faster or slower.
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):
Earlier I was lazy and just threw in a flatness check here:
Line 189 in 20dda3a
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
Did you try sdf bezier segment from this page / rendertoy: https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
@luckyclan Yeah, that's what it uses when exact=true
Line 77 in 20dda3a
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.
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…
@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 :)
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.
Btw, check my methods of converting cubic to quadratic:
https://www.shadertoy.com/view/7dlfRN
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:
Line 455 in 11a5577
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 :)
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?
@dumblob it made the fragment shader 2x slower. .66ms to 1.2ms.