How do I get this circle to maintain its thickness when viewed from different angles?

I have drawn a circle in a fragment shader. I have been able to keep the thickness when viewed at different distances with: `border *= -mvPos.z;`
But if viewed from an angle it gets thinner.
https://jsfiddle.net/zero0zero/ova45wf3/

Is this a good way to draw a circle? (with glsl) or is their a better way? I plan on having multiple circles inside each other that change with distance.

here is the fragment shader code:

``````varying vec3 vPosition;
varying vec4 mvPos;

void main() {
float circle_radius = 5.0;
float border = 0.0025;

vec2 uv = vPosition.xz;

float dist = sqrt(dot(uv, uv));

border *= -mvPos.z;

float t = 1.0 + smoothstep(circle_radius, circle_radius + border, dist)
- smoothstep(circle_radius - border, circle_radius, dist);

gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0 - t);
}``````

Thereâ€™s nothing that can be done in your situation, because youâ€™re trying to maintain the circle thickness on a plane. So when that plane inevitably gets infinitely thin when you rotate it by 90-degrees, then thereâ€™s nothing you can do to make the plane (and therefore, circle) thicker.

Think of it as using a big fat brush on a piece of paper, then looking at the paper from the edge. It doesnâ€™t matter how fat the brush is, the stroke is still going to be flat.

Youâ€™ll need to use actual torus 3D geometry to maintain the thickness when viewed from the edge.

1 Like

In dependence of your goal, you can use a torus, or a line, or a fat line.

@prisoner849
I might go with a line, but I would rather the perfect circle look of a shader generated circle.
There has been some progress, a suggestion from someone has led me to this: https://jsfiddle.net/zero0zero/joq046be/

@marquizzo
Thank you. If I do it this way, the plane will be very large and OrbitControls will have a maxPolarAngle to keep the view of the plane wide enough. If this route is unsuccessful then I will use a line, which is about the thickness i am looking for.

@zeroFire
Just out of curiousity, whatâ€™s the goal?

@prisoner849
The circles are to show a distance from a center point. when the camera is close the circle would have a smaller radius and when the camera is far the radius would be larger. the different radius would be somehitng like 1metre, 5 meter 10 meters etc. I can do this with a BufferGeometry in a circle and LineMaterial, but I want to try it with a shader, to get a better circle and maybe better performance.
What do you think?

Fwidth is what I would use for this to get pixel perfect lines, as well, but I pass it in as a threshold to `smoothstep`, which gives a pretty nice anti aliased edge but youâ€™ll start to notice artifacts at really skewed angles particularly with thicker lines. And of course itâ€™ll disappear if you look at the plane from the side anyway:

``````    // calculate the distance from center
float dist = length(uv);
float distToEdge = abs(dist - circle_radius);

float pixelWidth = fwidth(dist);
float t = smoothstep(pixelWidth * (border - 1.0), pixelWidth * (border + 0.25), distToEdge) ;
``````

Hereâ€™s a fiddle with the change:

https://jsfiddle.net/z914og7a/1/

You can adjust the `border - 1.0` and `border + 0.25` thresholds to taste depending on how much of a feathered / AAâ€™d edge you want. The artifacts at skewed angles are gonna bug me, thoughâ€¦

2 Likes

@gkjohnson
Nice. This works really well.
Thank you!