-
Notifications
You must be signed in to change notification settings - Fork 0
2D SDF(3): Reatangle and Rounded
- geogebra https://www.geogebra.org/classic/gae9k8gb
- shadertoy https://www.shadertoy.com/view/MctGWX
A rectangle can be defined by its center point, width and heigth. There are manly three cases for the distribution of a point's position with respect to the rectangle:
- P1 inside the reactangle: for points inside the reactangle, the signed distance to the nearest boundary is negative. where the absoulute value is the minimum distance to the nearest edge.
- P2, P3 Outside. Aligned Horizontally or vertically: if a Point lies on an extension of the rectangle's side(i.e, aligned vertically or horizontally), the nearest distance will be the straight-line distance to the nearest edge.
- P4 outside, Not Aligned with Any Edge: For points outside the rectangle that are neither parallel nor perpendicular to hte edges, the nearest distance is the Euclidean distance to the closest cornner of the rectangle.
Assume the rectangle's center
- Compute the distance from
$P$ along horizontal and vertical directions to the boundaries of the rectangle$dx = x - w/2$ ,$dy = y - h/2$ - Depending on the signs of
$dx$ and$dy$ , we can determine how to calculate the distance$d$ -
dx<0 and dy<0
:$d = max(dx, dy)$ -
P2, P3 Outside. Aligned Horizontally or vertically, i.e.,
oneOf(dx,dy) < 0
$d = max(dx, dy)$ -
P4 outside, Not Aligned with Any Edge: i.e.,
dx>0 and dy>0
$d = \sqrt{dx^2 + dy^2}$
-
this becomes very clear and straightforward in shader code
float sdf_rectangle1(vec2 pct, vec2 wh) {
vec2 dxy = abs(pct) - wh;
if (dxy.x > 0. && dxy.y >0.) {
return length(dxy);
} else {
return max(dxy.x, dxy.y);
}
}
However, it's important to note the shader prefer to avoidif else
statements. Consider how to combine two conditions into a single statement. particularly for cases 2 and 3
float sdf_rectangle2(vec2 pct, vec2 wh) {
vec2 dxy = abs(pct) - wh;
return length(max(dxy, 0.0)) + max(min(dxy.x, 0.0), min(dxy.y, 0.0));
}
Then we got this :)
- geogebra https://geogebra.org/classic/hswjqp87
- shadertoy https://www.shadertoy.com/view/MctGWX
Implementing rounded corners is quite straightforward. as illustrated above. The inner rectangle represetns the actual rectangle. and by increasing the inner rectangle's corners by the radius of the rounding, you can obtain the distance
. Then, by subtracting the raidus. you can achieve the rounded corner effect. the specific code is as follows
float sdf_rounded_rectangle(vec2 pct, vec2 wh, float radius) {
vec2 dxy = abs(pct) - wh + radius;
return length(max(dxy, 0.0)) + // one of (dx, dy) greater than 0
max(min(dxy.x, 0.0), min(dxy.y, 0.0))- // dx, dy lower than 0
radius;
}
Then we got this :)