Drawing Circles with a Shader

I currently have a need to draw circles with a shader, and I found this absolutely amazing article. The creator has made a shader that lets you animate circles, draw arcs, adjust widths etc., which are exactly the features I need. It has really nice anti-aliasing too. Full credit goes to Ben Golus for writing it.

I am experimenting with the final version in the link (near the bottom, 233 lines long) and it looks great in the editor:

8156894--1060181--Screenshot 2022-05-25 at 20.57.07.png

You can see how smooth the circle is. However, when I deploy my code to iOS and view it on my iPhone, it has a lot more aliasing and jaggedness:


8156894--1060184--IMG_0878.PNG

Does anyone have any idea why this might be? Previously I was using the built in line-renderer and the circles were perfectly smooth on iOS. So I guess there is something in this shader that maybe doesn’t translate well to mobile? I only have a very basic grasp of shaders so any help would be really appreciated. I would love to make use of this awesome shader but unfortunately I can’t if it looks like this when deployed.

Please note: I have not changed any graphics settings so my project is still using the default 2x Multi Sampling AA settings (Unity 2020.3 with Built-in Render Pipeline). I’ve also tried deploying to an iPad Air and am seeing the same aliasing on that device too.

Most curious. That looks like fwidth() isn’t functioning properly for some reason.

Random curiosity, does this link look smooth to you?

It should look like this, even on iOS (it does for me):

Thanks Bgolus, yes I can confirm that the circle you posted (both link and image) looks very smooth on my iOS devices, pretty much perfectly so.

EDIT: Facepalm… I just realised that it was you that made this shader! Seriously you did an awesome job so thanks so much!

You can try replacing line 131 with:

half radialGradDeriv = fwidth(radialGrad);

But honestly I’m not sure why it wouldn’t work.

You sir… are a legend! It now looks perfectly smooth just like it does in the editor. I honestly cannot thank you enough.

I do have a second question too if you don’t mind. I would like to add an extra feature to this shader and your advice on how to do it would be really appreciated. Basically I want to add a “dashed line” feature that would be:

  • A checkbox similar to “Arc” called “Dashed Line” which makes the line dashed

  • A range slider from 0 to 1 which changes the number of dashes

  • 0 would mean a line with large dashes and large gaps

  • Moving to 1 increases the number of dashes

  • 1 signifies a solid line with no dashes

  • There is no strict requirement for the max and min dashed size

  • Should work with “Arc” enabled or disabled. But it does not need to work with “Outline” enabled as this would probably look weird (unless you outlined each dash I suppose) and isn’t really needed.

Do you have any advice how to achieve this? Should it be done in the Vert or Frag function? I guess we could apply some sort of square wave within Frag to the Lerp function on Line 213, where the low region on the wave creates a gap in the line. Increasing the slider could increase the frequency of the square wave? But I am not too sure how to implement this. Any advice would be really appreciated. I have attached an image below to show my idea:

8163344--1061768--Screenshot 2022-05-28 at 11.39.02.png

If you want dashes like that, you’ll need to use a version of the shader that uses the atan2() function to get the angle per pixel. That’ll produce a shader with a completely different structure to the one I present at the bottom. And honestly if you don’t need all if the features of that shader you should probably use something simpler anyway.

Ah okay. I actually am using pretty much all the features aside from the outline (may use it later, just have no use for it now). I just need to add a dashed feature on top.

But how come it requires changing the structure? When we are filling the bar why can’t we just alternate between high and low to create gaps in the line?

Because we don’t know where along the line we are. That’s what atan2() gets you.