矩形
- geogebra www.geogebra.org/classic/gae…
- shadertoy www.shadertoy.com/view/MctGWX
长方形可以通过中心点、宽度和高度定义。点位置的分布主要有三种情况,分别是:
- P1 点在长方形内部:对于在长方形内部的点,其到最近边界的有符号距离是负值,其绝对值是点到最近边界的最小距离。
- P3, P2 点在长方形外部,水平或垂直对齐:如果点位于长方形的延长线上(即垂直或水平对齐),则其到长方形的最近距离将是其到最近边的直线距离。
- P4 点在长方形外部,不与任何边对齐:对于不与长方形边界平行或垂直的外部点,其到长方形的最近距离是点到长方形最近角的欧几里得距离。
设长方形中心为 为中心点宽度为 ,高度为 ,任意点 。由于坐标轴具有对称性,只需要考虑第一象限的四种情况,对于其他象限的距离都可以通过绝对值转换到第一象限。
- 计算点 水平和垂直方向上到长方形边界的距离 ,
- 根据dx$$dy正负情况可以判断如何计算距离
- P1 点在长方形内部, 即
**dx<0 and dy<0**
: - P3, P2 点在长方形外部,水平或垂直对齐即
**oneOf(dx,dy) < 0**
**, ** - P4 点在长方形外部,不与任何边对齐, 即
**dx>0 and dy>0**
:
- P1 点在长方形内部, 即
变成shader代码非常清晰
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);
}
}
但是要知道shader里面不喜欢if else
. 考虑如何让两个condition变成一条语句。考虑情况2,3。
在glsl
中向量是支持max
函数的,可以进一步简化max(dxy, vec2(0.))
,但是上述公式在情况1就不适用了,结果为0, 所以进一步考虑到情况1。
上面公式在情况2,3都为0, 所以最后只需要将两个公式相加,便得到最后的结果,shader代码如下
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));
}
最后得到以下的图形
圆角
- geogebra geogebra.org/classic/hsw…
- shadertoy www.shadertoy.com/view/MctGWX
实现圆角的原理非常简单,如上图所示,内圈的矩形是实际的矩形,将内圈矩形增加圆角的radius
。获取到distance
之后,在减去radius
便可以实现圆角效果。 具体代码如下
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;
}
得到下面的效果图