If you're new to the series or would like to catch up on the fundamentals, you can find every previous lesson, along with a summary of what each tutorial covers, here:
GLSL Beginner Series: A Journey from Your First Shader to Procedural Animation
In the previous tutorial, we learned how to create procedural rectangles using only UV coordinates and the step() function. Together with circles, rectangles gave us two powerful building blocks for creating procedural graphics.
Today we're going to combine those ideas to build one of the most common shapes found in modern interfaces.
Open almost any application on your computer or phone.
Buttons have rounded corners.
Search bars have rounded corners.
Cards, menus, notifications, and dialog boxes all have rounded corners.
They feel softer and more modern than ordinary rectangles.
Instead of importing an image, we're going to build this shape entirely with mathematics.
A rectangle is useful, but its sharp corners can sometimes look harsh.
Rounded rectangles solve that problem while keeping the same overall shape.
Because they're generated procedurally, we can change their size, corner radius, colour, and animation at any time.
We'll begin with the rectangle we created in the previous lesson.
vec2 uv = vUv;
Instead of checking four edges directly, we'll use a slightly different approach.
We'll measure the distance from the rectangle itself.
Move the origin to the centre of the screen.
vec2 p = uv - 0.5;
Now the middle of the rectangle is (0.0, 0.0).
Positive values move right and up.
Negative values move left and down.
This makes the calculations much easier.
abs()The abs() function returns the positive version of a number.
abs(-0.4)
becomes
0.4
This allows us to treat every corner of the rectangle the same way.
vec2 q = abs(p);
Now every corner behaves identically.
Choose the half size of the rectangle.
vec2 size = vec2(0.25, 0.15);
This means the rectangle extends
0.25 units left and right.0.15 units up and down.Changing these values changes the size of the rectangle.
Now choose a corner radius.
float radius = 0.08;
This value controls how round the corners become.
A small radius creates subtle curves.
A large radius creates a pill shaped button.
Now combine everything.
float d = length(max(q - size + radius, 0.0)) - radius;
This line looks complicated.
Let's break it down.
q - size
Measures how far each pixel is outside the rectangle.
max(..., 0.0)
Ignores pixels already inside the rectangle.
length()
Measures the distance to the nearest corner.
Finally,
-radius
moves the edge inward to create rounded corners.
Although the formula is compact, each part performs one simple job.
Now use smoothstep().
float rect = 1.0 - smoothstep(0.0, 0.01, d);
Pixels inside the rounded rectangle become white.
Everything else becomes black.
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 vUv;
void main(){
vec2 p = vUv - 0.5;
vec2 q = abs(p);
vec2 size = vec2(0.25, 0.15);
float radius = 0.08;
float d = length(max(q - size + radius, 0.0)) - radius;
float rect = 1.0 - smoothstep(0.0, 0.01, d);
gl_FragColor = vec4(vec3(rect), 1.0);
}
With only a few lines of code, we've created a clean rounded rectangle without importing a texture.
Try different values.
radius = 0.02;
Almost square corners.
radius = 0.12;
Soft rounded corners.
radius = 0.18;
A capsule shape.
Changing one number completely changes the appearance.
Colour works exactly as before.
vec3 color = vec3(0.25, 0.75, 1.0) * rect;
gl_FragColor = vec4(color, 1.0);
You can create buttons, cards, and panels using any colour you like.
Let's animate the radius.
float radius = 0.06 + sin(uTime) * 0.03;
The corners smoothly become sharper and rounder over time.
This demonstrates that procedural geometry is completely dynamic.
Add a soft glow.
vec3 color = vec3(0.2, 0.8, 1.0) * rect;
color += vec3(0.15) * smoothstep(0.15, 0.0, d);
The rectangle now looks much closer to a modern interface button.
Rounded rectangles appear almost everywhere.
Some common examples include
Once you notice them, you'll see them in nearly every application you use.
Create a thin button.
Create a square with rounded corners.
Create a capsule.
Animate the corner radius.
Combine a rounded rectangle with a glowing circle.
Experiment with different sizes and colours.
Can you create these effects?
Each one can be created by changing only a few numbers.
Today we combined ideas from previous tutorials to create rounded rectangles entirely with mathematics.
By using abs(), length(), and smoothstep(), we generated a shape that appears throughout modern interface design.
Rounded rectangles are one of the most useful procedural shapes you'll ever build.