Drawing Rings and Outlines: Creating Hollow Shapes in GLSL
In the previous tutorial, every pixel decided whether it belonged inside or outside a circle.
That gave us a filled shape.
But many effects don't need a filled circle.
Think about a loading indicator, a radar display, a target reticle, a glowing portal, or the outline of a planet.
These are all rings rather than solid circles.
The good news is that creating a ring only requires one extra step.
Instead of drawing one circle, we'll compare two circles with different sizes.
How Does a Ring Work?
Imagine drawing two circles.
The first one has a radius of
0.30
The second has a radius of
0.25
If we remove the smaller circle from the larger one, only the space between them remains.
That remaining area is a ring.
Visually it looks like this.
Large Circle
██████████
██████████
██████████
Minus
Small Circle
████
████
Equals
████ ████
██ ██
████ ████
This is the basic idea behind almost every outlined shape in procedural graphics.
Drawing Two Circles
Let's start by calculating two distances.
vec2 center = vec2(0.5);
float d = distance(vUv, center);
float outer = 1.0 - step(0.30, d);
float inner = 1.0 - step(0.25, d);
Both values are simply circles with different radii.
Creating the Ring
Now subtract the smaller circle.
float ring = outer - inner;
Pixels that belong to both circles disappear.
Only the space between them remains.
Complete Shader
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 vUv;
void main(){
vec2 center = vec2(0.5);
float d = distance(vUv, center);
float outer = 1.0 - step(0.30, d);
float inner = 1.0 - step(0.25, d);
float ring = outer - inner;
gl_FragColor = vec4(vec3(ring), 1.0);
}
With only one extra line of code, we've transformed a filled circle into a hollow one.
Making the Ring Thicker
The thickness depends on the difference between the two radii.
A thick ring.
outer = step(0.35, d);
inner = step(0.15, d);
A thin ring.
outer = step(0.30, d);
inner = step(0.28, d);
The closer the numbers are, the thinner the outline becomes.
Soft Rings
Sharp edges are useful, but sometimes a softer look is better.
Replace step() with smoothstep().
float outer = 1.0 - smoothstep(0.29, 0.31, d);
float inner = 1.0 - smoothstep(0.24, 0.26, d);
float ring = outer - inner;
Now the edges fade smoothly.
This technique is commonly used for glowing interfaces, energy shields, and lighting effects.
Coloring the Ring
Instead of grayscale, assign a color.
vec3 color = vec3(0.2, 0.8, 1.0) * ring;
gl_FragColor = vec4(color, 1.0);
Only the ring receives the color.
Everything else stays black.
Animating the Radius
Let's combine this lesson with what we learned about time.
float radius = 0.25 + sin(uTime) * 0.05;
Now use the animated radius.
float outer = 1.0 - step(radius + 0.03, d);
float inner = 1.0 - step(radius, d);
The ring slowly grows and shrinks.
This simple animation can become a pulse, a radar scan, or a loading animation.
Creating Multiple Rings
Nothing limits us to one ring.
float rings = step(0.5, fract(d * 10.0));
Because fract() repeats the distance values, several rings appear around the center.
This is the beginning of ripple effects.
Where Are Rings Used?
Ring shapes appear in many shaders.
Some common examples include
- Loading indicators
- Radar displays
- Shockwaves
- Energy shields
- Audio visualizers
- Planet outlines
- User interface elements
- Target reticles
- Ripples on water
Most of these begin with exactly the same idea you learned today.
Try These Experiments
Create a very thin ring.
outer = 0.30
inner = 0.29
Create a thick ring.
outer = 0.40
inner = 0.20
Animate the radius.
radius = 0.25 + sin(uTime) * 0.05
Create several repeating rings.
step(0.5, fract(distance(vUv, vec2(0.5)) * 8.0))
Try changing the values and observe how the ring changes.
A Small Challenge
Can you create these effects?
- A thin outline around a circle.
- A thick glowing ring.
- A pulsing ring that grows and shrinks.
- Several rings spreading outward from the center.
- A colored radar style circle.
Leave Drawing Rings and Outlines: Creating Hollow Shapes in GLSL to:
Read more #editing posts
Best Posts From hey2d
We have not curated any of hey2d's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.
More Posts From hey2d
- Fragment Shaders Made Simple: What gl-FragColor Does
- Understanding gl-Position: My First Real Vertex Shader
- Creating Procedural Galaxies and Nebulas in GLSL
- Creating a Procedural Night Sky and Stars in GLSL
- Creating Procedural Clouds in GLSL
- Adding Reflections and Highlights to Procedural Water in GLSL
- Creating Procedural Water in GLSL
- Creating Procedural Smoke in GLSL
- Creating Procedural Fire in GLSL
- Creating Procedural Wood Grain in GLSL
- Creating a Procedural Marble Texture in GLSL
- Domain Warping in GLSL: Distorting Noise to Create Organic Worlds
- Fractal Brownian Motion in GLSL: Building Rich Procedural Noise
- Understanding Gradient Noise in GLSL
- Creating Smooth Value Noise in GLSL
- Creating Random Values in GLSL: The Building Blocks of Procedural Graphics
- Combining Translation, Rotation, and Scaling in GLSL
- Scaling Shapes in GLSL: Making Procedural Graphics Grow and Shrink
- Rotating Shapes in GLSL: Understanding Coordinate Rotation
- Moving Shapes in GLSL: Understanding Coordinate Translation