Creating Rounded Rectangles in GLSL
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.
Why Rounded Rectangles?
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.
Starting with a Rectangle
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.
Centering the Coordinates
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.
Using 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.
Defining the Rectangle Size
Choose the half size of the rectangle.
vec2 size = vec2(0.25, 0.15);
This means the rectangle extends
0.25units left and right.0.15units up and down.
Changing these values changes the size of the rectangle.
Adding Rounded Corners
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.
Measuring the Corner Distance
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.
Turning the Distance into a Shape
Now use smoothstep().
float rect = 1.0 - smoothstep(0.0, 0.01, d);
Pixels inside the rounded rectangle become white.
Everything else becomes black.
Complete Shader
#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.
Changing the Corner Radius
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.
Adding Colour
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.
Animating the Corners
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.
Creating a Button
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.
Where Are Rounded Rectangles Used?
Rounded rectangles appear almost everywhere.
Some common examples include
- Mobile app buttons
- Search bars
- Cards
- Login panels
- Dialog boxes
- Notification windows
- Video player controls
- Progress bars
- User interface panels
- Dashboard widgets
Once you notice them, you'll see them in nearly every application you use.
Try These Experiments
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.
A Small Challenge
Can you create these effects?
- A glowing button.
- A search bar.
- A rounded notification card.
- A pulsing capsule.
- A row of animated buttons.
Each one can be created by changing only a few numbers.
What We Learned
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.
Posted Using INLEO