Search code examples
glslshader

How to render a smooth ellipse?


I'm trying to render an ellipse where I can decide how hard the edge is. (It should also be tileable, i.e. I must be able to split the rendering into multiple textures with a given offset)

I came up with this:

float inEllipseSmooth(vec2 pos, float width, float height, float smoothness, float tiling, vec2 offset)
{
    pos = pos / iResolution.xy;
    float smoothnessSqr = smoothness * tiling * smoothness * tiling;

    vec2 center = -offset + tiling / 2.0;
    pos -= center;

    float x = (pos.x * pos.x + smoothnessSqr) / (width * width);
    float y = (pos.y * pos.y  + smoothnessSqr) / (height * height);
    float result = (x + y);

    return (tiling * tiling) - result;
}

See here (was updated after comment -> now it's how I needed it): https://www.shadertoy.com/view/ssGBDK

But at the moment it is not possible to get a completely hard edge. It's also smooth if "smoothness" is set to 0.

One idea was "calculating the distance of the position to the center and comparing that to the corresponding radius", but I think there is probably a better solution.

I was not able to find anything online, maybe I'm just searching for the wrong keywords.

Any help would be appreciated.


Solution

  • I don't yet understand what you are trying to accomplish. Anyway, I have been playing with shadertoy and I have created something that could help you. I think that smoothstep GLSL function is what you need. And some inner and outer ratio to set the limits of the inner and border.

    It is not optimized...

    void mainImage( out vec4 fragColor, in vec2 fragCoord )
    {
    
        int tiling = 4;
        float width = 0.5;
        float height = 0.2;
        float smoothness = 0.9;
        float outerRatio = 1.0;
        float innerRatio = 0.75;
        vec2 offset = vec2(0.25, 0.75);
        //offset = iMouse.xy / iResolution.xy;
        
        vec2 center = vec2(0.5, 0.5);
        vec2 axis = vec2(width, height);
    
        vec2 pos = float(tiling) * (fragCoord.xy);
        pos = mod(pos / iResolution.xy, 1.0);            
        pos = mod(pos - offset, 1.0);
        pos = pos - center;
        pos = (pos * pos) / (axis * axis);
        float distance = pos.x + pos.y;
        float alpha;
        if ( distance > outerRatio ) { alpha = 0.0; }
        else if ( distance < innerRatio ) { alpha = 1.0; }
        else { alpha = smoothstep(outerRatio, innerRatio, distance); }
        
        fragColor = vec4(vec3(alpha), 1.0);
    }
    

    Shadertoy multiple ellipses with soft edge and solid inner